summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/pemagine/pemagine.h38
-rw-r--r--project/common.mk1
-rw-r--r--src/internal/pe_os.h14
-rw-r--r--src/ldso/pe_get_framework_runtime_data.c287
4 files changed, 340 insertions, 0 deletions
diff --git a/include/pemagine/pemagine.h b/include/pemagine/pemagine.h
index 8990b15..61ffb7a 100644
--- a/include/pemagine/pemagine.h
+++ b/include/pemagine/pemagine.h
@@ -30,6 +30,29 @@ struct pe_export_sym {
};
+struct pe_guid {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ unsigned char data4[8];
+};
+
+
+struct pe_guid_str_utf16 {
+ wchar16_t lbrace;
+ wchar16_t group1[8];
+ wchar16_t dash1;
+ wchar16_t group2[4];
+ wchar16_t dash2;
+ wchar16_t group3[4];
+ wchar16_t dash3;
+ wchar16_t group4[4];
+ wchar16_t dash4;
+ wchar16_t group5[12];
+ wchar16_t rbrace;
+};
+
+
struct pe_unicode_str {
uint16_t strlen;
uint16_t maxlen;
@@ -109,6 +132,16 @@ struct pe_ldr_tbl_entry {
};
+struct pe_framework_runtime_data {
+ void * hself;
+ void * hparent;
+ void * himage;
+ void * hroot;
+ void * hcwd;
+ void * hdrive;
+ struct pe_guid abi;
+};
+
/* static inlined functions */
static __inline__ void * pe_get_teb_address(void);
@@ -200,6 +233,11 @@ pe_api void * pe_get_kernel32_module_handle (void);
pe_api wchar16_t * pe_get_peb_command_line(void);
pe_api wchar16_t * pe_get_peb_environment_block(void);
+pe_api int32_t pe_get_framework_runtime_data(
+ struct pe_framework_runtime_data ** rtdata,
+ const wchar16_t * cmdline,
+ const struct pe_guid * abi);
+
pe_api int32_t pe_open_image_from_addr(
void ** himage,
void * addr,
diff --git a/project/common.mk b/project/common.mk
index 695a656..40bfe21 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -10,6 +10,7 @@ API_SRCS = \
src/headers/pe_get_image_section_tbl_addr.c \
src/headers/pe_get_image_special_hdr_addr.c \
src/imports/pe_enum_image_import_hdrs.c \
+ src/ldso/pe_get_framework_runtime_data.c \
src/ldso/pe_get_peb_strings.c \
src/ldso/pe_open_image_from_addr.c \
src/ldso/pe_open_physical_parent_directory.c \
diff --git a/src/internal/pe_os.h b/src/internal/pe_os.h
index f8a787a..d0dc903 100644
--- a/src/internal/pe_os.h
+++ b/src/internal/pe_os.h
@@ -3,6 +3,12 @@
#include <pemagine/pe_structs.h>
+#define OS_STATUS_SUCCESS 0x00000000
+#define OS_STATUS_INVALID_PARAMETER 0xC000000D
+#define OS_STATUS_ILLEGAL_CHARACTER 0xC0000161
+#define OS_STATUS_NO_MATCH 0xC0000272
+#define OS_STATUS_INVALID_ADDRESS 0xC0000141
+#define OS_STATUS_CONTEXT_MISMATCH 0xC0000719
#define OS_STATUS_INTERNAL_ERROR 0xC00000E5
#define OS_STATUS_BAD_FILE_TYPE 0xC0000903
#define OS_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034
@@ -124,6 +130,14 @@ typedef int32_t __stdcall os_zw_query_virtual_memory(
__out uint32_t * returned_length __optional);
+typedef int32_t __stdcall os_zw_read_virtual_memory(
+ __in void * hprocess,
+ __in void * base_address,
+ __out char * buffer,
+ __in size_t buffer_length,
+ __out size_t * bytes_written);
+
+
typedef int32_t __stdcall os_zw_open_file(
__out void ** hfile,
__in uint32_t desired_access,
diff --git a/src/ldso/pe_get_framework_runtime_data.c b/src/ldso/pe_get_framework_runtime_data.c
new file mode 100644
index 0000000..6e024c3
--- /dev/null
+++ b/src/ldso/pe_get_framework_runtime_data.c
@@ -0,0 +1,287 @@
+/*****************************************************************************/
+/* pemagination: a (virtual) tour into portable bits and executable bytes */
+/* Copyright (C) 2013--2017 Z. Gilboa */
+/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */
+/*****************************************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <pemagine/pemagine.h>
+#include "pe_os.h"
+
+struct pe_framework_cmdline {
+ struct pe_guid_str_utf16 guid;
+ wchar16_t space1;
+ wchar16_t rarg[2];
+ wchar16_t space2;
+ wchar16_t addr[2*__SIZEOF_POINTER__];
+ wchar16_t null;
+};
+
+static int32_t pe_hex_utf16_to_uint32(
+ const wchar16_t hex_key_utf16[8],
+ uint32_t * key)
+{
+ int i;
+ unsigned char uch[8];
+ unsigned char ubytes[4];
+ uint32_t * key_ret;
+
+ /* input validation */
+ for (i=0; i<8; i++)
+ if (!((hex_key_utf16[i] >= 'a') && (hex_key_utf16[i] <= 'f')))
+ if (!((hex_key_utf16[i] >= 'A') && (hex_key_utf16[i] <= 'F')))
+ if (!((hex_key_utf16[i] >= '0') && (hex_key_utf16[i] <= '9')))
+ return OS_STATUS_ILLEGAL_CHARACTER;
+
+ /* intermediate step: little endian byte order */
+ uch[0] = (unsigned char)hex_key_utf16[6];
+ uch[1] = (unsigned char)hex_key_utf16[7];
+ uch[2] = (unsigned char)hex_key_utf16[4];
+ uch[3] = (unsigned char)hex_key_utf16[5];
+ uch[4] = (unsigned char)hex_key_utf16[2];
+ uch[5] = (unsigned char)hex_key_utf16[3];
+ uch[6] = (unsigned char)hex_key_utf16[0];
+ uch[7] = (unsigned char)hex_key_utf16[1];
+
+ for (i=0; i<8; i++) {
+ /* 'a' > 'A' > '0' */
+ if (uch[i] >= 'a')
+ uch[i] -= ('a' - 0x0a);
+ else if (uch[i] >= 'A')
+ uch[i] -= ('A' - 0x0a);
+ else
+ uch[i] -= '0';
+ }
+
+ ubytes[0] = uch[0] * 0x10 + uch[1];
+ ubytes[1] = uch[2] * 0x10 + uch[3];
+ ubytes[2] = uch[4] * 0x10 + uch[5];
+ ubytes[3] = uch[6] * 0x10 + uch[7];
+
+ key_ret = (uint32_t *)ubytes;
+ *key = *key_ret;
+
+ return OS_STATUS_SUCCESS;
+}
+
+static int32_t pe_hex_utf16_to_uint16(
+ const wchar16_t hex_key_utf16[4],
+ uint16_t * key)
+{
+ int32_t status;
+ uint32_t dword_key;
+ wchar16_t hex_buf[8] = {'0','0','0','0'};
+
+ hex_buf[4] = hex_key_utf16[0];
+ hex_buf[5] = hex_key_utf16[1];
+ hex_buf[6] = hex_key_utf16[2];
+ hex_buf[7] = hex_key_utf16[3];
+
+ if ((status = pe_hex_utf16_to_uint32(hex_buf,&dword_key)))
+ return status;
+
+ *key = (uint16_t)dword_key;
+
+ return OS_STATUS_SUCCESS;
+}
+
+static int32_t pe_hex_utf16_to_uint64(
+ const wchar16_t hex_key_utf16[16],
+ uint64_t * key)
+{
+ int32_t status;
+ uint32_t x64_key[2];
+ uint64_t * key_ret;
+
+ if ((status = pe_hex_utf16_to_uint32(
+ &hex_key_utf16[0],
+ &x64_key[1])))
+ return status;
+
+ if ((status = pe_hex_utf16_to_uint32(
+ &hex_key_utf16[8],
+ &x64_key[0])))
+ return status;
+
+ key_ret = (uint64_t *)x64_key;
+ *key = *key_ret;
+
+ return OS_STATUS_SUCCESS;
+}
+
+
+static int32_t pe_hex_utf16_to_uintptr(
+ const wchar16_t hex_key_utf16[],
+ uintptr_t * key)
+{
+ #if (__SIZEOF_POINTER__ == 4)
+ return pe_hex_utf16_to_uint32(hex_key_utf16,key);
+ #elif (__SIZEOF_POINTER__ == 8)
+ return pe_hex_utf16_to_uint64(hex_key_utf16,key);
+ #endif
+}
+
+static int32_t pe_string_to_guid_utf16(
+ const struct pe_guid_str_utf16 *guid_str,
+ struct pe_guid * guid)
+{
+ int32_t status;
+ uint16_t key;
+ const wchar16_t * wch;
+
+ if ((guid_str->lbrace != '{')
+ || (guid_str->rbrace != '}')
+ || (guid_str->dash1 != '-')
+ || (guid_str->dash2 != '-')
+ || (guid_str->dash3 != '-')
+ || (guid_str->dash4 != '-'))
+ return OS_STATUS_INVALID_PARAMETER;
+
+ wch = &(guid_str->group5[0]);
+
+ if ((status = pe_hex_utf16_to_uint32(
+ guid_str->group1,
+ &guid->data1)))
+ return status;
+
+ if ((status = pe_hex_utf16_to_uint16(
+ guid_str->group2,
+ &guid->data2)))
+ return status;
+
+ if ((status = pe_hex_utf16_to_uint16(
+ guid_str->group3,
+ &guid->data3)))
+ return status;
+
+ if ((status = pe_hex_utf16_to_uint16(
+ guid_str->group4,
+ &key)))
+ return status;
+
+ guid->data4[0] = key >> 8;
+ guid->data4[1] = key % 0x100;
+
+ if ((status = pe_hex_utf16_to_uint16(
+ &(wch[0]),
+ &key)))
+ return status;
+
+ guid->data4[2] = key >> 8;
+ guid->data4[3] = key % 0x100;
+
+ if ((status = pe_hex_utf16_to_uint16(
+ &(wch[4]),
+ &key)))
+ return status;
+
+ guid->data4[4] = key >> 8;
+ guid->data4[5] = key % 0x100;
+
+ if ((status = pe_hex_utf16_to_uint16(
+ &(wch[8]),
+ &key)))
+ return status;
+
+ guid->data4[6] = key >> 8;
+ guid->data4[7] = key % 0x100;
+
+ return OS_STATUS_SUCCESS;
+}
+
+static int32_t pe_guid_compare(
+ const struct pe_guid * pguid_dst,
+ const struct pe_guid * pguid_src)
+{
+ const uint32_t * dst;
+ const uint32_t * src;
+
+ dst = &pguid_dst->data1;
+ src = &pguid_src->data1;
+
+ if ((dst[0] == src[0])
+ && (dst[1] == src[1])
+ && (dst[2] == src[2])
+ && (dst[3] == src[3]))
+ return OS_STATUS_SUCCESS;
+
+ return OS_STATUS_NO_MATCH;
+}
+
+int32_t pe_get_framework_runtime_data(
+ struct pe_framework_runtime_data ** rtdata,
+ const wchar16_t * cmdline,
+ const struct pe_guid * abi)
+{
+ int32_t status;
+ struct pe_framework_runtime_data * prtdata;
+ struct pe_framework_cmdline * fcmdline;
+ struct pe_guid guid;
+ uintptr_t address;
+ uintptr_t buffer;
+ void * hntdll;
+ os_zw_read_virtual_memory * zw_read_virtual_memory;
+
+ /* init */
+ if (!(hntdll = pe_get_ntdll_module_handle()))
+ return OS_STATUS_INTERNAL_ERROR;
+
+ if (!(zw_read_virtual_memory = (os_zw_read_virtual_memory *)pe_get_procedure_address(
+ hntdll,"ZwReadVirtualMemory")))
+ return OS_STATUS_INTERNAL_ERROR;
+
+ /* framework cmdline */
+ fcmdline = (struct pe_framework_cmdline *)cmdline;
+
+ /* framework cmdline: conformance */
+ if (fcmdline->null)
+ return OS_STATUS_INVALID_PARAMETER;
+
+ /* framework cmdline: rarg */
+ if ((fcmdline->space1 != ' ')
+ || (fcmdline->space2 != ' ')
+ || (fcmdline->rarg[0] != '-')
+ || (fcmdline->rarg[1] != 'r'))
+ return OS_STATUS_INVALID_PARAMETER;
+
+ /* framework cmdline: address */
+ if ((status = pe_hex_utf16_to_uintptr(
+ fcmdline->addr,
+ &address)))
+ return status;
+
+ /* framework cmdline: guid */
+ if ((status = pe_string_to_guid_utf16(
+ &fcmdline->guid,
+ &guid)))
+ return status;
+
+ /* framework cmdline: abi */
+ if ((status = pe_guid_compare(&guid,abi)))
+ return status;
+
+ /* address: alignment */
+ if (address & 0xFFF)
+ return OS_STATUS_INVALID_ADDRESS;
+
+ /* address is aligned at page boundary */
+ if ((status = zw_read_virtual_memory(
+ OS_CURRENT_PROCESS_HANDLE,
+ (void *)address,
+ (char *)&buffer,
+ sizeof(buffer),
+ 0)))
+ return status;
+
+ /* rtdata */
+ prtdata = (struct pe_framework_runtime_data *)address;
+
+ /* rtdata: abi */
+ if (pe_guid_compare(&prtdata->abi,abi))
+ return OS_STATUS_CONTEXT_MISMATCH;
+
+ /* yay */
+ *rtdata = prtdata;
+
+ return OS_STATUS_SUCCESS;
+}