summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/internal/pe_os.h67
-rw-r--r--src/ldso/pe_open_physical_parent_directory.c105
2 files changed, 172 insertions, 0 deletions
diff --git a/src/internal/pe_os.h b/src/internal/pe_os.h
new file mode 100644
index 0000000..f68a462
--- /dev/null
+++ b/src/internal/pe_os.h
@@ -0,0 +1,67 @@
+#ifndef PE_OS_H
+#define PE_OS_H
+
+#include <pemagine/pe_structs.h>
+
+#define OS_STATUS_INTERNAL_ERROR 0xC00000E5
+#define OS_STATUS_BAD_FILE_TYPE 0xC0000903
+#define OS_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000034
+#define OS_STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
+
+#define OS_SEC_SYNCHRONIZE 0x00100000
+#define OS_FILE_READ_ACCESS 0x00000001
+#define OS_FILE_READ_ATTRIBUTES 0x00000080
+
+#define OS_FILE_DIRECTORY_FILE 0x00000001
+#define OS_FILE_NON_DIRECTORY_FILE 0x00000040
+
+#define OS_FILE_SHARE_READ 0x00000001
+#define OS_FILE_SHARE_WRITE 0x00000002
+#define OS_FILE_SHARE_DELETE 0x00000004
+
+
+enum os_object_info_class {
+ OS_OBJECT_BASIC_INFORMATION = 0,
+ OS_OBJECT_NAME_INFORMATION = 1,
+ OS_OBJECT_TYPE_INFORMATION = 2,
+ OS_OBJECT_ALL_TYPES_INFORMATION = 3,
+ OS_OBJECT_HANDLE_INFORMATION = 4
+};
+
+
+struct os_oa {
+ uint32_t len;
+ void * root_dir;
+ struct pe_unicode_str * obj_name;
+ uint32_t obj_attr;
+ void * sec_desc;
+ void * sec_qos;
+};
+
+
+struct os_iosb {
+ union {
+ int32_t status;
+ void * pointer;
+ };
+ intptr_t info;
+};
+
+
+typedef int32_t __stdcall os_zw_query_object(
+ __in void * handle,
+ __in int obj_info_class,
+ __out void * obj_info,
+ __in size_t obj_info_length,
+ __out uint32_t * returned_length __optional);
+
+
+typedef int32_t __stdcall os_zw_open_file(
+ __out void ** hfile,
+ __in uint32_t desired_access,
+ __in struct os_oa * obj_attr,
+ __out struct os_iosb * io_status_block,
+ __in uint32_t share_access,
+ __in uint32_t open_options);
+
+#endif
diff --git a/src/ldso/pe_open_physical_parent_directory.c b/src/ldso/pe_open_physical_parent_directory.c
new file mode 100644
index 0000000..7166df5
--- /dev/null
+++ b/src/ldso/pe_open_physical_parent_directory.c
@@ -0,0 +1,105 @@
+/*****************************************************************************/
+/* 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 <pemagine/pe_structs.h>
+#include "pe_os.h"
+
+int32_t pe_open_physical_parent_directory(
+ __out void ** hparent,
+ __in void * href,
+ __out uintptr_t * buffer,
+ __in uint32_t buffer_size,
+ __in uint32_t desired_access,
+ __in uint32_t open_options)
+{
+ int32_t status;
+ struct os_oa oa;
+ struct os_iosb iosb;
+ wchar16_t * wch;
+ wchar16_t * root;
+ struct pe_unicode_str * path;
+ uint32_t len;
+ void * hntdll;
+ os_zw_query_object * zw_query_object;
+ os_zw_open_file * zw_open_file;
+
+
+ /* init */
+ path = (struct pe_unicode_str *)buffer;
+
+ 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 (!(zw_open_file = (os_zw_open_file *)pe_get_procedure_address(
+ hntdll,"ZwOpenFile")))
+ return OS_STATUS_INTERNAL_ERROR;
+
+ /* native path of base directory */
+ if ((status = zw_query_object(
+ href,
+ OS_OBJECT_NAME_INFORMATION,
+ path,
+ buffer_size,
+ &len)))
+ return status;
+
+ /* integrity */
+ if (len == sizeof(struct pe_unicode_str))
+ return OS_STATUS_BAD_FILE_TYPE;
+
+ /* device root directory */
+ root = path->buffer;
+ wch = path->buffer + (path->strlen / sizeof(uint16_t));
+
+
+ if ((root[0] != '\\')
+ || (root[1] != 'D') || (root[2] != 'e')
+ || (root[3] != 'v') || (root[4] != 'i')
+ || (root[5] != 'c') || (root[6] != 'e')
+ || (root[7] != '\\'))
+ return OS_STATUS_INTERNAL_ERROR;
+
+ for (root=&root[8]; (root<wch) && (*root!='\\'); )
+ root++;
+
+ if ((uint16_t)((++root - path->buffer) * sizeof(uint16_t)) == path->strlen)
+ return OS_STATUS_MORE_PROCESSING_REQUIRED;
+
+ /* physical parent directory path */
+ for (; (wch>root) && (wch[-1]!='\\'); )
+ wch--;
+
+ path->strlen = sizeof(uint16_t) * (uint16_t)(wch-path->buffer);
+ 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;
+
+ /* default access */
+ desired_access = desired_access
+ ? desired_access
+ : OS_SEC_SYNCHRONIZE | OS_FILE_READ_ATTRIBUTES | OS_FILE_READ_ACCESS;
+
+ /* open parent directory */
+ return zw_open_file(
+ hparent,
+ desired_access,
+ &oa,
+ &iosb,
+ OS_FILE_SHARE_READ | OS_FILE_SHARE_WRITE,
+ open_options | OS_FILE_DIRECTORY_FILE);
+}