/*****************************************************************************/ /* 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 #include #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_INVALID_PARAMETER; /* 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) { (void)pe_hex_utf16_to_uint32; (void)pe_hex_utf16_to_uint64; #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 */ if (!(fcmdline = (struct pe_framework_cmdline *)cmdline)) return OS_STATUS_INVALID_PARAMETER; /* 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; }