diff options
Diffstat (limited to 'src/logic')
-rw-r--r-- | src/logic/pe_image_meta_data.c | 151 |
1 files changed, 124 insertions, 27 deletions
diff --git a/src/logic/pe_image_meta_data.c b/src/logic/pe_image_meta_data.c index b2255d7..9914350 100644 --- a/src/logic/pe_image_meta_data.c +++ b/src/logic/pe_image_meta_data.c @@ -15,6 +15,7 @@ #include <perk/perk.h> #include <perk/perk_consts.h> #include <perk/perk_structs.h> +#include "perk_endian_impl.h" #include "perk_reader_impl.h" #include "perk_errinfo_impl.h" @@ -28,6 +29,7 @@ static int pe_free_image_meta_impl(struct pe_image_meta * meta, int ret) free(meta->m_symvec_crc32); free(meta->m_symvec_crc64); + free(meta->m_symvec_symidx); free(meta->m_idata); free(meta->m_symtbl); @@ -61,7 +63,9 @@ static int pe_symrec_crc64_compare(const void * a, const void * b) return eqor * (syma->cs_crc64 > symb->cs_crc64 ? (1) : (-1)); } -static int pe_get_named_section_index(const struct pe_image_meta * m, const char * name) +static int pe_get_named_section_index( + const struct pe_image_meta * m, + const char * name) { int i; for (i=0; i<m->m_coff.cfh_num_of_sections; i++) if (!(strcmp(name,m->m_sectbl[i].sh_name))) @@ -70,12 +74,16 @@ static int pe_get_named_section_index(const struct pe_image_meta * m, const char return -1; } -int pe_meta_get_named_section_index(const struct pe_image_meta * m, const char * name) +int pe_meta_get_named_section_index( + const struct pe_image_meta * m, + const char * name) { return pe_get_named_section_index(m,name); } -static int pe_get_block_section_index(const struct pe_image_meta * m, const struct pe_block * block) +static int pe_get_block_section_index( + const struct pe_image_meta * m, + const struct pe_block * block) { int i; uint32_t low,high; @@ -87,21 +95,28 @@ static int pe_get_block_section_index(const struct pe_image_meta * m, const stru low = m->m_sectbl[i].sh_virtual_addr; high = low + m->m_sectbl[i].sh_virtual_size; - if ((block->dh_rva >= low) && (block->dh_rva + block->dh_size <= high)) - return i; + if (block->dh_rva >= low) + if (block->dh_rva + block->dh_size <= high) + return i; } return -1; } -int pe_meta_get_block_section_index(const struct pe_image_meta * m, const struct pe_block * block) +int pe_meta_get_block_section_index( + const struct pe_image_meta * m, + const struct pe_block * block) { return pe_get_block_section_index(m,block); } -int pe_meta_get_roffset_from_rva(const struct pe_image_meta * m, uint32_t rva, uint32_t * roffset) +int pe_meta_get_roffset_from_rva( + const struct pe_image_meta * m, + uint32_t rva, + uint32_t * roffset) { - int i; + int i; + uint32_t offset; uint32_t low,high; for (i=0; i<m->m_coff.cfh_num_of_sections; i++) { @@ -109,7 +124,11 @@ int pe_meta_get_roffset_from_rva(const struct pe_image_meta * m, uint32_t rva, u high = low + m->m_sectbl[i].sh_virtual_size; if ((rva >= low) && (rva < high)) { - *roffset = (rva - low) + m->m_sectbl[i].sh_ptr_to_raw_data; + offset = m->m_sectbl[i].sh_ptr_to_raw_data; + offset += rva - low; + + *roffset = offset; + return 0; } } @@ -117,9 +136,12 @@ int pe_meta_get_roffset_from_rva(const struct pe_image_meta * m, uint32_t rva, u return -1; } -int pe_meta_get_rva_from_roffset(const struct pe_image_meta * m, uint32_t roffset, uint32_t * rva) +int pe_meta_get_rva_from_roffset( + const struct pe_image_meta * m, + uint32_t roffset, + uint32_t * rva) { - int i; + int i; uint32_t low,high,ref; for (i=0, ref=~0; i<m->m_coff.cfh_num_of_sections; i++) { @@ -127,8 +149,13 @@ int pe_meta_get_rva_from_roffset(const struct pe_image_meta * m, uint32_t roffse high = low + m->m_sectbl[i].sh_virtual_size; if ((roffset >= low) && (roffset < high)) { - *rva = (roffset - low) + m->m_sectbl[i].sh_virtual_addr; + roffset -= low; + roffset += m->m_sectbl[i].sh_virtual_addr; + + *rva = roffset; + return 0; + } else if (ref > low) { ref = low; } @@ -147,19 +174,24 @@ static int pe_get_expsym_by_name( const char * name, struct pe_expsym * expsym) { - uint32_t offset; - uint32_t * symrva; - const char * sym; - unsigned i; + uint32_t offset; + const unsigned char * ptrtbl; + const char * sym; + unsigned i; if (m->r_obj || !m->h_edata) return -1; - offset = m->h_edata->sh_virtual_addr - m->h_edata->sh_ptr_to_raw_data; - symrva = (uint32_t *)((uintptr_t)m->r_image.map_addr + (m->m_edata.eh_name_ptr_rva - offset)); + offset = m->h_edata->sh_virtual_addr; + offset -= m->h_edata->sh_ptr_to_raw_data; + + ptrtbl = m->r_image.map_addr; + ptrtbl += m->m_edata.eh_name_ptr_rva; + ptrtbl -= offset; for (i=0; i<m->m_edata.eh_num_of_name_ptrs; i++) { - sym = (const char *)m->r_image.map_addr + symrva[i] - offset; + sym = m->r_image.map_addr; + sym += pe_read_long(ptrtbl) - offset; if (!(strcmp(sym,name))) { if (expsym) { @@ -171,6 +203,8 @@ static int pe_get_expsym_by_name( return 0; } + + ptrtbl += sizeof(uint32_t); } return -1; @@ -189,9 +223,9 @@ static int pe_get_expsym_by_index( unsigned index, struct pe_expsym * expsym) { - uint32_t offset; - uint32_t * symrva; - uintptr_t symaddr; + uint32_t offset; + const unsigned char * symptr; + const char * sym; if (m->r_obj) return -1; @@ -200,11 +234,17 @@ static int pe_get_expsym_by_index( return -1; if (expsym) { - offset = m->h_edata->sh_virtual_addr - m->h_edata->sh_ptr_to_raw_data; - symrva = (uint32_t *)((uintptr_t)m->r_image.map_addr + (m->m_edata.eh_name_ptr_rva - offset)); - symaddr = (uintptr_t)m->r_image.map_addr + symrva[index] - offset; + offset = m->h_edata->sh_virtual_addr; + offset -= m->h_edata->sh_ptr_to_raw_data; - expsym->s_name = (const char *)symaddr; + symptr = m->r_image.map_addr; + symptr += m->m_edata.eh_name_ptr_rva - offset; + symptr += index * sizeof(uint32_t); + + sym = m->r_image.map_addr; + sym += pe_read_long(symptr) - offset; + + expsym->s_name = sym; expsym->s_eaddr = 0; expsym->s_maddr = 0; expsym->s_roffset = 0; @@ -364,6 +404,7 @@ int pe_meta_get_image_meta( void * addr; char * base; const unsigned char * mark; + const unsigned char * cap; uint64_t vaddr; struct pe_image_meta * m; @@ -404,11 +445,17 @@ int pe_meta_get_image_meta( } - if ((nrecs = m->m_coff.cfh_size_of_sym_tbl/sizeof(struct pe_raw_coff_symbol))) + if ((nrecs = m->m_coff.cfh_size_of_sym_tbl/sizeof(struct pe_raw_coff_symbol))) { if (!(m->m_symtbl = calloc(nrecs+1,sizeof(struct pe_meta_coff_symbol)))) return PERK_SYSTEM_ERROR(dctx); + if (!(m->m_symvec_symidx = calloc(nrecs,sizeof(struct pe_meta_coff_symbol *)))) + return PERK_SYSTEM_ERROR(dctx); + } + for (i=0,symrec=m->m_symtbl; i<nrecs; i++,symrec++) { + m->m_symvec_symidx[i] = symrec; + pe_read_coff_symbol( &m->r_symtbl[i],symrec, &m->m_coff,base); @@ -476,6 +523,56 @@ int pe_meta_get_image_meta( m->m_sectbl[i].sh_name = base + m->m_coff.cfh_ptr_to_str_tbl + l; } + /* .relocs */ + struct pe_raw_base_reloc_block * r; + struct pe_block b; + + i = pe_get_named_section_index(m,".reloc"); + s = pe_get_block_section_index(m,&m->m_opt.oh_dirs.coh_base_reloc_tbl); + + if ((i >= 0) && (i != s)) + return pe_free_image_meta_impl( + m,PERK_CUSTOM_ERROR(dctx,PERK_ERR_IMAGE_MALFORMED)); + + + if (s >= 0) { + mark = image->map_addr; + mark += m->m_sectbl[s].sh_ptr_to_raw_data; + mark += m->m_opt.oh_dirs.coh_base_reloc_tbl.dh_rva; + mark -= m->m_sectbl[s].sh_virtual_addr; + cap = &mark[m->m_sectbl[s].sh_virtual_size]; + + } else if (i >= 0) { + mark = image->map_addr; + mark += m->m_sectbl[i].sh_ptr_to_raw_data; + cap = &mark[m->m_sectbl[s].sh_virtual_size]; + + } else { + mark = 0; + cap = 0; + } + + + + for (; mark < cap; ) { + r = (struct pe_raw_base_reloc_block *)mark; + + b.dh_rva = pe_read_long(r->blk_rva); + b.dh_size = pe_read_long(r->blk_size); + + if (b.dh_size <= offsetof(struct pe_raw_base_reloc_block,blk_data)) + return pe_free_image_meta_impl( + m,PERK_CUSTOM_ERROR( + dctx, + PERK_ERR_IMAGE_MALFORMED)); + + mark += b.dh_size; + b.dh_size -= offsetof(struct pe_raw_base_reloc_block,blk_data); + + m->m_stats.t_nrelocs += b.dh_size / sizeof(uint16_t); + m->m_stats.t_nrelblks++; + } + /* .edata */ i = pe_get_named_section_index(m,".edata"); s = pe_get_block_section_index(m,&m->m_opt.oh_dirs.coh_export_tbl); |