From dd89bb8ad4fe184a34b5dbdda237e640fc82121b Mon Sep 17 00:00:00 2001 From: midipix Date: Mon, 27 Jul 2015 04:01:18 -0400 Subject: entered advanced internal development stage. --- .../ntapi_tt_get_csr_port_handle_addr_by_logic.c | 197 ++++++++++++++++ src/system/ntapi_tt_get_system_directory.c | 257 +++++++++++++++++++++ src/system/ntapi_tt_get_system_info_snapshot.c | 89 +++++++ 3 files changed, 543 insertions(+) create mode 100644 src/system/ntapi_tt_get_csr_port_handle_addr_by_logic.c create mode 100644 src/system/ntapi_tt_get_system_directory.c create mode 100644 src/system/ntapi_tt_get_system_info_snapshot.c (limited to 'src/system') diff --git a/src/system/ntapi_tt_get_csr_port_handle_addr_by_logic.c b/src/system/ntapi_tt_get_csr_port_handle_addr_by_logic.c new file mode 100644 index 0000000..3f38067 --- /dev/null +++ b/src/system/ntapi_tt_get_csr_port_handle_addr_by_logic.c @@ -0,0 +1,197 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include "ntapi_impl.h" + +/************************************************************/ +/* beginning with version 6.0, explicit thread registration */ +/* with csrss is no longer required. the code below should */ +/* work with all known versions of NT, however it will only */ +/* be used when run on the now-obsolete versions of the OS. */ +/************************************************************/ + +/** + Nebbett was pretty much right in his interpretation of + the csrss port message; and as long as one changes + uint32_t to uintptr_t (especially when it comes to the + unknown parameters), then the structures behave as + expected according to his book. + + SysInternals: ProcessExplorer: csrss.exe: the stack shows + a thread in csrsrv.dll that has CsrUnhandledExceptionFilter + as its start address, and ntdll!NtReplyWaitReceivePort as + its next function call. This suggests that csrss still + uses LPC (at least to some extent) for communication with + user processes. + + Given the above, we may deduce that CsrClientCallServer + contains a call to ZwRequestWaitReplyPort. Assuming + the machine code in ntdll is as optimized as possible, + we may then conclude that on x86 machines, this would be + an E8 call using relative 32-bit addressing on both NT32 + and NT64. + + On the 32-bit variant of the operating system, the first + argument is passed on the stack, and is normally expressed + in terms of an offset from the ds register. + + On the 64-bit variant of the operating system, the first + argument is passed in the rcx register. Here, again, + machine code optimization suggests that the address of + CsrPortHandle will be provided as a 32-bit relative address, + or else the code will be larger by several bytes. + + The rest is based on simple logic and straight-forward + heuristics. Since we know the addresses of CsrClientCallSertver + and ZwRequestWaitReplyPort, we first find the call to the latter + function within the former. Once we have found that call, we + start going back to look for the argument-passing + opcode, and finally do the math to obtain the address of + CsrPortHandle. +**/ + + +#if defined(__X86_MODEL) +void ** __cdecl __ntapi_tt_get_csr_port_handle_addr_by_logic_i386(void) +{ + #define MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL 0x20 + #define MAX_FN_BYTES_TO_TEST 0x800 + + typedef struct __attr_aligned__ (1) __attr_packed__ __x86_e8_call_signature { + unsigned char __opcode_current_e8; + unsigned char __addr_relative[4]; + unsigned char __opcode_next_any; + } _x86_e8_call_signature; + + typedef struct __attr_aligned__ (1) __attr_packed__ __x86_push_ds_signature { + unsigned char __push; + unsigned char __ds; + unsigned char __push_ds_arg; + } _x86_push_ds_signature; + + unsigned char * ptr_test; + _x86_e8_call_signature * ptr_e8_call; + _x86_push_ds_signature * ptr_push_ds; + int32_t offset; + + /* type-punned tyrants */ + int32_t * prelative; + int32_t relative; + uintptr_t * pport_addr; + + + /* calling a function within the same library: assume E8 call */ + for (offset = 0; offset < MAX_FN_BYTES_TO_TEST; offset++) { + ptr_test = (unsigned char *)__ntapi->csr_client_call_server + + offset; + + if (*ptr_test == 0xE8) { + ptr_e8_call = (_x86_e8_call_signature *)ptr_test; + + /* make our type-punned tyrant compiler happy */ + prelative = (int32_t *)&(ptr_e8_call->__addr_relative); + relative = *prelative; + + /* are we calling ZwRequestWaitReplyPort? */ + if ((uintptr_t)(__ntapi->zw_request_wait_reply_port) == + (uintptr_t)&(ptr_e8_call->__opcode_next_any) + + relative) { + /* assume ds relative address for arg1, go back to find it */ + for (offset = 0; offset < MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL; offset++) { + ptr_push_ds = (_x86_push_ds_signature *)((uintptr_t)ptr_e8_call - offset); + + if ((ptr_push_ds->__push == 0xFF) && + (ptr_push_ds->__ds == 0x35)) { + /* bingo */ + /* make our type-punned tyrant compiler happy */ + pport_addr = (uintptr_t *)&(ptr_push_ds->__push_ds_arg); + + /* all done */ + return *(void ***)pport_addr; + } + } + } + } + } + + /* CsrPortHandle not found */ + return (void **)0; +} +#endif + + +#if defined(__X86_64_MODEL) +void ** __ntapi_tt_get_csr_port_handle_addr_by_logic_x86_64(void) +{ + #define MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL 0x20 + #define MAX_FN_BYTES_TO_TEST 0x800 + + typedef struct __attr_aligned__ (1) __attr_packed__ __x86_e8_call_signature { + unsigned char __opcode_current_e8; + unsigned char __addr_relative[4]; + unsigned char __opcode_next_any; + } _x86_e8_call_signature; + + typedef struct __attr_aligned__ (1) __attr_packed__ __x86_move_rcx_rel_signature { + unsigned char __move; + unsigned char __rcx; + unsigned char __relative; + unsigned char __arg_32_relative[4]; + unsigned char __opcode_next_any; + } _x86_move_rcx_rel_signature; + + unsigned char * ptr_test; + _x86_e8_call_signature * ptr_e8_call; + _x86_move_rcx_rel_signature * ptr_move_rcx_rel; + int32_t offset; + int32_t relative; + int32_t * prelative; /* for type-punned tyrants */ + + + /* calling a function within the same library: assume E8 call and 32-bit relative addressing */ + for (offset = 0; offset < MAX_FN_BYTES_TO_TEST; offset++) { + ptr_test = (unsigned char *)__ntapi->csr_client_call_server + + offset; + + if (*ptr_test == 0xE8) { + ptr_e8_call = (_x86_e8_call_signature *)ptr_test; + + /* please our type-punned tyrant compiler */ + prelative = (int32_t *)&(ptr_e8_call->__addr_relative); + relative = *prelative; + + /* are we calling ZwRequestWaitReplyPort? */ + /* comparing, not writing; ignore type-punned msgs. */ + if ((uintptr_t)(__ntapi->zw_request_wait_reply_port) == + (uintptr_t)&(ptr_e8_call->__opcode_next_any) + + relative) { + /* arg1 must be passed in rcx, so go back to find it */ + for (offset = 0; offset < MAX_BYTES_BETWEEN_ARG1_PUSH_AND_E8_CALL; offset++) { + ptr_move_rcx_rel = (_x86_move_rcx_rel_signature *)((uintptr_t)ptr_e8_call - offset); + + if ((ptr_move_rcx_rel->__move == 0x48) && + (ptr_move_rcx_rel->__rcx == 0x8b) && + (ptr_move_rcx_rel->__relative == 0x0d)) + /* bingo */ + /* make our type-punned tyrant compiler happy */ + prelative = (int32_t *)&(ptr_move_rcx_rel->__arg_32_relative); + relative = *prelative; + + /* all done */ + return (void **)( + (uintptr_t)&ptr_move_rcx_rel->__opcode_next_any + + relative); + } + } + } + } + + /* CsrPortHandle not found */ + return (void **)0; +} +#endif diff --git a/src/system/ntapi_tt_get_system_directory.c b/src/system/ntapi_tt_get_system_directory.c new file mode 100644 index 0000000..28b9745 --- /dev/null +++ b/src/system/ntapi_tt_get_system_directory.c @@ -0,0 +1,257 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include +#include +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_get_system_directory_native_path( + __out nt_mem_sec_name * buffer, + __in uint32_t buffer_size, + __in wchar16_t * base_name, + __in uint32_t base_name_size, + __out nt_unicode_string * nt_path __optional) +{ + int32_t status; + wchar16_t * wch_src; + wchar16_t * wch_dst; + wchar16_t * wch_cap; + size_t maxlen_saved; + size_t info_size; + + /* validation */ + if (!buffer || !buffer_size) + return NT_STATUS_BUFFER_TOO_SMALL; + else if (base_name && !base_name_size) + return NT_STATUS_INVALID_PARAMETER_MIX; + + /* init buffer */ + buffer->section_name.strlen = 0; + buffer->section_name.maxlen = (uint16_t)(buffer_size - sizeof(nt_unicode_string)); + buffer->section_name.buffer = buffer->section_name_buffer; + + maxlen_saved = buffer->section_name.maxlen; + info_size = 0; + + status = __ntapi->zw_query_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + pe_get_ntdll_module_handle(), + NT_MEMORY_SECTION_NAME, + buffer, + buffer_size, + &info_size); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* find directory portion */ + wch_dst = buffer->section_name.buffer + (buffer->section_name.strlen / sizeof(wchar16_t)); + wch_dst--; + + while ((*wch_dst != '\\') && (wch_dst > buffer->section_name.buffer)) + wch_dst--; + + if (wch_dst == buffer->section_name.buffer) + return NT_STATUS_INTERNAL_ERROR; + + /* base_name */ + if (base_name) { + wch_dst++; + wch_src = base_name; + wch_cap = (wchar16_t *)((uintptr_t)wch_dst + base_name_size); + + if ((uintptr_t)wch_cap - (uintptr_t)(buffer->section_name.buffer) > maxlen_saved) + return NT_STATUS_BUFFER_TOO_SMALL; + + while (wch_dst < wch_cap) { + *wch_dst = *wch_src; + wch_dst++; + wch_src++; + } + } + + /* null termination */ + *wch_dst = 0; + + /* nt_path */ + if (nt_path) + __ntapi->rtl_init_unicode_string( + nt_path, + buffer->section_name.buffer); + + return NT_STATUS_SUCCESS; +} + + +int32_t __stdcall __ntapi_tt_get_system_directory_handle( + __out void ** hsysdir, + __out nt_mem_sec_name * buffer __optional, + __in uint32_t buffer_size __optional) +{ + int32_t status; + nt_oa oa; + nt_iosb iosb; + nt_unicode_string path; + char _buffer[256]; + + /* validation */ + if (!hsysdir) + return NT_STATUS_INVALID_PARAMETER_1; + else if (buffer_size && buffer_size < 0x20) + return NT_STATUS_BUFFER_TOO_SMALL; + + /* buffer */ + if (!buffer) { + buffer = (nt_mem_sec_name *)_buffer; + buffer_size = sizeof(_buffer); + __ntapi->tt_aligned_block_memset(buffer,0,sizeof(buffer)); + } + + /* sysdir path */ + status = __ntapi_tt_get_system_directory_native_path( + buffer, + buffer_size, + (wchar16_t *)0, + 0, + &path); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* oa */ + oa.len = sizeof(nt_oa); + oa.root_dir = (void *)0; + oa.obj_name = &path; + oa.obj_attr = 0; + oa.sec_desc = 0; + oa.sec_qos = 0; + + /* open file/folder */ + status = __ntapi->zw_open_file( + hsysdir, + NT_SEC_SYNCHRONIZE | NT_FILE_READ_ATTRIBUTES | NT_FILE_READ_ACCESS, + &oa, + &iosb, + NT_FILE_SHARE_READ | NT_FILE_SHARE_WRITE, + NT_FILE_DIRECTORY_FILE | NT_FILE_SYNCHRONOUS_IO_ALERT); + + return status; +} + + +int32_t __stdcall __ntapi_tt_get_system_directory_dos_path( + __in void * hsysdir __optional, + __out wchar16_t * buffer, + __in uint32_t buffer_size, + __in wchar16_t * base_name, + __in uint32_t base_name_size, + __out nt_unicode_string * nt_path __optional) +{ + int32_t status; + nt_statfs statfs; + wchar16_t * wch; + wchar16_t * wch_src; + wchar16_t * wch_cap; + nt_iosb iosb; + nt_fni * fni; + uint32_t fni_length; + + /* validation */ + if (!buffer) + return NT_STATUS_INVALID_PARAMETER_2; + + /* hsysdir */ + if (!hsysdir) { + status = __ntapi_tt_get_system_directory_handle( + &hsysdir, + (nt_mem_sec_name *)buffer, + buffer_size); + + if (status != NT_STATUS_SUCCESS) + return status; + } + + /* statfs */ + status = __ntapi->tt_statfs( + hsysdir, + (void *)0, + (nt_unicode_string *)0, + &statfs, + (uintptr_t *)buffer, + buffer_size, + NT_STATFS_DOS_DRIVE_LETTER); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* dos path name (always shorter than the native path, so buffer_size must be ok) */ + wch = buffer; + *wch = '\\'; wch++; + *wch = '?'; wch++; + *wch = '?'; wch++; + *wch = '\\'; wch++; + *wch = statfs.nt_drive_letter; wch++; + *wch = ':'; wch++; + + /* alignment */ + fni = (nt_fni *)((uintptr_t)buffer + 0x10); + + status = __ntapi->zw_query_information_file( + hsysdir, + &iosb, + fni, + buffer_size - 8 * sizeof(wchar16_t), + NT_FILE_NAME_INFORMATION); + + if (status != NT_STATUS_SUCCESS) + return status; + + /* fni->file_name_length: save */ + fni_length = fni->file_name_length; + + /* overwrite */ + wch_src = fni->file_name; + wch_cap = (wchar16_t *)((uintptr_t)wch_src + fni_length); + + while (wch_src < wch_cap) { + *wch = *wch_src; + wch++; + wch_src++; + } + + /* ultimate path separator */ + *wch = '\\'; wch++; + + /* base_name */ + if (base_name) { + wch_src = base_name; + wch_cap = (wchar16_t *)((uintptr_t)wch + base_name_size); + + if ((uintptr_t)wch_cap - (uintptr_t)buffer - sizeof(wchar16_t) > buffer_size) + return NT_STATUS_BUFFER_TOO_SMALL; + + while (wch < wch_cap) { + *wch = *wch_src; + wch++; + wch_src++; + } + } + + /* null termination */ + *wch = 0; + + /* nt_path */ + if (nt_path) + __ntapi->rtl_init_unicode_string( + nt_path, + buffer); + + return NT_STATUS_SUCCESS; +} diff --git a/src/system/ntapi_tt_get_system_info_snapshot.c b/src/system/ntapi_tt_get_system_info_snapshot.c new file mode 100644 index 0000000..bfe2978 --- /dev/null +++ b/src/system/ntapi_tt_get_system_info_snapshot.c @@ -0,0 +1,89 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include +#include +#include +#include +#include +#include "ntapi_impl.h" + +int32_t __stdcall __ntapi_tt_get_system_info_snapshot( + __in_out nt_system_information_snapshot * sys_info_snapshot) +{ + int32_t status; + + /* pre-allocated buffer? */ + if (sys_info_snapshot->buffer) + status = __ntapi->zw_query_system_information( + sys_info_snapshot->sys_info_class, + sys_info_snapshot->buffer, + sys_info_snapshot->max_len, + &sys_info_snapshot->info_len); + else { + /* set initial buffer size */ + sys_info_snapshot->max_len = NT_ALLOCATION_GRANULARITY; + + /* allocate initial buffer */ + status = __ntapi->zw_allocate_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + (void **)&sys_info_snapshot->buffer, + 0, + &sys_info_snapshot->max_len, + NT_MEM_COMMIT, + NT_PAGE_READWRITE); + + /* verification */ + if (status != NT_STATUS_SUCCESS) + return status; + + /* loop until buffer is large enough to satisfy the system */ + while ((status = __ntapi->zw_query_system_information( + sys_info_snapshot->sys_info_class, + sys_info_snapshot->buffer, + sys_info_snapshot->max_len, + &sys_info_snapshot->info_len)) + == NT_STATUS_INFO_LENGTH_MISMATCH) { + + /* free previously allocated memory */ + status = __ntapi->zw_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + (void **)&sys_info_snapshot->buffer, + &sys_info_snapshot->max_len, + NT_MEM_RELEASE); + + /* verification */ + if (status != NT_STATUS_SUCCESS) + return status; + + /* reset buffer and increase buffer size */ + sys_info_snapshot->buffer = (nt_system_information_buffer *)0; + sys_info_snapshot->max_len += NT_ALLOCATION_GRANULARITY; + + /* reallocate buffer memory */ + status = __ntapi->zw_allocate_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + (void **)&sys_info_snapshot->buffer, + 0, + &sys_info_snapshot->max_len, + NT_MEM_COMMIT, + NT_PAGE_READWRITE); + + /* verification */ + if (status != NT_STATUS_SUCCESS) + return status; + } + } + + /* verification */ + if (status == NT_STATUS_SUCCESS) { + sys_info_snapshot->pcurrent = &sys_info_snapshot->buffer->mark; + return NT_STATUS_SUCCESS; + } else { + sys_info_snapshot->pcurrent = (void *)0; + return status; + } +} -- cgit v1.2.3