//------------------------------------------------------------------------ // process all imports of a pe file // returns: -1:could not read an impdir; 0-ok; // other values can be returned by the visitor inline int pe_loader_t::process_imports(linput_t *li, pe_import_visitor_t &piv) { if ( pe.impdir.rva == 0 ) return 0; if ( transvec.empty() ) process_sections(li); int code = 0; bool is_memory_linput = get_linput_type(li) == LINPUT_PROCMEM; for ( int ni=0; ; ni++ ) { off_t off = pe.impdir.rva + ni*sizeof(peimpdir_t); peimpdir_t &id = piv.id; if ( !vmread(li, off, &id, sizeof(id)) ) { int code = piv.impdesc_error(off); if ( code != 0 ) break; // we continue if the import descriptor is within the page belonging // to the program if ( !is_memory_linput ) { uint32 fsize = pe.align_up_in_file(qlsize(li)); if ( map_ea(off)+sizeof(id) > fsize ) return -1; } } if ( id.dllname == 0 && id.table1 == 0 ) break; ea_t ltable = id.table1; //OriginalFirstThunk ea_t atable = id.looktab; //FirstThunk bool ok = true; char dll[MAXSTR]; asciiz(li, id.dllname, dll, sizeof(dll), &ok); if ( !ok || dll[0] == '\0' ) break; ansi2idb(dll); if ( !is_memory_linput && (map_ea(ltable) == BADADDR || ltable < pe.hdrsize) ) ltable = atable; atable += get_imagebase(); int code = piv.visit_module(dll, atable, ltable); if ( code != 0 ) break; code = process_import_table(li, pe, atable, ltable, piv); if ( code != 0 ) break; } return code; }
//-------------------------------------------------------------------------- static void read_dyninfo(ulong offset, ulong size) { qlseek(li, offset); const int entsize = elf64 ? sizeof(Elf64_Dyn) : sizeof(Elf32_Dyn); for(int i = 1; i < size; i += entsize ) { Elf64_Dyn dyn; if ( elf64 ) { if(lread8bytes(li, &dyn.d_tag, mf) || lread8bytes(li, &dyn.d_un, mf)) errstruct(); } else { ulong tag, val; if(lread4bytes(li, &tag, mf) || lread4bytes(li, &val, mf)) errstruct(); dyn.d_tag = tag; dyn.d_un = val; } switch ( WC4(dyn.d_tag) ) { case DT_STRTAB: dynstr_off = map_ea(dyn.d_un); break; case DT_SYMTAB: dynsym_off = map_ea(dyn.d_un); break; case DT_REL: dynrel_off = map_ea(dyn.d_un); break; case DT_RELA: dynrela_off = map_ea(dyn.d_un); break; case DT_STRSZ: dynstr_size = ulong(dyn.d_un); break; case DT_RELSZ: dynrel_size = ulong(dyn.d_un); break; case DT_RELASZ: dynrela_size = ulong(dyn.d_un); break; } } ulong off = dynstr_off; if ( dynrel_off ) off = qmin(dynrel_off, off); if ( dynrela_off ) off = qmin(dynrela_off, off); dynsym_size = off - dynsym_off; }
//------------------------------------------------------------------------ inline bool pe_loader_t::vseek(linput_t *li, uint32 rva) { ea_t fpos = get_linput_type(li) == LINPUT_PROCMEM ? rva : map_ea(rva); if ( fpos != BADADDR ) { qlseek(li, int32(fpos)); return true; } qlseek(li, rva, SEEK_SET); return false; }
//-------------------------------------------------------------------------- static int parse_dyninfo(const dyninfo_t &dyninfo) { for ( int i=0; i < dyninfo.size(); i++ ) { const Elf64_Dyn &dyn = dyninfo[i]; switch ( dyn.d_tag ) { case DT_STRTAB: dynstr_off = map_ea(dyn.d_un); break; case DT_SYMTAB: dynsym_off = map_ea(dyn.d_un); break; case DT_REL: dynrel_off = map_ea(dyn.d_un); break; case DT_RELA: dynrela_off = map_ea(dyn.d_un); break; case DT_STRSZ: dynstr_size = uint32(dyn.d_un); break; case DT_RELSZ: dynrel_size = uint32(dyn.d_un); break; case DT_RELASZ: dynrela_size = uint32(dyn.d_un); break; } } size_t off = dynstr_off; if ( dynrel_off ) off = qmin(dynrel_off, off); if ( dynrela_off ) off = qmin(dynrela_off, off); dynsym_size = off - dynsym_off; return 0; }
//------------------------------------------------------------------------ // this function tries to read from a file as if it was reading from memory // if translation not found for the given RVA then ZEROs are returned // in addition, if it tries to read beyond a translation physical size // the additional bytes will be returned as zeros inline bool pe_loader_t::vmread(linput_t *li, uint32 rva, void *buf, size_t sz) { // clear whole user buffer memset(buf, 0, sz); size_t may_read = sz; if ( get_linput_type(li) == LINPUT_PROCMEM ) { qlseek(li, rva, SEEK_SET); } else { transl_t *t; ea_t fpos = map_ea(rva, &t); // cannot find translation? if ( fpos == BADADDR ) { qlseek(li, int32(rva), SEEK_SET); return true; } qlseek(li, int32(fpos)); // reading beyond section's limit? uint32 after_read_pos = uint32(fpos+sz); if ( after_read_pos >= (t->pos+t->psize) ) { // check if position belongs to the header and if reading beyond the limit if ( uint32(fpos) < pe.allhdrsize && after_read_pos > pe.allhdrsize ) may_read = pe.allhdrsize - size_t(fpos); else may_read = t->pos+t->psize - fpos; // just read as much as section limit allows } } return qlread(li, buf, may_read) == (ssize_t)may_read; }