diff options
author | midipix <writeonce@midipix.org> | 2017-01-28 19:08:59 +0000 |
---|---|---|
committer | midipix <writeonce@midipix.org> | 2017-01-28 21:53:55 -0500 |
commit | 4828517d5b619ddbbfbb05d1d698c50f02869b53 (patch) | |
tree | 70edc5429b2851b1ab12623831b1a832a11320d9 | |
parent | 75545658ab6d9a6b4e3d73466c95158f7c22fb17 (diff) | |
download | pemagine-4828517d5b619ddbbfbb05d1d698c50f02869b53.tar.bz2 pemagine-4828517d5b619ddbbfbb05d1d698c50f02869b53.tar.xz |
ldso: added pe_load_framework_loader().
-rw-r--r-- | include/pemagine/pemagine.h | 8 | ||||
-rw-r--r-- | project/common.mk | 1 | ||||
-rw-r--r-- | src/internal/pe_os.h | 7 | ||||
-rw-r--r-- | src/ldso/pe_load_framework_loader.c | 246 |
4 files changed, 262 insertions, 0 deletions
diff --git a/include/pemagine/pemagine.h b/include/pemagine/pemagine.h index 8b7e0a9..781ef59 100644 --- a/include/pemagine/pemagine.h +++ b/include/pemagine/pemagine.h @@ -256,6 +256,14 @@ pe_api int32_t pe_find_framework_loader( uint32_t flags); +pe_api int32_t pe_load_framework_loader( + void ** baseaddr, + struct pe_framework_runtime_data * rtdata, + uintptr_t * buffer, + uint32_t bufsize, + uint32_t * flags); + + pe_api int32_t pe_open_image_from_addr( void ** himage, void * addr, diff --git a/project/common.mk b/project/common.mk index 5158c04..bf0e5af 100644 --- a/project/common.mk +++ b/project/common.mk @@ -13,6 +13,7 @@ API_SRCS = \ src/ldso/pe_get_framework_runtime_data.c \ src/ldso/pe_get_peb_strings.c \ src/ldso/pe_find_framework_loader.c \ + src/ldso/pe_load_framework_loader.c \ src/ldso/pe_open_image_from_addr.c \ src/ldso/pe_open_physical_parent_directory.c \ src/meta/pe_get_image_stack_heap_info.c \ diff --git a/src/internal/pe_os.h b/src/internal/pe_os.h index a2f83b0..ba7da0e 100644 --- a/src/internal/pe_os.h +++ b/src/internal/pe_os.h @@ -11,6 +11,7 @@ #define OS_STATUS_INVALID_ADDRESS (int32_t)0xC0000141 #define OS_STATUS_CONTEXT_MISMATCH (int32_t)0xC0000719 #define OS_STATUS_COULD_NOT_INTERPRET (int32_t)0xC00000B9 +#define OS_STATUS_NOT_SUPPORTED (int32_t)0xC00000BB #define OS_STATUS_NAME_TOO_LONG (int32_t)0xC0000106 #define OS_STATUS_INTERNAL_ERROR (int32_t)0xC00000E5 #define OS_STATUS_BAD_FILE_TYPE (int32_t)0xC0000903 @@ -157,4 +158,10 @@ typedef int32_t __stdcall os_zw_open_file( __in uint32_t share_access, __in uint32_t open_options); +typedef int32_t __stdcall os_ldr_load_dll( + __in wchar16_t * image_path __optional, + __in uint32_t * image_flags __optional, + __in struct pe_unicode_str * image_name, + __out void ** image_base); + #endif diff --git a/src/ldso/pe_load_framework_loader.c b/src/ldso/pe_load_framework_loader.c new file mode 100644 index 0000000..3e3e903 --- /dev/null +++ b/src/ldso/pe_load_framework_loader.c @@ -0,0 +1,246 @@ +/*****************************************************************************/ +/* pemagination: a (virtual) tour into portable bits and executable bytes */ +/* Copyright (C) 2013--2017 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.PEMAGINE. */ +/*****************************************************************************/ + +#include <psxtypes/psxtypes.h> +#include <pemagine/pemagine.h> +#include "pe_os.h" + +static int32_t pe_get_device_dos_drive_letter( + void * hntdll, + os_zw_query_object * zw_query_object, + uintptr_t * dbuffer, + uint32_t dbufsize, + wchar16_t * devname, + size_t devnamelen, + wchar16_t * letter) +{ + int32_t status; + void * hdevice; + int sigh; + size_t idx; + size_t cap; + uint32_t len; + struct os_oa oa; + struct os_iosb iosb; + wchar16_t * src; + wchar16_t * dst; + struct pe_unicode_str path; + struct pe_unicode_str * dpath; + os_zw_open_file * zw_open_file; + os_zw_close * zw_close; + + wchar16_t namebuf[8] = { + '\\','?','?','\\', + 'X',':','\\',0}; + + unsigned char letters[26] = { + 'C','Z','Y','X','W','V', + 'E','H','F','G','D','I', + 'P','Q','R','S','T','U', + 'J','K','L','M','N','O', + 'A','B'}; + + /* init */ + if (!(zw_open_file = (os_zw_open_file *)pe_get_procedure_address( + hntdll,"ZwOpenFile"))) + return OS_STATUS_INTERNAL_ERROR; + + if (!(zw_close = (os_zw_close *)pe_get_procedure_address( + hntdll,"ZwClose"))) + return OS_STATUS_INTERNAL_ERROR; + + /* path */ + path.buffer = namebuf; + path.strlen = 7 * sizeof(wchar16_t); + path.maxlen = 0; + + /* oa */ + oa.len = sizeof(struct os_oa); + oa.root_dir = 0; + oa.obj_name = &path; + oa.obj_attr = 0; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* just a few rounds of submissiveness */ + for (sigh=0; sigh<26; sigh++) { + namebuf[4] = letters[sigh]; + + status = zw_open_file( + &hdevice, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ATTRIBUTES + | OS_FILE_READ_ACCESS, + &oa,&iosb, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + OS_FILE_DIRECTORY_FILE); + + if (status == OS_STATUS_SUCCESS) { + status = zw_query_object( + hdevice, + OS_OBJECT_NAME_INFORMATION, + dbuffer,dbufsize,&len); + + if (status == OS_STATUS_SUCCESS) { + dpath = (struct pe_unicode_str *)dbuffer; + + src = devname; + dst = dpath->buffer; + + idx = 0; + cap = devnamelen / sizeof(wchar16_t); + + for (; idx<cap && src[idx]==dst[idx]; ) + idx++; + + if (idx==cap && dst[idx]=='\\') { + zw_close(hdevice); + *letter = letters[sigh]; + + return OS_STATUS_SUCCESS; + } + } + + zw_close(hdevice); + } + } + + return OS_STATUS_NOT_SUPPORTED; +} + + +int32_t pe_load_framework_loader( + void ** baseaddr, + struct pe_framework_runtime_data * rtdata, + uintptr_t * buffer, + uint32_t bufsize, + uint32_t * flags) +{ + int32_t status; + struct pe_unicode_str path; + struct pe_unicode_str * npath; + uintptr_t addr; + uintptr_t * dbuffer; + uint32_t dbufsize; + wchar16_t * ldrdir; + wchar16_t * slash; + wchar16_t * wch; + wchar16_t * cap; + wchar16_t letter; + uint32_t len; + int mup; + void * hntdll; + os_zw_query_object * zw_query_object; + os_ldr_load_dll * ldr_load_dll; + + /* init */ + if (!(hntdll = pe_get_ntdll_module_handle())) + return OS_STATUS_INTERNAL_ERROR; + + if (!(zw_query_object = (os_zw_query_object *)pe_get_procedure_address( + hntdll,"ZwQueryObject"))) + return OS_STATUS_INTERNAL_ERROR; + + if (!(ldr_load_dll = (os_ldr_load_dll *)pe_get_procedure_address( + hntdll,"LdrLoadDll"))) + return OS_STATUS_INTERNAL_ERROR; + + /* loader native path */ + if ((status = zw_query_object( + rtdata->hloader, + OS_OBJECT_NAME_INFORMATION, + buffer,bufsize,&len))) + return status; + + /* integrity */ + if (len == sizeof(struct pe_unicode_str)) + return OS_STATUS_BAD_FILE_TYPE; + + /* first sigh */ + npath = (struct pe_unicode_str *)buffer; + + wch = npath->buffer; + cap = npath->buffer + (npath->strlen / sizeof(wchar16_t)); + + if ((cap < &wch[8]) + || (wch[0] != '\\') + || (wch[1] != 'D') + || (wch[2] != 'e') + || (wch[3] != 'v') + || (wch[4] != 'i') + || (wch[5] != 'c') + || (wch[6] != 'e') + || (wch[7] != '\\')) + return OS_STATUS_NOT_SUPPORTED; + + mup = (cap > &wch[11]) + && (wch[8]=='M') + && (wch[9]=='u') + && (wch[10]=='p') + && (wch[11]=='\\'); + + slash = mup ? &wch[12] : &wch[8]; + + for (; (*slash != '\\') && (slash < cap); ) + slash++; + + if (slash == cap) + return OS_STATUS_INTERNAL_ERROR; + + if (mup) + for (++slash; (*slash != '\\') && (slash < cap); ) + slash++; + + if (slash == cap) + return OS_STATUS_INTERNAL_ERROR; + + /* second sigh */ + addr = (uintptr_t)cap; + addr += sizeof(uintptr_t) - 1; + addr /= sizeof(uintptr_t); + addr *= sizeof(uintptr_t); + + dbuffer = (uintptr_t *)addr; + dbufsize = bufsize; + dbufsize -= (dbuffer - buffer) * sizeof(uintptr_t); + + if ((status = pe_get_device_dos_drive_letter( + hntdll, + zw_query_object, + dbuffer,dbufsize, + npath->buffer, + (slash - npath->buffer) * sizeof(wchar16_t), + &letter))) + return status; + + slash = &slash[-2]; + slash[0] = letter; + slash[1] = ':'; + + path.buffer = slash; + path.strlen = (cap - slash) * sizeof(wchar16_t); + + /* third sigh */ + for (slash=cap; (slash > path.buffer) && (*slash != '\\'); ) + slash--; + + if (slash == path.buffer) + return OS_STATUS_INTERNAL_ERROR; + + ldrdir = path.buffer; + *slash = 0; + + path.strlen -= (++slash - ldrdir) * sizeof(wchar16_t); + path.maxlen = path.strlen; + path.buffer = slash; + + /* hoppla */ + return ldr_load_dll( + ldrdir,flags, + &path,baseaddr); +} |