summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authormidipix <writeonce@midipix.org>2015-05-08 23:22:07 -0400
committermidipix <writeonce@midipix.org>2015-05-08 23:22:07 -0400
commitfeffc7263bb2fd33ae467de2dd51f1ddbbb1b895 (patch)
tree983daec02a2d1833796ad8bd04d43d9b3ec42765 /src
parent23329916dde5e0ffa056f74a81aeda1bfb7e54cc (diff)
downloadpemagine-feffc7263bb2fd33ae467de2dd51f1ddbbb1b895.tar.bz2
pemagine-feffc7263bb2fd33ae467de2dd51f1ddbbb1b895.tar.xz
initial commit.
Diffstat (limited to 'src')
-rw-r--r--src/exports/pe_enum_image_exports.c61
-rw-r--r--src/exports/pe_get_export_symbol_info.c142
-rw-r--r--src/exports/pe_get_procedure_address.c18
-rw-r--r--src/headers/pe_get_image_coff_hdr_addr.c30
-rw-r--r--src/headers/pe_get_image_data_dirs_addr.c33
-rw-r--r--src/headers/pe_get_image_dos_hdr_addr.c24
-rw-r--r--src/headers/pe_get_image_entry_point_addr.c39
-rw-r--r--src/headers/pe_get_image_opt_hdr_addr.c20
-rw-r--r--src/headers/pe_get_image_special_hdr_addr.c49
-rw-r--r--src/imports/pe_enum_image_import_hdrs.c35
-rw-r--r--src/internal/pe_impl.c51
-rw-r--r--src/internal/pe_impl.h17
-rw-r--r--src/internal/pe_lib_entry_point.c6
-rw-r--r--src/meta/pe_get_image_stack_heap_info.c43
-rw-r--r--src/meta/pe_get_symbol_module_info.c56
-rw-r--r--src/meta/pe_get_symbol_name.c209
-rw-r--r--src/modules/pe_enum_modules.c102
-rw-r--r--src/modules/pe_get_kernel32_module_handle.c73
-rw-r--r--src/modules/pe_get_module_handle.c80
-rw-r--r--src/modules/pe_get_ntdll_module_handle.c27
20 files changed, 1115 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;
+
+}
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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+
+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 <psxtypes/psxtypes.h>
+
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pemagine.h>
+
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+#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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+#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 <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+
+#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 <psxtypes/psxtypes.h>
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+
+
+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 <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+
+/* 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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+#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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+#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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+#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 <psxtypes/psxtypes.h>
+#include <pemagine/pe_consts.h>
+#include <pemagine/pe_structs.h>
+#include <pemagine/pemagine.h>
+#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;
+}