/*****************************************************************************/ /* pemagination: a (virtual) tour into portable bits and executable bytes */ /* Copyright (C) 2013--2020 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */ /*****************************************************************************/ #include #include #include #include #include "pe_impl.h" static __inline__ int pe_addr_within_bounds(void * addr, void * bottom, void * top) { 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 (; markordinal_base = 0; sym->ordinal = 0; sym->addr = 0; sym->forwarder_rva = 0; sym->name = 0; sym->status = 0; if (!(exp_hdr = pe_get_image_export_hdr_addr(base,&sec_size))) return -1; sec_addr_cap = pe_va_from_rva(exp_hdr,sec_size); rva_offset = (uint32_t *)(exp_hdr->eh_export_addr_tbl_rva); fn_addr = (uint32_t *)pe_va_from_rva(base,*rva_offset); rva_offset = (uint32_t *)(exp_hdr->eh_name_ptr_rva); fn_names = (uint32_t *)pe_va_from_rva(base,*rva_offset); rva_offset = (uint32_t *)(exp_hdr->eh_ordinal_tbl_rva); fn_ordinals = (uint16_t *)pe_va_from_rva(base,*rva_offset); addr_entries = (uint32_t *)exp_hdr->eh_addr_tbl_entries; name_entries = (uint32_t *)exp_hdr->eh_num_of_name_ptrs; /* by ordinal? */ if ((intptr_t)name < 0x10000) { sym->ordinal_base = (uint32_t *)exp_hdr->eh_ordinal_base; /* the array is zero-based, but ordinals are normally one-based... */ if (((intptr_t)name - *sym->ordinal_base + 1) > *addr_entries) return -1; addr = ((uintptr_t)name - *sym->ordinal_base) * sizeof(uint32_t); rva_offset = (uint32_t *)pe_va_from_rva(fn_addr,addr); 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; } return 0; } if ((len = pe_impl_strlen_ansi(name)) < 0) return -1; len++; lower = 0; upper = *name_entries; while (lower < upper) { idx = (lower + upper) / 2; rva_offset = (uint32_t *)pe_va_from_rva(fn_names,idx*sizeof(uint32_t)); exp_name = (char *)pe_va_from_rva(base,*rva_offset); src = name; dst = exp_name; for (match=0; (matchordinal_base = (uint32_t *)exp_hdr->eh_ordinal_base; sym->ordinal = (uint16_t *)pe_va_from_rva(fn_ordinals,idx*sizeof(uint16_t)); rva_offset = (uint32_t *)pe_va_from_rva(fn_addr,(*sym->ordinal)*sizeof(uint32_t)); 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; } return 0; } else { if (*src > *dst) lower = idx + 1; else upper = idx; } } return -1; }