|
|
7cd411 |
/*****************************************************************************/
|
|
|
7cd411 |
/* pemagination: a (virtual) tour into portable bits and executable bytes */
|
|
|
7cd411 |
/* Copyright (C) 2013--2017 Z. Gilboa */
|
|
|
7cd411 |
/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */
|
|
|
7cd411 |
/*****************************************************************************/
|
|
|
7cd411 |
|
|
|
7cd411 |
#include <psxtypes/psxtypes.h>
|
|
|
7cd411 |
#include <pemagine/pemagine.h>
|
|
|
7cd411 |
#include "pe_os.h"
|
|
|
7cd411 |
|
|
|
7cd411 |
struct pe_framework_cmdline {
|
|
|
7cd411 |
struct pe_guid_str_utf16 guid;
|
|
|
7cd411 |
wchar16_t space1;
|
|
|
7cd411 |
wchar16_t rarg[2];
|
|
|
7cd411 |
wchar16_t space2;
|
|
|
7cd411 |
wchar16_t addr[2*__SIZEOF_POINTER__];
|
|
|
7cd411 |
wchar16_t null;
|
|
|
7cd411 |
};
|
|
|
7cd411 |
|
|
|
7cd411 |
static int32_t pe_hex_utf16_to_uint32(
|
|
|
7cd411 |
const wchar16_t hex_key_utf16[8],
|
|
|
7cd411 |
uint32_t * key)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
int i;
|
|
|
7cd411 |
unsigned char uch[8];
|
|
|
7cd411 |
unsigned char ubytes[4];
|
|
|
7cd411 |
uint32_t * key_ret;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* input validation */
|
|
|
7cd411 |
for (i=0; i<8; i++)
|
|
|
7cd411 |
if (!((hex_key_utf16[i] >= 'a') && (hex_key_utf16[i] <= 'f')))
|
|
|
7cd411 |
if (!((hex_key_utf16[i] >= 'A') && (hex_key_utf16[i] <= 'F')))
|
|
|
7cd411 |
if (!((hex_key_utf16[i] >= '0') && (hex_key_utf16[i] <= '9')))
|
|
|
7cd411 |
return OS_STATUS_ILLEGAL_CHARACTER;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* intermediate step: little endian byte order */
|
|
|
7cd411 |
uch[0] = (unsigned char)hex_key_utf16[6];
|
|
|
7cd411 |
uch[1] = (unsigned char)hex_key_utf16[7];
|
|
|
7cd411 |
uch[2] = (unsigned char)hex_key_utf16[4];
|
|
|
7cd411 |
uch[3] = (unsigned char)hex_key_utf16[5];
|
|
|
7cd411 |
uch[4] = (unsigned char)hex_key_utf16[2];
|
|
|
7cd411 |
uch[5] = (unsigned char)hex_key_utf16[3];
|
|
|
7cd411 |
uch[6] = (unsigned char)hex_key_utf16[0];
|
|
|
7cd411 |
uch[7] = (unsigned char)hex_key_utf16[1];
|
|
|
7cd411 |
|
|
|
7cd411 |
for (i=0; i<8; i++) {
|
|
|
7cd411 |
/* 'a' > 'A' > '0' */
|
|
|
7cd411 |
if (uch[i] >= 'a')
|
|
|
7cd411 |
uch[i] -= ('a' - 0x0a);
|
|
|
7cd411 |
else if (uch[i] >= 'A')
|
|
|
7cd411 |
uch[i] -= ('A' - 0x0a);
|
|
|
7cd411 |
else
|
|
|
7cd411 |
uch[i] -= '0';
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
ubytes[0] = uch[0] * 0x10 + uch[1];
|
|
|
7cd411 |
ubytes[1] = uch[2] * 0x10 + uch[3];
|
|
|
7cd411 |
ubytes[2] = uch[4] * 0x10 + uch[5];
|
|
|
7cd411 |
ubytes[3] = uch[6] * 0x10 + uch[7];
|
|
|
7cd411 |
|
|
|
7cd411 |
key_ret = (uint32_t *)ubytes;
|
|
|
7cd411 |
*key = *key_ret;
|
|
|
7cd411 |
|
|
|
7cd411 |
return OS_STATUS_SUCCESS;
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
static int32_t pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
const wchar16_t hex_key_utf16[4],
|
|
|
7cd411 |
uint16_t * key)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
int32_t status;
|
|
|
7cd411 |
uint32_t dword_key;
|
|
|
7cd411 |
wchar16_t hex_buf[8] = {'0','0','0','0'};
|
|
|
7cd411 |
|
|
|
7cd411 |
hex_buf[4] = hex_key_utf16[0];
|
|
|
7cd411 |
hex_buf[5] = hex_key_utf16[1];
|
|
|
7cd411 |
hex_buf[6] = hex_key_utf16[2];
|
|
|
7cd411 |
hex_buf[7] = hex_key_utf16[3];
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint32(hex_buf,&dword_key)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
*key = (uint16_t)dword_key;
|
|
|
7cd411 |
|
|
|
7cd411 |
return OS_STATUS_SUCCESS;
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
static int32_t pe_hex_utf16_to_uint64(
|
|
|
7cd411 |
const wchar16_t hex_key_utf16[16],
|
|
|
7cd411 |
uint64_t * key)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
int32_t status;
|
|
|
7cd411 |
uint32_t x64_key[2];
|
|
|
7cd411 |
uint64_t * key_ret;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint32(
|
|
|
7cd411 |
&hex_key_utf16[0],
|
|
|
7cd411 |
&x64_key[1])))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint32(
|
|
|
7cd411 |
&hex_key_utf16[8],
|
|
|
7cd411 |
&x64_key[0])))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
key_ret = (uint64_t *)x64_key;
|
|
|
7cd411 |
*key = *key_ret;
|
|
|
7cd411 |
|
|
|
7cd411 |
return OS_STATUS_SUCCESS;
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
|
|
|
7cd411 |
static int32_t pe_hex_utf16_to_uintptr(
|
|
|
7cd411 |
const wchar16_t hex_key_utf16[],
|
|
|
7cd411 |
uintptr_t * key)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
#if (__SIZEOF_POINTER__ == 4)
|
|
|
7cd411 |
return pe_hex_utf16_to_uint32(hex_key_utf16,key);
|
|
|
7cd411 |
#elif (__SIZEOF_POINTER__ == 8)
|
|
|
7cd411 |
return pe_hex_utf16_to_uint64(hex_key_utf16,key);
|
|
|
7cd411 |
#endif
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
static int32_t pe_string_to_guid_utf16(
|
|
|
7cd411 |
const struct pe_guid_str_utf16 *guid_str,
|
|
|
7cd411 |
struct pe_guid * guid)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
int32_t status;
|
|
|
7cd411 |
uint16_t key;
|
|
|
7cd411 |
const wchar16_t * wch;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((guid_str->lbrace != '{')
|
|
|
7cd411 |
|| (guid_str->rbrace != '}')
|
|
|
7cd411 |
|| (guid_str->dash1 != '-')
|
|
|
7cd411 |
|| (guid_str->dash2 != '-')
|
|
|
7cd411 |
|| (guid_str->dash3 != '-')
|
|
|
7cd411 |
|| (guid_str->dash4 != '-'))
|
|
|
7cd411 |
return OS_STATUS_INVALID_PARAMETER;
|
|
|
7cd411 |
|
|
|
7cd411 |
wch = &(guid_str->group5[0]);
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint32(
|
|
|
7cd411 |
guid_str->group1,
|
|
|
7cd411 |
&guid->data1)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
guid_str->group2,
|
|
|
7cd411 |
&guid->data2)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
guid_str->group3,
|
|
|
7cd411 |
&guid->data3)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
guid_str->group4,
|
|
|
7cd411 |
&key)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
guid->data4[0] = key >> 8;
|
|
|
7cd411 |
guid->data4[1] = key % 0x100;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
&(wch[0]),
|
|
|
7cd411 |
&key)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
guid->data4[2] = key >> 8;
|
|
|
7cd411 |
guid->data4[3] = key % 0x100;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
&(wch[4]),
|
|
|
7cd411 |
&key)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
guid->data4[4] = key >> 8;
|
|
|
7cd411 |
guid->data4[5] = key % 0x100;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uint16(
|
|
|
7cd411 |
&(wch[8]),
|
|
|
7cd411 |
&key)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
guid->data4[6] = key >> 8;
|
|
|
7cd411 |
guid->data4[7] = key % 0x100;
|
|
|
7cd411 |
|
|
|
7cd411 |
return OS_STATUS_SUCCESS;
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
static int32_t pe_guid_compare(
|
|
|
7cd411 |
const struct pe_guid * pguid_dst,
|
|
|
7cd411 |
const struct pe_guid * pguid_src)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
const uint32_t * dst;
|
|
|
7cd411 |
const uint32_t * src;
|
|
|
7cd411 |
|
|
|
7cd411 |
dst = &pguid_dst->data1;
|
|
|
7cd411 |
src = &pguid_src->data1;
|
|
|
7cd411 |
|
|
|
7cd411 |
if ((dst[0] == src[0])
|
|
|
7cd411 |
&& (dst[1] == src[1])
|
|
|
7cd411 |
&& (dst[2] == src[2])
|
|
|
7cd411 |
&& (dst[3] == src[3]))
|
|
|
7cd411 |
return OS_STATUS_SUCCESS;
|
|
|
7cd411 |
|
|
|
7cd411 |
return OS_STATUS_NO_MATCH;
|
|
|
7cd411 |
}
|
|
|
7cd411 |
|
|
|
7cd411 |
int32_t pe_get_framework_runtime_data(
|
|
|
7cd411 |
struct pe_framework_runtime_data ** rtdata,
|
|
|
7cd411 |
const wchar16_t * cmdline,
|
|
|
7cd411 |
const struct pe_guid * abi)
|
|
|
7cd411 |
{
|
|
|
7cd411 |
int32_t status;
|
|
|
7cd411 |
struct pe_framework_runtime_data * prtdata;
|
|
|
7cd411 |
struct pe_framework_cmdline * fcmdline;
|
|
|
7cd411 |
struct pe_guid guid;
|
|
|
7cd411 |
uintptr_t address;
|
|
|
7cd411 |
uintptr_t buffer;
|
|
|
7cd411 |
void * hntdll;
|
|
|
7cd411 |
os_zw_read_virtual_memory * zw_read_virtual_memory;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* init */
|
|
|
7cd411 |
if (!(hntdll = pe_get_ntdll_module_handle()))
|
|
|
7cd411 |
return OS_STATUS_INTERNAL_ERROR;
|
|
|
7cd411 |
|
|
|
7cd411 |
if (!(zw_read_virtual_memory = (os_zw_read_virtual_memory *)pe_get_procedure_address(
|
|
|
7cd411 |
hntdll,"ZwReadVirtualMemory")))
|
|
|
7cd411 |
return OS_STATUS_INTERNAL_ERROR;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* framework cmdline */
|
|
|
7cd411 |
fcmdline = (struct pe_framework_cmdline *)cmdline;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* framework cmdline: conformance */
|
|
|
7cd411 |
if (fcmdline->null)
|
|
|
7cd411 |
return OS_STATUS_INVALID_PARAMETER;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* framework cmdline: rarg */
|
|
|
7cd411 |
if ((fcmdline->space1 != ' ')
|
|
|
7cd411 |
|| (fcmdline->space2 != ' ')
|
|
|
7cd411 |
|| (fcmdline->rarg[0] != '-')
|
|
|
7cd411 |
|| (fcmdline->rarg[1] != 'r'))
|
|
|
7cd411 |
return OS_STATUS_INVALID_PARAMETER;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* framework cmdline: address */
|
|
|
7cd411 |
if ((status = pe_hex_utf16_to_uintptr(
|
|
|
7cd411 |
fcmdline->addr,
|
|
|
7cd411 |
&address)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* framework cmdline: guid */
|
|
|
7cd411 |
if ((status = pe_string_to_guid_utf16(
|
|
|
7cd411 |
&fcmdline->guid,
|
|
|
7cd411 |
&guid)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* framework cmdline: abi */
|
|
|
7cd411 |
if ((status = pe_guid_compare(&guid,abi)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* address: alignment */
|
|
|
7cd411 |
if (address & 0xFFF)
|
|
|
7cd411 |
return OS_STATUS_INVALID_ADDRESS;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* address is aligned at page boundary */
|
|
|
7cd411 |
if ((status = zw_read_virtual_memory(
|
|
|
7cd411 |
OS_CURRENT_PROCESS_HANDLE,
|
|
|
7cd411 |
(void *)address,
|
|
|
7cd411 |
(char *)&buffer,
|
|
|
7cd411 |
sizeof(buffer),
|
|
|
7cd411 |
0)))
|
|
|
7cd411 |
return status;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* rtdata */
|
|
|
7cd411 |
prtdata = (struct pe_framework_runtime_data *)address;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* rtdata: abi */
|
|
|
7cd411 |
if (pe_guid_compare(&prtdata->abi,abi))
|
|
|
7cd411 |
return OS_STATUS_CONTEXT_MISMATCH;
|
|
|
7cd411 |
|
|
|
7cd411 |
/* yay */
|
|
|
7cd411 |
*rtdata = prtdata;
|
|
|
7cd411 |
|
|
|
7cd411 |
return OS_STATUS_SUCCESS;
|
|
|
7cd411 |
}
|