From feffc7263bb2fd33ae467de2dd51f1ddbbb1b895 Mon Sep 17 00:00:00 2001 From: midipix Date: Fri, 8 May 2015 23:22:07 -0400 Subject: initial commit. --- src/exports/pe_enum_image_exports.c | 61 ++++++++ src/exports/pe_get_export_symbol_info.c | 142 +++++++++++++++++++ src/exports/pe_get_procedure_address.c | 18 +++ src/headers/pe_get_image_coff_hdr_addr.c | 30 ++++ src/headers/pe_get_image_data_dirs_addr.c | 33 +++++ src/headers/pe_get_image_dos_hdr_addr.c | 24 ++++ src/headers/pe_get_image_entry_point_addr.c | 39 ++++++ src/headers/pe_get_image_opt_hdr_addr.c | 20 +++ src/headers/pe_get_image_special_hdr_addr.c | 49 +++++++ src/imports/pe_enum_image_import_hdrs.c | 35 +++++ src/internal/pe_impl.c | 51 +++++++ src/internal/pe_impl.h | 17 +++ src/internal/pe_lib_entry_point.c | 6 + src/meta/pe_get_image_stack_heap_info.c | 43 ++++++ src/meta/pe_get_symbol_module_info.c | 56 ++++++++ src/meta/pe_get_symbol_name.c | 209 ++++++++++++++++++++++++++++ src/modules/pe_enum_modules.c | 102 ++++++++++++++ src/modules/pe_get_kernel32_module_handle.c | 73 ++++++++++ src/modules/pe_get_module_handle.c | 80 +++++++++++ src/modules/pe_get_ntdll_module_handle.c | 27 ++++ 20 files changed, 1115 insertions(+) create mode 100644 src/exports/pe_enum_image_exports.c create mode 100644 src/exports/pe_get_export_symbol_info.c create mode 100644 src/exports/pe_get_procedure_address.c create mode 100644 src/headers/pe_get_image_coff_hdr_addr.c create mode 100644 src/headers/pe_get_image_data_dirs_addr.c create mode 100644 src/headers/pe_get_image_dos_hdr_addr.c create mode 100644 src/headers/pe_get_image_entry_point_addr.c create mode 100644 src/headers/pe_get_image_opt_hdr_addr.c create mode 100644 src/headers/pe_get_image_special_hdr_addr.c create mode 100644 src/imports/pe_enum_image_import_hdrs.c create mode 100644 src/internal/pe_impl.c create mode 100644 src/internal/pe_impl.h create mode 100644 src/internal/pe_lib_entry_point.c create mode 100644 src/meta/pe_get_image_stack_heap_info.c create mode 100644 src/meta/pe_get_symbol_module_info.c create mode 100644 src/meta/pe_get_symbol_name.c create mode 100644 src/modules/pe_enum_modules.c create mode 100644 src/modules/pe_get_kernel32_module_handle.c create mode 100644 src/modules/pe_get_module_handle.c create mode 100644 src/modules/pe_get_ntdll_module_handle.c (limited to 'src') 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 +#include +#include +#include + +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 +#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)); +} + +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; (matchordinal_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 + +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; + +} diff --git a/src/headers/pe_get_image_coff_hdr_addr.c b/src/headers/pe_get_image_coff_hdr_addr.c new file mode 100644 index 0000000..d2ff03a --- /dev/null +++ b/src/headers/pe_get_image_coff_hdr_addr.c @@ -0,0 +1,30 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include + +pe_api +struct pe_coff_file_hdr * pe_get_image_coff_hdr_addr(const void * base) +{ + struct pe_image_dos_hdr * dos; + struct pe_coff_file_hdr * coff; + uint32_t * offset; + + if (!(dos = pe_get_image_dos_hdr_addr(base))) + return 0; + + offset = (uint32_t *)(dos->dos_lfanew); + coff = (struct pe_coff_file_hdr *)pe_va_from_rva(base,*offset); + + if ((coff->signature[0] == 'P') && (coff->signature[1] == 'E') + && (coff->signature[2] == '\0') && (coff->signature[3] == '\0')) + return coff; + else + return 0; +} diff --git a/src/headers/pe_get_image_data_dirs_addr.c b/src/headers/pe_get_image_data_dirs_addr.c new file mode 100644 index 0000000..d0167c0 --- /dev/null +++ b/src/headers/pe_get_image_data_dirs_addr.c @@ -0,0 +1,33 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include + +pe_api +struct pe_data_dirs * pe_get_image_data_dirs_addr(const void * base) +{ + uint16_t * magic; + union pe_opt_hdr * hdr; + + if (!(hdr = pe_get_image_opt_hdr_addr(base))) + return 0; + + magic = (uint16_t *)hdr; + + switch (*magic) { + case PE_MAGIC_PE32: + return (struct pe_data_dirs *)hdr->opt_hdr_32.rva_and_sizes; + + case PE_MAGIC_PE32_PLUS: + return (struct pe_data_dirs *)hdr->opt_hdr_64.rva_and_sizes; + + default: + return 0; + } +} diff --git a/src/headers/pe_get_image_dos_hdr_addr.c b/src/headers/pe_get_image_dos_hdr_addr.c new file mode 100644 index 0000000..279d04e --- /dev/null +++ b/src/headers/pe_get_image_dos_hdr_addr.c @@ -0,0 +1,24 @@ +/*****************************************************************************/ +/* 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 + +#include +#include +#include + +pe_api +struct pe_image_dos_hdr * pe_get_image_dos_hdr_addr(const void * base) +{ + struct pe_image_dos_hdr * dos; + + dos = (struct pe_image_dos_hdr *)base; + + if ((dos->dos_magic[0] == 'M') && (dos->dos_magic[1] == 'Z')) + return dos; + else + return 0; +} diff --git a/src/headers/pe_get_image_entry_point_addr.c b/src/headers/pe_get_image_entry_point_addr.c new file mode 100644 index 0000000..5869633 --- /dev/null +++ b/src/headers/pe_get_image_entry_point_addr.c @@ -0,0 +1,39 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include + + +pe_api +void * pe_get_image_entry_point_addr(const void * base) +{ + uint16_t * magic; + union pe_opt_hdr * hdr; + uint32_t * rva; + + if (!(hdr = pe_get_image_opt_hdr_addr(base))) + return 0; + + magic = (uint16_t *)hdr; + + switch (*magic) { + case PE_MAGIC_PE32: + rva = (uint32_t *)hdr->opt_hdr_32.entry_point; + break; + + case PE_MAGIC_PE32_PLUS: + rva = (uint32_t *)hdr->opt_hdr_64.entry_point; + break; + + default: + return 0; + } + + return pe_va_from_rva(base,*rva); +} diff --git a/src/headers/pe_get_image_opt_hdr_addr.c b/src/headers/pe_get_image_opt_hdr_addr.c new file mode 100644 index 0000000..dcb8c48 --- /dev/null +++ b/src/headers/pe_get_image_opt_hdr_addr.c @@ -0,0 +1,20 @@ +/*****************************************************************************/ +/* 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 +#include +#include + +pe_api +union pe_opt_hdr * pe_get_image_opt_hdr_addr(const void * base) +{ + struct pe_coff_file_hdr * coff; + + if (!(coff = pe_get_image_coff_hdr_addr(base))) + return 0; + else + return (union pe_opt_hdr *)pe_va_from_rva(coff, sizeof(*coff)); +} diff --git a/src/headers/pe_get_image_special_hdr_addr.c b/src/headers/pe_get_image_special_hdr_addr.c new file mode 100644 index 0000000..276ec9f --- /dev/null +++ b/src/headers/pe_get_image_special_hdr_addr.c @@ -0,0 +1,49 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include +#include "pe_impl.h" + +pe_api +void * pe_get_image_special_hdr_addr(const void * base, uint32_t ordinal, uint32_t * sec_size) +{ + struct pe_data_dirs * dirs; + struct pe_block * dir; + uint32_t * count; + + if (!(dirs = pe_get_image_data_dirs_addr(base))) + return 0; + + count = (uint32_t *)dirs->rva_and_sizes; + + if (*count < (ordinal+1)) + return 0; + + dir = (struct pe_block *)dirs->export_tbl; + dir += ordinal; + + if (sec_size) + *sec_size = dir->size; + + return dir->rva + ? pe_va_from_rva(base,dir->rva) + : 0; +} + +pe_api +struct pe_export_hdr * pe_get_image_export_hdr_addr(const void * base, uint32_t * sec_size) +{ + return (struct pe_export_hdr *)pe_get_image_special_hdr_addr(base,PE_IMAGE_DATA_DIR_ORDINAL_EXPORT,sec_size); +} + +pe_api +struct pe_import_hdr * pe_get_image_import_dir_addr(const void * base, uint32_t * sec_size) +{ + return (struct pe_import_hdr *)pe_get_image_special_hdr_addr(base,PE_IMAGE_DATA_DIR_ORDINAL_IMPORT,sec_size); +} diff --git a/src/imports/pe_enum_image_import_hdrs.c b/src/imports/pe_enum_image_import_hdrs.c new file mode 100644 index 0000000..0a1a10e --- /dev/null +++ b/src/imports/pe_enum_image_import_hdrs.c @@ -0,0 +1,35 @@ +/*****************************************************************************/ +/* 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 +#include +#include + +pe_api +int pe_enum_image_import_hdrs( + const void * base, + pe_enum_image_import_hdrs_callback * callback, + void * ctx) +{ + struct pe_import_hdr * imp_hdr; + int ret; + + if (!(imp_hdr = pe_get_image_import_dir_addr(base,0))) { + callback(base,0,PE_CALLBACK_REASON_ERROR,ctx); + return -1; + } + + if ((ret = callback(base,0,PE_CALLBACK_REASON_INIT,ctx)) <= 0) + return ret; + + while (imp_hdr->name_rva[0]) { + if ((ret = callback(base,imp_hdr,PE_CALLBACK_REASON_ITEM,ctx)) <= 0) + return ret; + imp_hdr++; + }; + + return callback(base,imp_hdr,PE_CALLBACK_REASON_DONE,ctx); +} diff --git a/src/internal/pe_impl.c b/src/internal/pe_impl.c new file mode 100644 index 0000000..46069e8 --- /dev/null +++ b/src/internal/pe_impl.c @@ -0,0 +1,51 @@ +/*****************************************************************************/ +/* 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 +#include +#include "pe_impl.h" + +size_t pe_impl_strlen_ansi(const char * str) +{ + char * ch; + char * upper_bound; + + /* sanity check */ + upper_bound = (char *)str + PE_STR_MAX_SYMBOL_LEN_ALLOWED; + + for (ch = (char *)str; (ch < upper_bound) && (*ch); ch++); + + if (ch < upper_bound) + return (size_t)((intptr_t)ch - (intptr_t)str); + else + return -1; +} + + +size_t pe_impl_strlen_utf16(const wchar16_t * str) +{ + wchar16_t * wch; + wchar16_t * upper_bound; + + /* sanity check */ + upper_bound = (wchar16_t *)str + PE_STR_MAX_SYMBOL_LEN_ALLOWED; + + for (wch = (wchar16_t *)str; (wch < upper_bound) && (*wch); wch++); + + if (wch < upper_bound) + return (size_t)((intptr_t)wch - (intptr_t)str); + else + return -1; +} + + +wchar16_t pe_impl_utf16_char_to_lower(const wchar16_t c) +{ + if ((c >= 'A') && (c <= 'Z')) + return c + 'a' - 'A'; + else + return c; +} diff --git a/src/internal/pe_impl.h b/src/internal/pe_impl.h new file mode 100644 index 0000000..09e81c9 --- /dev/null +++ b/src/internal/pe_impl.h @@ -0,0 +1,17 @@ +#include +#include + +#define PE_STR_MAX_SYMBOL_LEN_ALLOWED (uint32_t)0x10000 + +#define IN_LOAD_ORDER_MODULE_LIST_OFFSET (intptr_t)0x00 +#define IN_MEMORY_ORDER_MODULE_LIST_OFFSET (intptr_t)0x01 * sizeof(struct pe_list_entry) +#define IN_INITIALIZATION_ORDER_MODULE_LIST_OFFSET (intptr_t)0x02 * sizeof(struct pe_list_entry) + +struct pe_block { + uint32_t rva; + uint32_t size; +}; + +size_t pe_impl_strlen_ansi(const char * str); +size_t pe_impl_strlen_utf16(const wchar16_t * str); +wchar16_t pe_impl_utf16_char_to_lower(const wchar16_t c); diff --git a/src/internal/pe_lib_entry_point.c b/src/internal/pe_lib_entry_point.c new file mode 100644 index 0000000..efdaa26 --- /dev/null +++ b/src/internal/pe_lib_entry_point.c @@ -0,0 +1,6 @@ +#include + +int __stdcall pe_lib_entry_point(void * hinstance, uint32_t reason, void * reserved) +{ + return 1; +} diff --git a/src/meta/pe_get_image_stack_heap_info.c b/src/meta/pe_get_image_stack_heap_info.c new file mode 100644 index 0000000..ec1aba9 --- /dev/null +++ b/src/meta/pe_get_image_stack_heap_info.c @@ -0,0 +1,43 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include + +pe_api +int pe_get_image_stack_heap_info(const void * base, struct pe_stack_heap_info * stack_heap_info) +{ + uint16_t * magic; + union pe_opt_hdr * hdr; + + if (!(hdr = pe_get_image_opt_hdr_addr(base))) + return 0; + + magic = (uint16_t *)hdr; + + switch (*magic) { + case PE_MAGIC_PE32: + stack_heap_info->size_of_stack_reserve = *(uint32_t *)hdr->opt_hdr_32.size_of_stack_reserve; + stack_heap_info->size_of_stack_commit = *(uint32_t *)hdr->opt_hdr_32.size_of_stack_commit; + stack_heap_info->size_of_heap_reserve = *(uint32_t *)hdr->opt_hdr_32.size_of_heap_reserve; + stack_heap_info->size_of_heap_commit = *(uint32_t *)hdr->opt_hdr_32.size_of_heap_commit; + break; + + case PE_MAGIC_PE32_PLUS: + stack_heap_info->size_of_stack_reserve = *(size_t *)hdr->opt_hdr_64.size_of_stack_reserve; + stack_heap_info->size_of_stack_commit = *(size_t *)hdr->opt_hdr_64.size_of_stack_commit; + stack_heap_info->size_of_heap_reserve = *(size_t *)hdr->opt_hdr_64.size_of_heap_reserve; + stack_heap_info->size_of_heap_commit = *(size_t *)hdr->opt_hdr_64.size_of_heap_commit; + break; + + default: + return -1; + } + + return 0; +} diff --git a/src/meta/pe_get_symbol_module_info.c b/src/meta/pe_get_symbol_module_info.c new file mode 100644 index 0000000..7dd8a5a --- /dev/null +++ b/src/meta/pe_get_symbol_module_info.c @@ -0,0 +1,56 @@ +/*****************************************************************************/ +/* 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 +#include + + +struct pe_module_info_ctx { + uintptr_t sym_addr; + struct pe_ldr_tbl_entry * image_ldr_tbl_entry; +}; + + + +static int pe_get_symbol_module_info_callback( + struct pe_ldr_tbl_entry * ldr_tbl_entry, + enum pe_callback_reason reason, + void * context) +{ + uintptr_t image_base; + uintptr_t image_size; + struct pe_module_info_ctx * ctx; + + if (reason != PE_CALLBACK_REASON_ITEM) + return 1; + + ctx = (struct pe_module_info_ctx *)context; + image_base = (uintptr_t)(ldr_tbl_entry->dll_base); + image_size = (uintptr_t)(ldr_tbl_entry->size_of_image); + + if ((ctx->sym_addr > image_base) && (ctx->sym_addr < image_base + image_size)) { + /* within bounds */ + ctx->image_ldr_tbl_entry = ldr_tbl_entry; + return 0; + } else + return 1; +} + + +pe_api +struct pe_ldr_tbl_entry * pe_get_symbol_module_info(const void * sym_addr) +{ + struct pe_module_info_ctx ctx; + + ctx.sym_addr = (uintptr_t)sym_addr; + ctx.image_ldr_tbl_entry = 0; + + pe_enum_modules_in_load_order( + pe_get_symbol_module_info_callback, + &ctx); + + return ctx.image_ldr_tbl_entry; +} diff --git a/src/meta/pe_get_symbol_name.c b/src/meta/pe_get_symbol_name.c new file mode 100644 index 0000000..f9001ef --- /dev/null +++ b/src/meta/pe_get_symbol_name.c @@ -0,0 +1,209 @@ +/*****************************************************************************/ +/* 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 +#include + +/* private args structure */ +struct pe_symbol_name_ctx { + const void * addr; + char * name; +}; + +/* private forward declarations */ +static int pe_enum_exports_callback( + const void * base, + struct pe_export_hdr * exp_hdr, + struct pe_export_sym * sym, + enum pe_callback_reason reason, + void * context); + +#if defined (__NT32) +static char * pe_get_imported_symbol_info_32( + const void * sym_addr, + void ** sym_image_addr, + char ** sym_name, + struct pe_ldr_tbl_entry ** ldr_tbl_entry); +#endif + +#if defined (__NT64) +static char * pe_get_imported_symbol_info_64( + const void * sym_addr, + void ** sym_image_addr, + char ** sym_name, + struct pe_ldr_tbl_entry ** ldr_tbl_entry); +; +#endif + +pe_api +char * pe_get_symbol_name(const void * base, const void * sym_addr) +{ + struct pe_export_sym exp_item; + struct pe_symbol_name_ctx ctx; + + ctx.name = 0; + ctx.addr = sym_addr; + + pe_enum_image_exports( + base, + pe_enum_exports_callback, + &exp_item, + &ctx); + + return ctx.name; +} + + +pe_api +char * pe_get_import_symbol_info( + const void * sym_addr, + void ** sym_image_addr, + char ** sym_name, + struct pe_ldr_tbl_entry ** ldr_tbl_entry) +{ + #if defined(__NT32) + return pe_get_imported_symbol_info_32( + sym_addr, + sym_image_addr, + sym_name, + ldr_tbl_entry); + #elif defined (__NT64) + return pe_get_imported_symbol_info_64( + sym_addr, + sym_image_addr, + sym_name, + ldr_tbl_entry); + #endif +} + +static int pe_enum_exports_callback( + const void * base, + struct pe_export_hdr * exp_hdr, + struct pe_export_sym * sym, + enum pe_callback_reason reason, + void * context) +{ + struct pe_symbol_name_ctx * ctx; + + if (reason != PE_CALLBACK_REASON_ITEM) + return 1; + + ctx = (struct pe_symbol_name_ctx *)context; + + if (sym->addr == ctx->addr) { + ctx->name = sym->name; + return 0; + } else + return 1; +} + + +#ifdef __NT32 +static char * pe_get_imported_symbol_info_32( + const void * sym_addr, + void ** sym_image_addr, + char ** sym_name, + struct pe_ldr_tbl_entry ** ldr_tbl_entry) +{ + struct symbol { + unsigned char call; + unsigned char ds; + unsigned char sym_addr[4]; + unsigned char padding[2]; + }; + + char * fn_name; + struct pe_ldr_tbl_entry * mod_info; + void * mod_base; + uint32_t *** sym_redirected_addr; + struct symbol * sym; + + fn_name = 0; + mod_info = 0; + sym = (struct symbol *)sym_addr; + + if ((sym->call == 0xff) && (sym->ds == 0x25)) { + sym_redirected_addr = (uint32_t ***)sym->sym_addr; + + if (sym_redirected_addr) + mod_info = pe_get_symbol_module_info(**sym_redirected_addr); + + if (mod_info) + mod_base = mod_info->dll_base; + else + mod_base = (void *)0; + + if (mod_base) + fn_name = pe_get_symbol_name( + mod_base, + **sym_redirected_addr); + } + + if (fn_name && ldr_tbl_entry) + *ldr_tbl_entry = mod_info; + + return fn_name; +} +#endif + + +#ifdef __NT64 +static char * pe_get_imported_symbol_info_64( + const void * sym_addr, + void ** sym_image_addr, + char ** sym_name, + struct pe_ldr_tbl_entry ** ldr_tbl_entry) +{ + struct symbol { + unsigned char call; + unsigned char ds; + unsigned char sym_addr[4]; + unsigned char padding[2]; + }; + + char * fn_name; + struct pe_ldr_tbl_entry * mod_info; + void * mod_base; + uint32_t * sym_offset; + uint32_t offset; + struct symbol * sym; + + fn_name = 0; + mod_info = 0; + sym = (struct symbol *)sym_addr; + + if ((sym->call == 0xff) && (sym->ds == 0x25)) { + sym_offset = (uint32_t *)sym->sym_addr; + + if (sym_offset) { + offset = *sym_offset; + sym_addr = *(void **)(offset + (uintptr_t)(++sym_offset)); + mod_info = pe_get_symbol_module_info(sym_addr); + } + + if (mod_info) + mod_base = mod_info->dll_base; + else + mod_base = (void *)0; + + if (mod_base) + fn_name = pe_get_symbol_name(mod_base,sym_addr); + } + + if (fn_name) { + if (ldr_tbl_entry) + *ldr_tbl_entry = mod_info; + + if (sym_image_addr) + *sym_image_addr = (void *)sym_addr; + + if (sym_name) + *sym_name = fn_name; + } + + return fn_name; +} +#endif diff --git a/src/modules/pe_enum_modules.c b/src/modules/pe_enum_modules.c new file mode 100644 index 0000000..c36b076 --- /dev/null +++ b/src/modules/pe_enum_modules.c @@ -0,0 +1,102 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include +#include "pe_impl.h" + +static int pe_enum_modules( + pe_enum_modules_callback * callback, + const uintptr_t in_order_member_offset, + void * context) +{ + int ret; + uintptr_t peb_tbl_addr; + struct pe_peb_ldr_data * peb_ldr_data; + struct pe_ldr_tbl_entry * ldr_tbl_entry; + struct pe_list_entry * plist_head; + struct pe_list_entry * plist_current; + + peb_ldr_data = (struct pe_peb_ldr_data *)pe_get_peb_ldr_data_address(); + plist_head = (struct pe_list_entry *)0; + + if ((intptr_t)peb_ldr_data == 0) { + callback( + 0, + PE_CALLBACK_REASON_ERROR, + context); + return -1; + } + + ret = callback( + 0, + PE_CALLBACK_REASON_INIT, + context); + + if (ret <= 0) + return ret; + + switch (in_order_member_offset) { + case IN_LOAD_ORDER_MODULE_LIST_OFFSET: + plist_head = peb_ldr_data->in_load_order_module_list.flink; + break; + + case IN_MEMORY_ORDER_MODULE_LIST_OFFSET: + plist_head = peb_ldr_data->in_memory_order_module_list.flink; + break; + + case IN_INITIALIZATION_ORDER_MODULE_LIST_OFFSET: + plist_head = peb_ldr_data->in_init_order_module_list.flink; + break; + } + + plist_current = plist_head; + + do + { + peb_tbl_addr = (uintptr_t)plist_current - in_order_member_offset; + ldr_tbl_entry = (struct pe_ldr_tbl_entry *)peb_tbl_addr; + + ret = callback( + ldr_tbl_entry, + PE_CALLBACK_REASON_ITEM, + context); + + if (ret <= 0) + return ret; + else + plist_current = plist_current->flink; + + } while (plist_current != plist_head); + + ret = callback( + ldr_tbl_entry, + PE_CALLBACK_REASON_DONE, + context); + + return ret; +} + + +pe_api +int pe_enum_modules_in_load_order(pe_enum_modules_callback * fn, void * ctx) +{ + return pe_enum_modules(fn,IN_LOAD_ORDER_MODULE_LIST_OFFSET,ctx); +} + +pe_api +int pe_enum_modules_in_memory_order(pe_enum_modules_callback * fn, void * ctx) +{ + return pe_enum_modules(fn,IN_MEMORY_ORDER_MODULE_LIST_OFFSET,ctx); +} + +pe_api +int pe_enum_modules_in_init_order(pe_enum_modules_callback * fn, void * ctx) +{ + return pe_enum_modules(fn,IN_INITIALIZATION_ORDER_MODULE_LIST_OFFSET,ctx); +} diff --git a/src/modules/pe_get_kernel32_module_handle.c b/src/modules/pe_get_kernel32_module_handle.c new file mode 100644 index 0000000..9cd0c18 --- /dev/null +++ b/src/modules/pe_get_kernel32_module_handle.c @@ -0,0 +1,73 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include +#include "pe_impl.h" + +static int pe_get_kernel32_handle_callback( + struct pe_ldr_tbl_entry * ldr_tbl_entry, + enum pe_callback_reason reason, + void * context) +{ + #define KERNEL32_UTF16_STRLEN 24 + + int32_t kernel32_base_name_le[4]; + char * kernel32_base_name_ansi; + + intptr_t * addr; + char * ch; + size_t match; + + /* avoid scan-based false positives */ + kernel32_base_name_le[0] = 0x6E72656B; /* 'kern' */ + kernel32_base_name_le[1] = 0x32336C65; /* 'el32' */ + kernel32_base_name_le[2] = 0x6C6C642E; /* '.dll' */ + kernel32_base_name_le[3] = 0; + + kernel32_base_name_ansi = (char *)&kernel32_base_name_le; + + match = 0; + addr = (intptr_t *)context; + + if (reason == PE_CALLBACK_REASON_ITEM) + if (ldr_tbl_entry->base_dll_name.strlen == KERNEL32_UTF16_STRLEN) { + ch = (char *)ldr_tbl_entry->base_dll_name.buffer; + match = 0; + + while ((match < sizeof(kernel32_base_name_ansi)) + && ((*ch == kernel32_base_name_ansi[match]) + || (*ch == (kernel32_base_name_ansi[match] + 'A' - 'a'))) + && (*(ch + 1) == 0)) { + ch+=sizeof(uint16_t); + match++; + } + } + + if (match == sizeof(kernel32_base_name_ansi)) { + *addr = (intptr_t)ldr_tbl_entry->dll_base; + return 0; + } + else + return 1; +} + + +pe_api +void * pe_get_kernel32_module_handle(void) +{ + + intptr_t kernel32_base_addr = 0; + void * ptr_to_callback = &kernel32_base_addr; + + pe_enum_modules_in_init_order( + &pe_get_kernel32_handle_callback, + ptr_to_callback); + + return (void *)kernel32_base_addr; +} diff --git a/src/modules/pe_get_module_handle.c b/src/modules/pe_get_module_handle.c new file mode 100644 index 0000000..7677ba0 --- /dev/null +++ b/src/modules/pe_get_module_handle.c @@ -0,0 +1,80 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include +#include "pe_impl.h" + +pe_api +void * pe_get_first_module_handle(void) +{ + struct pe_peb_ldr_data * peb_ldr_data; + struct pe_list_entry * peb_list_entry; + intptr_t peb_tbl_addr; + struct pe_ldr_tbl_entry * peb_ldr_tbl_entry; + + peb_ldr_data = (struct pe_peb_ldr_data *)pe_get_peb_ldr_data_address(); + peb_list_entry = (struct pe_list_entry *)peb_ldr_data->in_load_order_module_list.flink; + peb_tbl_addr = (intptr_t)peb_list_entry - IN_LOAD_ORDER_MODULE_LIST_OFFSET; + peb_ldr_tbl_entry = (struct pe_ldr_tbl_entry *)peb_tbl_addr; + + return peb_ldr_tbl_entry->dll_base; +} + +pe_api +void * pe_get_module_handle(const wchar16_t * name) +{ + wchar16_t * src; + wchar16_t * dst; + + size_t match; + size_t len; + + struct pe_peb_ldr_data * peb_ldr_data; + struct pe_list_entry * plist_head; + + struct pe_list_entry * plist_current; + struct pe_ldr_tbl_entry * ldr_tbl_entry = 0; + + peb_ldr_data = (struct pe_peb_ldr_data *)pe_get_peb_ldr_data_address(); + plist_head = (struct pe_list_entry *)peb_ldr_data->in_load_order_module_list.flink; + plist_current = plist_head; + + len = pe_impl_strlen_utf16(name); + + do { + ldr_tbl_entry = (struct pe_ldr_tbl_entry *)plist_current - IN_LOAD_ORDER_MODULE_LIST_OFFSET; + + if (ldr_tbl_entry->base_dll_name.strlen == len) + dst = (wchar16_t *)ldr_tbl_entry->base_dll_name.buffer; + else if (ldr_tbl_entry->full_dll_name.strlen == len) + dst = (wchar16_t *)ldr_tbl_entry->full_dll_name.buffer; + else + dst = (wchar16_t *)0; + + if ((intptr_t)(dst)) { + src = (wchar16_t *)name; + match = 0; + + while ((match < len) + && ((pe_impl_utf16_char_to_lower(*src)) == (pe_impl_utf16_char_to_lower(*dst)))) { + src = (wchar16_t *)pe_va_from_rva(src,sizeof(wchar16_t)); + dst = (wchar16_t *)pe_va_from_rva(dst,sizeof(wchar16_t)); + match+=sizeof(wchar16_t); + } + + if (match == len) + return ldr_tbl_entry->dll_base; + } + + plist_current = plist_current->flink; + } while (plist_current != plist_head); + + /* address not found */ + return 0; +} diff --git a/src/modules/pe_get_ntdll_module_handle.c b/src/modules/pe_get_ntdll_module_handle.c new file mode 100644 index 0000000..72f81ec --- /dev/null +++ b/src/modules/pe_get_ntdll_module_handle.c @@ -0,0 +1,27 @@ +/*****************************************************************************/ +/* 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 +#include +#include +#include +#include "pe_impl.h" + +pe_api +void * pe_get_ntdll_module_handle(void) +{ + struct pe_peb_ldr_data * peb_ldr_data; + struct pe_list_entry * peb_list_entry; + intptr_t peb_tbl_addr; + struct pe_ldr_tbl_entry * peb_ldr_tbl_entry; + + peb_ldr_data = (struct pe_peb_ldr_data *)pe_get_peb_ldr_data_address(); + peb_list_entry = peb_ldr_data->in_init_order_module_list.flink; + peb_tbl_addr = (intptr_t)peb_list_entry - IN_INITIALIZATION_ORDER_MODULE_LIST_OFFSET; + peb_ldr_tbl_entry = (struct pe_ldr_tbl_entry *)peb_tbl_addr; + + return peb_ldr_tbl_entry->dll_base; +} -- cgit v1.2.3