Blame src/ldso/pe_find_framework_loader.c

77cbd4
/*****************************************************************************/
77cbd4
/*  pemagination: a (virtual) tour into portable bits and executable bytes   */
6dda52
/*  Copyright (C) 2013--2020  SysDeer Technologies, LLC                      */
77cbd4
/*  Released under GPLv2 and GPLv3; see COPYING.PEMAGINE.                    */
77cbd4
/*****************************************************************************/
77cbd4
77cbd4
#include <psxtypes/psxtypes.h>
77cbd4
#include <pemagine/pemagine.h>
77cbd4
#include "pe_os.h"
77cbd4
77cbd4
int32_t pe_find_framework_loader(
77cbd4
	struct pe_framework_runtime_data *	rtdata,
77cbd4
	const wchar16_t *			basename,
77cbd4
	const wchar16_t *			rrelname,
77cbd4
	void *					refaddr,
77cbd4
	uintptr_t *				buffer,
77cbd4
	uint32_t				bufsize,
77cbd4
	uint32_t				flags)
77cbd4
{
77cbd4
	int32_t			status;
77cbd4
	struct pe_unicode_str	path;
77cbd4
	struct os_oa		oa;
77cbd4
	struct os_iosb		iosb;
77cbd4
	void *			himage;
77cbd4
	void *			himgdir;
77cbd4
	void *			hdsodir;
77cbd4
	void *			hloader;
77cbd4
	void *			hparent;
77cbd4
	void *			hprevious;
77cbd4
	const wchar16_t *	wch;
77cbd4
	const wchar16_t *	wch_cap;
77cbd4
	void *			hntdll;
77cbd4
	os_zw_close *		zw_close;
77cbd4
	os_zw_open_file *	zw_open_file;
77cbd4
77cbd4
	/* init */
77cbd4
	if (!(hntdll = pe_get_ntdll_module_handle()))
77cbd4
		return OS_STATUS_INTERNAL_ERROR;
77cbd4
77cbd4
	if (!(zw_close = (os_zw_close *)pe_get_procedure_address(
77cbd4
			hntdll,"ZwClose")))
77cbd4
		return OS_STATUS_INTERNAL_ERROR;
77cbd4
77cbd4
	if (!(zw_open_file = (os_zw_open_file *)pe_get_procedure_address(
77cbd4
			hntdll,"ZwOpenFile")))
77cbd4
		return OS_STATUS_INTERNAL_ERROR;
77cbd4
77cbd4
	/* flags */
77cbd4
	if (flags == PE_LDSO_INTEGRAL_ONLY)
77cbd4
		(void)0;
77cbd4
	else if (flags == PE_LDSO_DEFAULT_EXECUTABLE)
77cbd4
		(void)0;
77cbd4
	else if (flags == PE_LDSO_STANDALONE_EXECUTABLE)
77cbd4
		(void)0;
77cbd4
	else
77cbd4
		return OS_STATUS_INVALID_PARAMETER;
77cbd4
77cbd4
	/* oa */
77cbd4
	oa.len      = sizeof(struct os_oa);
77cbd4
	oa.root_dir = 0;
77cbd4
	oa.obj_name = &pat;;
77cbd4
	oa.obj_attr = OS_OBJ_CASE_INSENSITIVE;
77cbd4
	oa.sec_desc = 0;
77cbd4
	oa.sec_qos  = 0;
77cbd4
77cbd4
	/* standalone executable? */
77cbd4
	if (flags == PE_LDSO_STANDALONE_EXECUTABLE) {
77cbd4
		wch     = basename;
77cbd4
		wch_cap = basename + 512;
77cbd4
77cbd4
		for (; *wch && wch
49f412
			if ((*wch == '\\') || (*wch == '/'))
77cbd4
				return OS_STATUS_INVALID_PARAMETER;
77cbd4
77cbd4
		if (*wch)
77cbd4
			return OS_STATUS_NAME_TOO_LONG;
77cbd4
77cbd4
		path.buffer = (wchar16_t *)basename;
77cbd4
		path.strlen = sizeof(wchar16_t) * (wch - basename);
77cbd4
		path.maxlen = 0;
77cbd4
77cbd4
		if ((status = pe_open_image_from_addr(
77cbd4
				&himage,refaddr,
77cbd4
				buffer,bufsize,
77cbd4
				0,
77cbd4
				OS_SEC_SYNCHRONIZE
77cbd4
					| OS_FILE_READ_ACCESS
77cbd4
					| OS_FILE_READ_ATTRIBUTES,
77cbd4
				OS_FILE_SHARE_READ
77cbd4
					| OS_FILE_SHARE_WRITE
77cbd4
					| OS_FILE_SHARE_DELETE,
77cbd4
				0)))
77cbd4
			return status;
77cbd4
77cbd4
		if ((status = pe_open_physical_parent_directory(
77cbd4
				&hdsodir,himage,
77cbd4
				buffer,bufsize,
77cbd4
				0,
77cbd4
				OS_SEC_SYNCHRONIZE
77cbd4
					| OS_FILE_READ_ACCESS
77cbd4
					| OS_FILE_READ_ATTRIBUTES,
77cbd4
				OS_FILE_SHARE_READ
77cbd4
					| OS_FILE_SHARE_WRITE
77cbd4
					| OS_FILE_SHARE_DELETE,
77cbd4
				0)))
77cbd4
			return status;
77cbd4
77cbd4
		oa.root_dir = hdsodir;
77cbd4
77cbd4
		if ((status = zw_open_file(
77cbd4
				&hloader,
77cbd4
				OS_SEC_SYNCHRONIZE
77cbd4
					| OS_FILE_READ_ACCESS
77cbd4
					| OS_FILE_READ_ATTRIBUTES,
77cbd4
				&oa,&iosb,
77cbd4
				OS_FILE_SHARE_READ
77cbd4
					| OS_FILE_SHARE_WRITE
77cbd4
					| OS_FILE_SHARE_DELETE,
77cbd4
				OS_FILE_NON_DIRECTORY_FILE)))
77cbd4
			return status;
77cbd4
80fd71
		if (rtdata->hloader)
80fd71
			zw_close(hloader);
80fd71
		else
80fd71
			rtdata->hloader = hloader;
80fd71
77cbd4
		rtdata->hdsodir = hdsodir;
77cbd4
		rtdata->himage  = himage;
77cbd4
77cbd4
		return OS_STATUS_SUCCESS;
77cbd4
	}
77cbd4
77cbd4
	/* root-relative loader path */
77cbd4
	wch     = rrelname;
77cbd4
	wch_cap = rrelname + 512;
77cbd4
77cbd4
	for (; *wch && wch
77cbd4
		wch++;
77cbd4
77cbd4
	if (*wch)
77cbd4
		return OS_STATUS_NAME_TOO_LONG;
77cbd4
77cbd4
	path.buffer = (wchar16_t *)rrelname;
77cbd4
	path.strlen = sizeof(wchar16_t) * (wch - rrelname);
77cbd4
	path.maxlen = 0;
77cbd4
77cbd4
	/* inherited root directory? */
77cbd4
	if (rtdata->hroot) {
77cbd4
		oa.root_dir = rtdata->hroot;
77cbd4
77cbd4
		if ((status = zw_open_file(
77cbd4
				&hloader,
77cbd4
				OS_SEC_SYNCHRONIZE
77cbd4
					| OS_FILE_READ_ACCESS
77cbd4
					| OS_FILE_READ_ATTRIBUTES,
77cbd4
				&oa,&iosb,
77cbd4
				OS_FILE_SHARE_READ
77cbd4
					| OS_FILE_SHARE_WRITE
77cbd4
					| OS_FILE_SHARE_DELETE,
77cbd4
				OS_FILE_NON_DIRECTORY_FILE)))
77cbd4
			return status;
77cbd4
80fd71
		if (rtdata->hloader)
80fd71
			zw_close(hloader);
80fd71
		else
80fd71
			rtdata->hloader = hloader;
80fd71
77cbd4
		rtdata->hdsodir = 0;
77cbd4
77cbd4
		return OS_STATUS_SUCCESS;
77cbd4
	}
77cbd4
77cbd4
	/* integral only and no inherited root directory? */
77cbd4
	if (flags == PE_LDSO_INTEGRAL_ONLY)
77cbd4
		return OS_STATUS_COULD_NOT_INTERPRET;
77cbd4
77cbd4
	/* finde Pluto / find Waldo */
77cbd4
	if ((status = pe_open_image_from_addr(
77cbd4
			&himage,refaddr,
77cbd4
			buffer,bufsize,
77cbd4
			0,
77cbd4
			OS_SEC_SYNCHRONIZE
77cbd4
				| OS_FILE_READ_ACCESS
77cbd4
				| OS_FILE_READ_ATTRIBUTES,
77cbd4
			OS_FILE_SHARE_READ
77cbd4
				| OS_FILE_SHARE_WRITE
77cbd4
				| OS_FILE_SHARE_DELETE,
77cbd4
			0)))
77cbd4
		return status;
77cbd4
77cbd4
	if ((status = pe_open_physical_parent_directory(
77cbd4
			&himgdir,himage,
77cbd4
			buffer,bufsize,
77cbd4
			0,
77cbd4
			OS_SEC_SYNCHRONIZE
77cbd4
				| OS_FILE_READ_ACCESS
77cbd4
				| OS_FILE_READ_ATTRIBUTES,
77cbd4
			OS_FILE_SHARE_READ
77cbd4
				| OS_FILE_SHARE_WRITE
77cbd4
				| OS_FILE_SHARE_DELETE,
77cbd4
			0)))
77cbd4
		return status;
77cbd4
77cbd4
	if ((status = pe_open_physical_parent_directory(
77cbd4
			&hparent,himgdir,
77cbd4
			buffer,bufsize,
77cbd4
			OS_OBJ_INHERIT,
77cbd4
			OS_SEC_SYNCHRONIZE
77cbd4
				| OS_FILE_READ_ACCESS
77cbd4
				| OS_FILE_READ_ATTRIBUTES,
77cbd4
			OS_FILE_SHARE_READ
77cbd4
				| OS_FILE_SHARE_WRITE
77cbd4
				| OS_FILE_SHARE_DELETE,
77cbd4
			0)))
77cbd4
		return status;
77cbd4
77cbd4
	zw_close(himgdir);
77cbd4
77cbd4
	hloader     = 0;
77cbd4
	oa.root_dir = hparent;
77cbd4
77cbd4
	status = zw_open_file(
77cbd4
		&hloader,
77cbd4
		OS_SEC_SYNCHRONIZE
77cbd4
			| OS_FILE_READ_ACCESS
77cbd4
			| OS_FILE_READ_ATTRIBUTES,
77cbd4
		&oa,&iosb,
77cbd4
		OS_FILE_SHARE_READ
77cbd4
			| OS_FILE_SHARE_WRITE
77cbd4
			| OS_FILE_SHARE_DELETE,
77cbd4
		OS_FILE_NON_DIRECTORY_FILE);
77cbd4
77cbd4
	while (!hloader) {
a29a7a
		if (status == OS_STATUS_OBJECT_NAME_NOT_FOUND)
77cbd4
			(void)0;
a29a7a
		else if (status == OS_STATUS_OBJECT_PATH_NOT_FOUND)
77cbd4
			(void)0;
77cbd4
		else
77cbd4
			return status;
77cbd4
77cbd4
		hprevious = hparent;
77cbd4
77cbd4
		if ((status = pe_open_physical_parent_directory(
77cbd4
				&hparent,hprevious,
77cbd4
				buffer,bufsize,
77cbd4
				OS_OBJ_INHERIT,
77cbd4
				OS_SEC_SYNCHRONIZE
77cbd4
					| OS_FILE_READ_ACCESS
77cbd4
					| OS_FILE_READ_ATTRIBUTES,
77cbd4
				OS_FILE_SHARE_READ
77cbd4
					| OS_FILE_SHARE_WRITE
77cbd4
					| OS_FILE_SHARE_DELETE,
77cbd4
				0)))
77cbd4
			return status;
77cbd4
77cbd4
		oa.root_dir = hparent;
77cbd4
77cbd4
		status = zw_open_file(
77cbd4
			&hloader,
77cbd4
			OS_SEC_SYNCHRONIZE
77cbd4
				| OS_FILE_READ_ACCESS
77cbd4
				| OS_FILE_READ_ATTRIBUTES,
77cbd4
			&oa,&iosb,
77cbd4
			OS_FILE_SHARE_READ
77cbd4
				| OS_FILE_SHARE_WRITE
77cbd4
				| OS_FILE_SHARE_DELETE,
77cbd4
			OS_FILE_NON_DIRECTORY_FILE);
77cbd4
77cbd4
		zw_close(hprevious);
77cbd4
	}
77cbd4
80fd71
	if (rtdata->hloader)
80fd71
		zw_close(hloader);
80fd71
	else
80fd71
		rtdata->hloader = hloader;
80fd71
77cbd4
	rtdata->hdsodir = 0;
77cbd4
	rtdata->himage  = himage;
77cbd4
	rtdata->hroot   = hparent;
77cbd4
77cbd4
	return OS_STATUS_SUCCESS;
77cbd4
}