diff options
-rw-r--r-- | include/pemagine/pemagine.h | 18 | ||||
-rw-r--r-- | project/common.mk | 1 | ||||
-rw-r--r-- | src/internal/pe_os.h | 10 | ||||
-rw-r--r-- | src/ldso/pe_find_framework_loader.c | 271 |
4 files changed, 300 insertions, 0 deletions
diff --git a/include/pemagine/pemagine.h b/include/pemagine/pemagine.h index 61ffb7a..8b7e0a9 100644 --- a/include/pemagine/pemagine.h +++ b/include/pemagine/pemagine.h @@ -19,6 +19,12 @@ enum pe_callback_reason { }; +/* ldso flags */ +#define PE_LDSO_INTEGRAL_ONLY 0x00000000 +#define PE_LDSO_DEFAULT_EXECUTABLE 0x00000001 +#define PE_LDSO_STANDALONE_EXECUTABLE 0x00000002 + + /* library specific structures */ struct pe_export_sym { uint32_t * ordinal_base; @@ -137,6 +143,8 @@ struct pe_framework_runtime_data { void * hparent; void * himage; void * hroot; + void * hdsodir; + void * hloader; void * hcwd; void * hdrive; struct pe_guid abi; @@ -238,6 +246,16 @@ pe_api int32_t pe_get_framework_runtime_data( const wchar16_t * cmdline, const struct pe_guid * abi); +pe_api int32_t pe_find_framework_loader( + struct pe_framework_runtime_data * rtdata, + const wchar16_t * basename, + const wchar16_t * rrelname, + void * refaddr, + 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 40bfe21..5158c04 100644 --- a/project/common.mk +++ b/project/common.mk @@ -12,6 +12,7 @@ API_SRCS = \ src/imports/pe_enum_image_import_hdrs.c \ 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_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 d0dc903..ad26de4 100644 --- a/src/internal/pe_os.h +++ b/src/internal/pe_os.h @@ -9,11 +9,17 @@ #define OS_STATUS_NO_MATCH 0xC0000272 #define OS_STATUS_INVALID_ADDRESS 0xC0000141 #define OS_STATUS_CONTEXT_MISMATCH 0xC0000719 +#define OS_STATUS_COULD_NOT_INTERPRET 0xC00000B9 +#define OS_STATUS_NAME_TOO_LONG 0xC0000106 #define OS_STATUS_INTERNAL_ERROR 0xC00000E5 #define OS_STATUS_BAD_FILE_TYPE 0xC0000903 #define OS_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034 +#define OS_STATUS_OBJECT_PATH_NOT_FOUND 0xC000003A #define OS_STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 +#define OS_OBJ_INHERIT 0x00000002 +#define OS_OBJ_CASE_INSENSITIVE 0x00000040 + #define OS_SEC_SYNCHRONIZE 0x00100000 #define OS_FILE_READ_ACCESS 0x00000001 #define OS_FILE_READ_ATTRIBUTES 0x00000080 @@ -113,6 +119,10 @@ struct os_peb { }; +typedef int32_t __stdcall os_zw_close( + __in void * handle); + + typedef int32_t __stdcall os_zw_query_object( __in void * handle, __in int obj_info_class, diff --git a/src/ldso/pe_find_framework_loader.c b/src/ldso/pe_find_framework_loader.c new file mode 100644 index 0000000..df18655 --- /dev/null +++ b/src/ldso/pe_find_framework_loader.c @@ -0,0 +1,271 @@ +/*****************************************************************************/ +/* 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" + +int32_t pe_find_framework_loader( + struct pe_framework_runtime_data * rtdata, + const wchar16_t * basename, + const wchar16_t * rrelname, + void * refaddr, + uintptr_t * buffer, + uint32_t bufsize, + uint32_t flags) +{ + int32_t status; + struct pe_unicode_str path; + struct os_oa oa; + struct os_iosb iosb; + void * himage; + void * himgdir; + void * hdsodir; + void * hloader; + void * hparent; + void * hprevious; + const wchar16_t * wch; + const wchar16_t * wch_cap; + void * hntdll; + os_zw_close * zw_close; + os_zw_open_file * zw_open_file; + + /* init */ + if (!(hntdll = pe_get_ntdll_module_handle())) + return OS_STATUS_INTERNAL_ERROR; + + if (!(zw_close = (os_zw_close *)pe_get_procedure_address( + hntdll,"ZwClose"))) + return OS_STATUS_INTERNAL_ERROR; + + if (!(zw_open_file = (os_zw_open_file *)pe_get_procedure_address( + hntdll,"ZwOpenFile"))) + return OS_STATUS_INTERNAL_ERROR; + + /* flags */ + if (flags == PE_LDSO_INTEGRAL_ONLY) + (void)0; + else if (flags == PE_LDSO_DEFAULT_EXECUTABLE) + (void)0; + else if (flags == PE_LDSO_STANDALONE_EXECUTABLE) + (void)0; + else + return OS_STATUS_INVALID_PARAMETER; + + /* oa */ + oa.len = sizeof(struct os_oa); + oa.root_dir = 0; + oa.obj_name = &path; + oa.obj_attr = OS_OBJ_CASE_INSENSITIVE; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* standalone executable? */ + if (flags == PE_LDSO_STANDALONE_EXECUTABLE) { + wch = basename; + wch_cap = basename + 512; + + for (; *wch && wch<wch_cap; wch++) + if ((*wch == '\\') != (*wch == '/')) + return OS_STATUS_INVALID_PARAMETER; + + if (*wch) + return OS_STATUS_NAME_TOO_LONG; + + path.buffer = (wchar16_t *)basename; + path.strlen = sizeof(wchar16_t) * (wch - basename); + path.maxlen = 0; + + if ((status = pe_open_image_from_addr( + &himage,refaddr, + buffer,bufsize, + 0, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + 0))) + return status; + + if ((status = pe_open_physical_parent_directory( + &hdsodir,himage, + buffer,bufsize, + 0, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + 0))) + return status; + + oa.root_dir = hdsodir; + + if ((status = zw_open_file( + &hloader, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + &oa,&iosb, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + OS_FILE_NON_DIRECTORY_FILE))) + return status; + + rtdata->hdsodir = hdsodir; + rtdata->hloader = hloader; + rtdata->himage = himage; + + return OS_STATUS_SUCCESS; + } + + /* root-relative loader path */ + wch = rrelname; + wch_cap = rrelname + 512; + + for (; *wch && wch<wch_cap; ) + wch++; + + if (*wch) + return OS_STATUS_NAME_TOO_LONG; + + path.buffer = (wchar16_t *)rrelname; + path.strlen = sizeof(wchar16_t) * (wch - rrelname); + path.maxlen = 0; + + /* inherited root directory? */ + if (rtdata->hroot) { + oa.root_dir = rtdata->hroot; + + if ((status = zw_open_file( + &hloader, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + &oa,&iosb, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + OS_FILE_NON_DIRECTORY_FILE))) + return status; + + rtdata->hdsodir = 0; + rtdata->hloader = hloader; + rtdata->himage = himage; + + return OS_STATUS_SUCCESS; + } + + /* integral only and no inherited root directory? */ + if (flags == PE_LDSO_INTEGRAL_ONLY) + return OS_STATUS_COULD_NOT_INTERPRET; + + /* finde Pluto / find Waldo */ + if ((status = pe_open_image_from_addr( + &himage,refaddr, + buffer,bufsize, + 0, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + 0))) + return status; + + if ((status = pe_open_physical_parent_directory( + &himgdir,himage, + buffer,bufsize, + 0, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + 0))) + return status; + + if ((status = pe_open_physical_parent_directory( + &hparent,himgdir, + buffer,bufsize, + OS_OBJ_INHERIT, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + 0))) + return status; + + zw_close(himgdir); + + hloader = 0; + oa.root_dir = hparent; + + status = zw_open_file( + &hloader, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + &oa,&iosb, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + OS_FILE_NON_DIRECTORY_FILE); + + while (!hloader) { + if (status == (int32_t)OS_STATUS_OBJECT_NAME_NOT_FOUND) + (void)0; + else if (status == (int32_t)OS_STATUS_OBJECT_PATH_NOT_FOUND) + (void)0; + else + return status; + + hprevious = hparent; + + if ((status = pe_open_physical_parent_directory( + &hparent,hprevious, + buffer,bufsize, + OS_OBJ_INHERIT, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + 0))) + return status; + + oa.root_dir = hparent; + + status = zw_open_file( + &hloader, + OS_SEC_SYNCHRONIZE + | OS_FILE_READ_ACCESS + | OS_FILE_READ_ATTRIBUTES, + &oa,&iosb, + OS_FILE_SHARE_READ + | OS_FILE_SHARE_WRITE + | OS_FILE_SHARE_DELETE, + OS_FILE_NON_DIRECTORY_FILE); + + zw_close(hprevious); + } + + rtdata->hdsodir = 0; + rtdata->hloader = hloader; + rtdata->himage = himage; + rtdata->hroot = hparent; + + return OS_STATUS_SUCCESS; +} |