Blame src/ldso/pe_get_framework_runtime_data.c

7cd411
/*****************************************************************************/
7cd411
/*  pemagination: a (virtual) tour into portable bits and executable bytes   */
6dda52
/*  Copyright (C) 2013--2020  SysDeer Technologies, LLC                      */
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')))
be9490
					return OS_STATUS_INVALID_PARAMETER;
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
{
da5089
	(void)pe_hex_utf16_to_uint32;
da5089
	(void)pe_hex_utf16_to_uint64;
da5089
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 */
a4c09f
	if (!(fcmdline = (struct pe_framework_cmdline *)cmdline))
a4c09f
		return OS_STATUS_INVALID_PARAMETER;
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
}