diff options
Diffstat (limited to 'src/exports')
-rw-r--r-- | src/exports/pe_enum_image_exports.c | 61 | ||||
-rw-r--r-- | src/exports/pe_get_export_symbol_info.c | 142 | ||||
-rw-r--r-- | src/exports/pe_get_procedure_address.c | 18 |
3 files changed, 221 insertions, 0 deletions
diff --git a/src/exports/pe_enum_image_exports.c b/src/exports/pe_enum_image_exports.c new file mode 100644 index 0000000..85e92cf --- /dev/null +++ b/src/exports/pe_enum_image_exports.c @@ -0,0 +1,61 @@ +/*****************************************************************************/ +/* pemagination: a (virtual) tour into portable bits and executable bytes */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */ +/*****************************************************************************/ + +#include <psxtypes/psxtypes.h> +#include <pemagine/pe_consts.h> +#include <pemagine/pe_structs.h> +#include <pemagine/pemagine.h> + +pe_api +int pe_enum_image_exports( + const void * base, + pe_enum_image_exports_callback * callback, + struct pe_export_sym * sym, + void * ctx) +{ + struct pe_export_hdr * exp_hdr; + uint32_t * count; + uint32_t * fn_addr; + uint32_t * fn_names; + uint16_t * fn_ordinals; + uint32_t * offset; + uint32_t idx; + int ret; + + if (!(exp_hdr = pe_get_image_export_hdr_addr(base,0))) { + callback(base,0,0,PE_CALLBACK_REASON_ERROR,ctx); + return -1; + } + + offset = (uint32_t *)(exp_hdr->export_addr_tbl_rva); + fn_addr = (uint32_t *)pe_va_from_rva(base,*offset); + + offset = (uint32_t *)(exp_hdr->name_ptr_rva); + fn_names = (uint32_t *)pe_va_from_rva(base,*offset); + + offset = (uint32_t *)(exp_hdr->ordinal_tbl_rva); + fn_ordinals = (uint16_t *)pe_va_from_rva(base,*offset); + + if ((ret = callback(base,exp_hdr,0,PE_CALLBACK_REASON_INIT,ctx)) <= 0) + return ret; + + count = (uint32_t *)exp_hdr->num_of_name_ptrs; + sym->ordinal_base = (uint32_t *)exp_hdr->ordinal_base; + + for (idx=0; idx<*count; idx++) { + offset = (uint32_t *)pe_va_from_rva(fn_names,idx*sizeof(uint32_t)); + sym->name = (char *)pe_va_from_rva(base,*offset); + sym->ordinal = (uint16_t *)pe_va_from_rva(fn_ordinals,idx*sizeof(uint16_t)); + + offset = (uint32_t *)pe_va_from_rva(fn_addr,(*sym->ordinal)*sizeof(uint32_t)); + sym->addr = pe_va_from_rva(base,*offset); + + if ((ret = callback(base,exp_hdr,sym,PE_CALLBACK_REASON_ITEM,ctx)) <= 0) + return ret; + } + + return callback(base,exp_hdr,sym,PE_CALLBACK_REASON_DONE,ctx); +} diff --git a/src/exports/pe_get_export_symbol_info.c b/src/exports/pe_get_export_symbol_info.c new file mode 100644 index 0000000..9f00634 --- /dev/null +++ b/src/exports/pe_get_export_symbol_info.c @@ -0,0 +1,142 @@ +/*****************************************************************************/ +/* pemagination: a (virtual) tour into portable bits and executable bytes */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */ +/*****************************************************************************/ + +#include <psxtypes/psxtypes.h> +#include <pemagine/pe_consts.h> +#include <pemagine/pe_structs.h> +#include <pemagine/pemagine.h> +#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)); +} + +pe_api +int pe_get_export_symbol_info( + const void * base, + const char * name, + struct pe_export_sym * sym) +{ + struct pe_export_hdr * exp_hdr; + + size_t len; + uint32_t * rva_offset; + uintptr_t * addr_offset; + + uint32_t sec_size; + void * sec_addr_cap; + + uint32_t * fn_addr; + uint32_t * fn_names; + uint16_t * fn_ordinals; + uint32_t * addr_entries; + uint32_t * name_entries; + + char * exp_name; + const char * src; + const char * dst; + size_t match; + + uint32_t lower; + uint32_t upper; + uint32_t idx; + + /* initialize pe_exp_item */ + sym->ordinal_base = (uint32_t *)0; + sym->ordinal = (uint16_t *)0; + sym->addr = (void *)0; + sym->forwarder_rva = (void *)0; + sym->name = (char *)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->export_addr_tbl_rva); + fn_addr = (uint32_t *)pe_va_from_rva(base,*rva_offset); + + rva_offset = (uint32_t *)(exp_hdr->name_ptr_rva); + fn_names = (uint32_t *)pe_va_from_rva(base,*rva_offset); + + rva_offset = (uint32_t *)(exp_hdr->ordinal_tbl_rva); + fn_ordinals = (uint16_t *)pe_va_from_rva(base,*rva_offset); + + addr_entries = (uint32_t *)exp_hdr->addr_tbl_entries; + name_entries = (uint32_t *)exp_hdr->num_of_name_ptrs; + + /* by ordinal? */ + if ((intptr_t)name < 0x10000) { + sym->ordinal_base = (uint32_t *)exp_hdr->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; + + rva_offset = (uint32_t *)pe_va_from_rva(fn_addr,((uintptr_t)name-*sym->ordinal_base)*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 = 0; + sym->addr = addr_offset; + } else + /* todo: resolve forwarder address */ + 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; (match<len) && (*src==*dst); match++) { + src++; + dst++; + } + + if (match == len) { + sym->ordinal_base = (uint32_t *)exp_hdr->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)) { + /* todo: resolve forwarder address */ + sym->forwarder_rva = 0; + sym->addr = 0; + } else { + sym->forwarder_rva = 0; + sym->addr = addr_offset; + } + + return 0; + } + + else { + if (*src > *dst) + lower = idx + 1; + else + upper = idx; + } + } + + /* export name not found */ + return -1; +} diff --git a/src/exports/pe_get_procedure_address.c b/src/exports/pe_get_procedure_address.c new file mode 100644 index 0000000..958f205 --- /dev/null +++ b/src/exports/pe_get_procedure_address.c @@ -0,0 +1,18 @@ +/*****************************************************************************/ +/* pemagination: a (virtual) tour into portable bits and executable bytes */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */ +/*****************************************************************************/ + +#include <pemagine/pemagine.h> + +pe_api +void * pe_get_procedure_address(const void * base, const char * name) +{ + struct pe_export_sym sym; + + return pe_get_export_symbol_info(base,name,&sym) + ? 0 + : sym.addr; + +} |