Blame src/ldso/pe_load_framework_loader.c

482851
/*****************************************************************************/
482851
/*  pemagination: a (virtual) tour into portable bits and executable bytes   */
6dda52
/*  Copyright (C) 2013--2020  SysDeer Technologies, LLC                      */
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
				'\\','?','?','\\',
0443ad
				'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;
0443ad
	path.strlen = 6 * 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
0443ad
				| OS_FILE_READ_ATTRIBUTES,
482851
			&oa,&iosb,
482851
			OS_FILE_SHARE_READ
482851
				| OS_FILE_SHARE_WRITE
482851
				| OS_FILE_SHARE_DELETE,
0443ad
			OS_FILE_SYNCHRONOUS_IO_ALERT);
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
0443ad
				if (devnamelen == dpath->strlen) {
0443ad
					idx = 0;
0443ad
					cap = devnamelen / sizeof(wchar16_t);
482851
0443ad
					for (; idx
0443ad
						idx++;
482851
0443ad
					if (idx==cap) {
0443ad
						zw_close(hdevice);
0443ad
						*letter = letters[sigh];
482851
0443ad
						return OS_STATUS_SUCCESS;
0443ad
					}
482851
				}
482851
			}
482851
482851
			zw_close(hdevice);
482851
		}
482851
	}
482851
482851
	return OS_STATUS_NOT_SUPPORTED;
482851
}
482851
482851
aa2c17
static int32_t pe_load_library_impl(
aa2c17
	void **		baseaddr,
aa2c17
	void *		hdsolib,
aa2c17
	uintptr_t *	buffer,
aa2c17
	uint32_t	bufsize,
aa2c17
	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(
aa2c17
			hdsolib,
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
}
aa2c17
aa2c17
aa2c17
int32_t pe_load_framework_loader(
aa2c17
	void **					baseaddr,
aa2c17
	struct pe_framework_runtime_data *	rtdata,
aa2c17
	uintptr_t *				buffer,
aa2c17
	uint32_t				bufsize,
aa2c17
	uint32_t *				sysflags)
aa2c17
{
aa2c17
	return pe_load_library_impl(
aa2c17
		baseaddr,
aa2c17
		rtdata->hloader,
aa2c17
		buffer,bufsize,
aa2c17
		sysflags);
aa2c17
}
224f38
224f38
224f38
int32_t pe_load_framework_library(
224f38
	void **					baseaddr,
224f38
	void *					hat,
224f38
	const wchar16_t *			atrelname,
224f38
	uintptr_t *				buffer,
224f38
	uint32_t				bufsize,
224f38
	uint32_t *				sysflags)
224f38
{
224f38
	int32_t			status;
224f38
	struct pe_unicode_str	path;
224f38
	struct os_oa		oa;
224f38
	struct os_iosb		iosb;
224f38
	const wchar16_t *	wch;
224f38
	const wchar16_t *	wch_cap;
224f38
	void *			hdsolib;
224f38
	void *			hntdll;
224f38
	os_zw_close *		zw_close;
224f38
	os_zw_open_file *	zw_open_file;
224f38
224f38
	/* init */
224f38
	if (!(hntdll = pe_get_ntdll_module_handle()))
224f38
		return OS_STATUS_INTERNAL_ERROR;
224f38
224f38
	if (!(zw_close = (os_zw_close *)pe_get_procedure_address(
224f38
			hntdll,"ZwClose")))
224f38
		return OS_STATUS_INTERNAL_ERROR;
224f38
224f38
	if (!(zw_open_file = (os_zw_open_file *)pe_get_procedure_address(
224f38
			hntdll,"ZwOpenFile")))
224f38
		return OS_STATUS_INTERNAL_ERROR;
224f38
224f38
	/* oa */
224f38
	oa.len      = sizeof(struct os_oa);
224f38
	oa.root_dir = hat;
224f38
	oa.obj_name = &pat;;
224f38
	oa.obj_attr = 0;
224f38
	oa.sec_desc = 0;
224f38
	oa.sec_qos  = 0;
224f38
224f38
	/* at-relative path */
224f38
	wch     = atrelname;
224f38
	wch_cap = atrelname + 512;
224f38
224f38
	for (; *wch && wch
224f38
		wch++;
224f38
224f38
	if (*wch)
224f38
		return OS_STATUS_NAME_TOO_LONG;
224f38
224f38
	path.buffer = (wchar16_t *)atrelname;
224f38
	path.strlen = sizeof(wchar16_t) * (wch - atrelname);
224f38
	path.maxlen = 0;
224f38
224f38
	/* open at */
224f38
	if ((status = zw_open_file(
224f38
			&hdsolib,
224f38
			OS_SEC_SYNCHRONIZE
224f38
				| OS_FILE_READ_ACCESS
224f38
				| OS_FILE_READ_ATTRIBUTES,
224f38
			&oa,&iosb,
224f38
			OS_FILE_SHARE_READ
224f38
				| OS_FILE_SHARE_WRITE
224f38
				| OS_FILE_SHARE_DELETE,
224f38
			OS_FILE_NON_DIRECTORY_FILE)))
224f38
		return status;
224f38
224f38
	/* hoppla */
224f38
	status = pe_load_library_impl(
224f38
		baseaddr,hdsolib,
224f38
		buffer,bufsize,
224f38
		sysflags);
224f38
224f38
	/* all done */
224f38
	zw_close(hdsolib);
224f38
224f38
	return status;
224f38
}