diff options
-rw-r--r-- | src/exports/pe_get_export_symbol_info.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/src/exports/pe_get_export_symbol_info.c b/src/exports/pe_get_export_symbol_info.c index c933cee..d0cef88 100644 --- a/src/exports/pe_get_export_symbol_info.c +++ b/src/exports/pe_get_export_symbol_info.c @@ -15,6 +15,47 @@ static __inline__ int pe_addr_within_bounds(void * addr, void * bottom, void * t return (((uintptr_t)addr >= (uintptr_t)bottom) && ((uintptr_t)addr < (uintptr_t)top)); } +static void * pe_resolve_forwarder_rva(char * forwarder) +{ + uint16_t soname[512]; + uint16_t * wch; + char * mark; + char * dot; + void * base; + + for (mark=forwarder; *mark; mark++) + (void)0; + + if (mark - forwarder + 5 > 512) + return 0; + + for (dot=&mark[-1]; dot>forwarder && *dot!='.'; dot--) + (void)0; + + if (*dot != '.') + return 0; + + mark = forwarder; + wch = soname; + + for (; mark<dot && (unsigned)*mark<0x80; ) + *wch++ = *mark++; + + if (mark < dot) + return 0; + + *wch++ = '.'; + *wch++ = 'd'; + *wch++ = 'l'; + *wch++ = 'l'; + *wch++ = 0; + + if (!(base = pe_get_module_handle(soname))) + return 0; + + return pe_get_procedure_address(base,++dot); +} + int pe_get_export_symbol_info( const void * base, const char * name, @@ -83,11 +124,12 @@ int pe_get_export_symbol_info( addr_offset = (uintptr_t *)pe_va_from_rva(base,*rva_offset); if (pe_addr_within_bounds(addr_offset,exp_hdr,sec_addr_cap)) { + sym->forwarder_rva = addr_offset; + sym->addr = pe_resolve_forwarder_rva((char *)addr_offset); + } else { sym->forwarder_rva = 0; sym->addr = addr_offset; - } else - /* todo: resolve forwarder address */ - sym->addr = addr_offset; + } return 0; } @@ -120,9 +162,8 @@ int pe_get_export_symbol_info( addr_offset = (uintptr_t *)pe_va_from_rva(base,*rva_offset); if (pe_addr_within_bounds(addr_offset,exp_hdr,sec_addr_cap)) { - /* todo: resolve forwarder address */ - sym->forwarder_rva = 0; - sym->addr = 0; + sym->forwarder_rva = addr_offset; + sym->addr = pe_resolve_forwarder_rva((char *)addr_offset); } else { sym->forwarder_rva = 0; sym->addr = addr_offset; |