Blame src/ldso/pe_load_framework_loader.c

482851
/*****************************************************************************/
482851
/*  pemagination: a (virtual) tour into portable bits and executable bytes   */
482851
/*  Copyright (C) 2013--2017  Z. Gilboa                                      */
482851
/*  Released under GPLv2 and GPLv3; see COPYING.PEMAGINE.                    */
482851
/*****************************************************************************/
482851
482851
#include <psxtypes/psxtypes.h>
482851
#include <pemagine/pemagine.h>
482851
#include "pe_os.h"
482851
482851
static int32_t pe_get_device_dos_drive_letter(
482851
	void *			hntdll,
482851
	os_zw_query_object *	zw_query_object,
482851
	uintptr_t *		dbuffer,
482851
	uint32_t		dbufsize,
482851
	wchar16_t *		devname,
482851
	size_t			devnamelen,
482851
	wchar16_t *		letter)
482851
{
482851
	int32_t			status;
482851
	void *			hdevice;
482851
	int			sigh;
482851
	size_t			idx;
482851
	size_t			cap;
482851
	uint32_t		len;
482851
	struct os_oa		oa;
482851
	struct os_iosb		iosb;
482851
	wchar16_t *		src;
482851
	wchar16_t *		dst;
482851
	struct pe_unicode_str	path;
482851
	struct pe_unicode_str * dpath;
482851
	os_zw_open_file *	zw_open_file;
482851
	os_zw_close *		zw_close;
482851
482851
	wchar16_t		namebuf[8] = {
482851
				'\\','?','?','\\',
482851
				'X',':','\\',0};
482851
482851
	unsigned char		letters[26] = {
482851
				'C','Z','Y','X','W','V',
482851
				'E','H','F','G','D','I',
482851
				'P','Q','R','S','T','U',
482851
				'J','K','L','M','N','O',
482851
				'A','B'};
482851
482851
	/* init */
482851
	if (!(zw_open_file = (os_zw_open_file *)pe_get_procedure_address(
482851
			hntdll,"ZwOpenFile")))
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	if (!(zw_close = (os_zw_close *)pe_get_procedure_address(
482851
			hntdll,"ZwClose")))
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	/* path */
482851
	path.buffer = namebuf;
482851
	path.strlen = 7 * sizeof(wchar16_t);
482851
	path.maxlen = 0;
482851
482851
	/* oa */
482851
	oa.len      = sizeof(struct os_oa);
482851
	oa.root_dir = 0;
482851
	oa.obj_name = &pat;;
482851
	oa.obj_attr = 0;
482851
	oa.sec_desc = 0;
482851
	oa.sec_qos  = 0;
482851
482851
	/* just a few rounds of submissiveness */
482851
	for (sigh=0; sigh<26; sigh++) {
482851
		namebuf[4] = letters[sigh];
482851
482851
		status = zw_open_file(
482851
			&hdevice,
482851
			OS_SEC_SYNCHRONIZE
482851
				| OS_FILE_READ_ATTRIBUTES
482851
				| OS_FILE_READ_ACCESS,
482851
			&oa,&iosb,
482851
			OS_FILE_SHARE_READ
482851
				| OS_FILE_SHARE_WRITE
482851
				| OS_FILE_SHARE_DELETE,
482851
			OS_FILE_DIRECTORY_FILE);
482851
482851
		if (status == OS_STATUS_SUCCESS) {
482851
			status = zw_query_object(
482851
				hdevice,
482851
				OS_OBJECT_NAME_INFORMATION,
482851
				dbuffer,dbufsize,&len;;
482851
482851
			if (status == OS_STATUS_SUCCESS) {
482851
				dpath = (struct pe_unicode_str *)dbuffer;
482851
482851
				src = devname;
482851
				dst = dpath->buffer;
482851
482851
				idx = 0;
482851
				cap = devnamelen / sizeof(wchar16_t);
482851
482851
				for (; idx
482851
					idx++;
482851
482851
				if (idx==cap && dst[idx]=='\\') {
482851
					zw_close(hdevice);
482851
					*letter = letters[sigh];
482851
482851
					return OS_STATUS_SUCCESS;
482851
				}
482851
			}
482851
482851
			zw_close(hdevice);
482851
		}
482851
	}
482851
482851
	return OS_STATUS_NOT_SUPPORTED;
482851
}
482851
482851
482851
int32_t pe_load_framework_loader(
482851
	void **					baseaddr,
482851
	struct pe_framework_runtime_data *	rtdata,
482851
	uintptr_t *				buffer,
482851
	uint32_t				bufsize,
482851
	uint32_t *				flags)
482851
{
482851
	int32_t			status;
482851
	struct pe_unicode_str	path;
482851
	struct pe_unicode_str *	npath;
482851
	uintptr_t		addr;
482851
	uintptr_t *		dbuffer;
482851
	uint32_t		dbufsize;
482851
	wchar16_t *		ldrdir;
482851
	wchar16_t *		slash;
482851
	wchar16_t *		wch;
482851
	wchar16_t *		cap;
482851
	wchar16_t		letter;
482851
	uint32_t		len;
482851
	int			mup;
482851
	void *			hntdll;
482851
	os_zw_query_object *	zw_query_object;
482851
	os_ldr_load_dll *	ldr_load_dll;
482851
482851
	/* init */
482851
	if (!(hntdll = pe_get_ntdll_module_handle()))
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	if (!(zw_query_object = (os_zw_query_object *)pe_get_procedure_address(
482851
			hntdll,"ZwQueryObject")))
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	if (!(ldr_load_dll = (os_ldr_load_dll *)pe_get_procedure_address(
482851
			hntdll,"LdrLoadDll")))
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	/* loader native path */
482851
	if ((status = zw_query_object(
482851
			rtdata->hloader,
482851
			OS_OBJECT_NAME_INFORMATION,
482851
			buffer,bufsize,&len)))
482851
		return status;
482851
482851
	/* integrity */
482851
	if (len == sizeof(struct pe_unicode_str))
482851
		return OS_STATUS_BAD_FILE_TYPE;
482851
482851
	/* first sigh */
482851
	npath = (struct pe_unicode_str *)buffer;
482851
482851
	wch = npath->buffer;
482851
	cap = npath->buffer + (npath->strlen / sizeof(wchar16_t));
482851
482851
	if ((cap < &wch[8])
482851
			|| (wch[0] != '\\')
482851
			|| (wch[1] != 'D')
482851
			|| (wch[2] != 'e')
482851
			|| (wch[3] != 'v')
482851
			|| (wch[4] != 'i')
482851
			|| (wch[5] != 'c')
482851
			|| (wch[6] != 'e')
482851
			|| (wch[7] != '\\'))
482851
		return OS_STATUS_NOT_SUPPORTED;
482851
482851
	mup = (cap > &wch[11])
482851
		&& (wch[8]=='M')
482851
		&& (wch[9]=='u')
482851
		&& (wch[10]=='p')
482851
		&& (wch[11]=='\\');
482851
482851
	slash = mup ? &wch[12] : &wch[8];
482851
482851
	for (; (*slash != '\\') && (slash < cap); )
482851
		slash++;
482851
482851
	if (slash == cap)
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	if (mup)
482851
		for (++slash; (*slash != '\\') && (slash < cap); )
482851
			slash++;
482851
482851
	if (slash == cap)
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	/* second sigh */
482851
	addr  = (uintptr_t)cap;
482851
	addr += sizeof(uintptr_t) - 1;
482851
	addr /= sizeof(uintptr_t);
482851
	addr *= sizeof(uintptr_t);
482851
482851
	dbuffer   = (uintptr_t *)addr;
482851
	dbufsize  = bufsize;
482851
	dbufsize -= (dbuffer - buffer) * sizeof(uintptr_t);
482851
482851
	if ((status = pe_get_device_dos_drive_letter(
482851
			hntdll,
482851
			zw_query_object,
482851
			dbuffer,dbufsize,
482851
			npath->buffer,
482851
			(slash - npath->buffer) * sizeof(wchar16_t),
482851
			&letter)))
482851
		return status;
482851
482851
	slash    = &slash[-2];
482851
	slash[0] = letter;
482851
	slash[1] = ':';
482851
482851
	path.buffer = slash;
482851
	path.strlen = (cap - slash) * sizeof(wchar16_t);
482851
482851
	/* third sigh */
482851
	for (slash=cap; (slash > path.buffer) && (*slash != '\\'); )
482851
		slash--;
482851
482851
	if (slash == path.buffer)
482851
		return OS_STATUS_INTERNAL_ERROR;
482851
482851
	ldrdir = path.buffer;
482851
	*slash = 0;
482851
482851
	path.strlen -= (++slash - ldrdir) * sizeof(wchar16_t);
482851
	path.maxlen  = path.strlen;
482851
	path.buffer  = slash;
482851
482851
	/* hoppla */
482851
	return ldr_load_dll(
482851
		ldrdir,flags,
482851
		&path,baseaddr);
482851
}