From 4408833cde97ac4ea180b54ed018c196d0bb9490 Mon Sep 17 00:00:00 2001 From: olari Date: Fri, 25 Oct 2019 23:04:37 +0300 Subject: [PATCH] Implement clearing of PiDDBCacheTable --- swhinjector/src/intel_driver.cpp | 176 ++++++++++++++++++++++++++++++- swhinjector/src/intel_driver.hpp | 8 ++ swhinjector/src/nt.hpp | 17 +++ swhinjector/src/utils.cpp | 30 +++++- swhinjector/src/utils.hpp | 2 + 5 files changed, 231 insertions(+), 2 deletions(-) diff --git a/swhinjector/src/intel_driver.cpp b/swhinjector/src/intel_driver.cpp index 5ee90e3..3521061 100644 --- a/swhinjector/src/intel_driver.cpp +++ b/swhinjector/src/intel_driver.cpp @@ -37,6 +37,7 @@ void intel_driver::Unload(HANDLE device_handle) std::cout << "[<] Unloading vulnerable driver" << std::endl; ClearMmUnloadedDrivers(device_handle); + ClearPiDDBCacheTable(device_handle); CloseHandle(device_handle); service::StopAndRemove(driver_name); @@ -367,4 +368,177 @@ bool intel_driver::ClearMmUnloadedDrivers(HANDLE device_handle) return false; return true; -} \ No newline at end of file +} + +bool LocatePiDDB(HANDLE device_handle, uint64_t* lock, uint64_t* table) { + auto kernel_base = utils::GetKernelModuleAddress("ntoskrnl.exe"); + if (!kernel_base) + return false; + + IMAGE_DOS_HEADER dos_header; + intel_driver::ReadMemory(device_handle, kernel_base, &dos_header, sizeof(dos_header)); + if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) + return false; + + IMAGE_NT_HEADERS nt_headers; + intel_driver::ReadMemory(device_handle, kernel_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)); + if (nt_headers.Signature != IMAGE_NT_SIGNATURE) + return false; + + std::vector ntoskrnl_file(nt_headers.OptionalHeader.SizeOfImage); + if (!intel_driver::ReadMemory(device_handle, kernel_base, ntoskrnl_file.data(), nt_headers.OptionalHeader.SizeOfImage)) + return false; + + auto lock_sig = utils::FindPatternInVector(ntoskrnl_file, "48 8D 0D ? ? ? ? E8 ? ? ? ? 48 8B 0D ? ? ? ? 33 DB"); + if (!lock_sig) + return false; + + auto table_sig = utils::FindPatternInVector(ntoskrnl_file, "48 8D 0D ? ? ? ? E8 ? ? ? ? 3D ? ? ? ? 0F 83 ? ? ? ?"); + if (!table_sig) + return false; + + int lock_rel_addr; + if (!intel_driver::ReadMemory(device_handle, kernel_base + lock_sig + 3, &lock_rel_addr, sizeof(lock_rel_addr))) + return false; + + int table_rel_addr; + if (!intel_driver::ReadMemory(device_handle, kernel_base + table_sig + 3, &table_rel_addr, sizeof(table_rel_addr))) + return false; + + auto lock_addr = lock_sig + lock_rel_addr + 7; + auto table_addr = table_sig + table_rel_addr + 7; + + *lock = kernel_base + lock_addr; + *table = kernel_base + table_addr; + + return true; +} + +bool intel_driver::ClearPiDDBCacheTable(HANDLE device_handle) { + uint64_t piddb_lock; + uint64_t piddb_cache_table; + if (!LocatePiDDB(device_handle, &piddb_lock, &piddb_cache_table)) + return false; + + // build lookup entry + nt::PiDDBCacheEntry lookup_entry{}; + RtlInitUnicodeString(&lookup_entry.DriverName, L"iqvw64e.sys"); + lookup_entry.TimeDateStamp = 0x5284EAC3; + + // lock the table for safety + if (!ExAcquireResourceExclusiveLite(device_handle, piddb_lock, TRUE)) + return false; + + auto found_entry = (nt::PiDDBCacheEntry*)RtlLookupElementGenericTableAvl(device_handle, piddb_cache_table, &lookup_entry); + if (!found_entry) { + ExReleaseResourceLite(device_handle, piddb_lock); + return false; + } + + // remove the entry from the list + if (!RemoveEntryList(device_handle, &found_entry->List)) { + ExReleaseResourceLite(device_handle, piddb_lock); + return false; + } + + // remove the entry from the table + if (!RtlDeleteElementGenericTableAvl(device_handle, piddb_cache_table, &found_entry)) { + ExReleaseResourceLite(device_handle, piddb_lock); + return false; + } + + // unlock the table + ExReleaseResourceLite(device_handle, piddb_lock); + + return true; +} + +void* intel_driver::RtlLookupElementGenericTableAvl(HANDLE device_handle, uint64_t table, void* buffer) +{ + if (!table || !buffer) + return 0; + + static uint64_t kernel_RtlLookupElementGenericTableAvl = 0; + + if (!kernel_RtlLookupElementGenericTableAvl) + kernel_RtlLookupElementGenericTableAvl = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "RtlLookupElementGenericTableAvl"); + + void* result = 0; + + if (!CallKernelFunction(device_handle, &result, kernel_RtlLookupElementGenericTableAvl, table, buffer)) + return 0; + + return result; +} + +bool intel_driver::RtlDeleteElementGenericTableAvl(HANDLE device_handle, uint64_t table, void* buffer) +{ + if (!table || !buffer) + return false; + + static uint64_t kernel_RtlDeleteElementGenericTableAvl = false; + + if (!kernel_RtlDeleteElementGenericTableAvl) + kernel_RtlDeleteElementGenericTableAvl = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "RtlDeleteElementGenericTableAvl"); + + bool result = false; + + if (!CallKernelFunction(device_handle, &result, kernel_RtlDeleteElementGenericTableAvl, table, buffer)) + return 0; + + return result; +} + +bool intel_driver::ExAcquireResourceExclusiveLite(HANDLE device_handle, uint64_t resource, BOOLEAN wait) +{ + if (!resource) + return false; + + static uint64_t kernel_ExAcquireResourceExclusiveLite = false; + + if (!kernel_ExAcquireResourceExclusiveLite) + kernel_ExAcquireResourceExclusiveLite = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExAcquireResourceExclusiveLite"); + + bool result = false; + + if (!CallKernelFunction(device_handle, &result, kernel_ExAcquireResourceExclusiveLite, resource, wait)) + return 0; + + return result; +} + +void intel_driver::ExReleaseResourceLite(HANDLE device_handle, uint64_t resource) +{ + if (!resource) + return; + + static uint64_t kernel_ExReleaseResourceLite = false; + + if (!kernel_ExReleaseResourceLite) + kernel_ExReleaseResourceLite = GetKernelModuleExport(device_handle, utils::GetKernelModuleAddress("ntoskrnl.exe"), "ExReleaseResourceLite"); + + CallKernelFunction(device_handle, nullptr, kernel_ExReleaseResourceLite, resource); +} + +bool intel_driver::RemoveEntryList(HANDLE device_handle, PLIST_ENTRY Entry) +{ + constexpr auto flink_offset = offsetof(LIST_ENTRY, Flink); + constexpr auto blink_offset = offsetof(LIST_ENTRY, Blink); + + PLIST_ENTRY flink; + PLIST_ENTRY blink; + + if (!ReadMemory(device_handle, (uint64_t)Entry + flink_offset, &flink, sizeof(flink))) + return false; + + if (!ReadMemory(device_handle, (uint64_t)Entry + blink_offset, &blink, sizeof(blink))) + return false; + + if (!WriteMemory(device_handle, (uint64_t)blink + flink_offset, &flink, sizeof(flink))) + return false; + + if (!WriteMemory(device_handle, (uint64_t)flink + blink_offset, &blink, sizeof(blink))) + return false; + + return true; +} diff --git a/swhinjector/src/intel_driver.hpp b/swhinjector/src/intel_driver.hpp index 98b593f..ff830da 100644 --- a/swhinjector/src/intel_driver.hpp +++ b/swhinjector/src/intel_driver.hpp @@ -77,6 +77,14 @@ namespace intel_driver uint64_t GetKernelModuleExport(HANDLE device_handle, uint64_t kernel_module_base, const std::string& function_name); bool GetNtGdiDdDDIReclaimAllocations2KernelInfo(HANDLE device_handle, uint64_t* out_kernel_function_ptr, uint64_t* out_kernel_original_function_address); bool ClearMmUnloadedDrivers(HANDLE device_handle); + bool ClearPiDDBCacheTable(HANDLE device_handle); + + void* RtlLookupElementGenericTableAvl(HANDLE device_handle, uint64_t table, void* buffer); + bool RtlDeleteElementGenericTableAvl(HANDLE device_handle, uint64_t table, void* buffer); + bool ExAcquireResourceExclusiveLite(HANDLE device_handle, uint64_t resource, BOOLEAN wait); + void ExReleaseResourceLite(HANDLE device_handle, uint64_t resource); + + bool RemoveEntryList(HANDLE device_handle, PLIST_ENTRY Entry); template bool CallKernelFunction(HANDLE device_handle, T* out_result, uint64_t kernel_function_address, const A ...arguments) diff --git a/swhinjector/src/nt.hpp b/swhinjector/src/nt.hpp index f6dce30..59389fe 100644 --- a/swhinjector/src/nt.hpp +++ b/swhinjector/src/nt.hpp @@ -76,4 +76,21 @@ namespace nt ULONG NumberOfModules; RTL_PROCESS_MODULE_INFORMATION Modules[1]; } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; + + typedef struct _RTL_BALANCED_LINKS + { + struct _RTL_BALANCED_LINKS* Parent; + struct _RTL_BALANCED_LINKS* LeftChild; + struct _RTL_BALANCED_LINKS* RightChild; + CHAR Balance; + UCHAR Reserved[3]; + } RTL_BALANCED_LINKS, * PRTL_BALANCED_LINKS; + + struct PiDDBCacheEntry { + LIST_ENTRY List; + UNICODE_STRING DriverName; + ULONG TimeDateStamp; + NTSTATUS LoadStatus; + char _0x0028[16]; // data from the shim engine, or uninitialized memory for custom drivers + }; } \ No newline at end of file diff --git a/swhinjector/src/utils.cpp b/swhinjector/src/utils.cpp index 0295ed8..782bf8d 100644 --- a/swhinjector/src/utils.cpp +++ b/swhinjector/src/utils.cpp @@ -65,4 +65,32 @@ uint64_t utils::GetKernelModuleAddress(const std::string& module_name) VirtualFree(buffer, 0, MEM_RELEASE); return 0; -} \ No newline at end of file +} + +uint64_t utils::FindPatternInVector(const std::vector& vector, const std::string& pattern) { + using sig_byte = std::pair; + std::vector sig; + + for (auto i = 0; i < pattern.length() - 1; i += 2) { + if (pattern[i] == '?') { + sig.emplace_back(std::make_pair('\x00', true)); + } + else { + sig.emplace_back(std::make_pair((uint8_t)std::stoi(pattern.substr(i, 2), nullptr, 16), false)); + i++; + } + } + + auto offset = std::search( + vector.begin(), + vector.end(), + sig.begin(), sig.end(), + [](uint8_t current_byte, sig_byte current_sig_byte) { + // if wildcard or matching + return current_sig_byte.second || (current_byte == current_sig_byte.first); + }); + + std::vector result(offset, offset + sig.size()); + + return offset == vector.end() ? 0 : std::distance(vector.begin(), offset); +} diff --git a/swhinjector/src/utils.hpp b/swhinjector/src/utils.hpp index fc022df..ab32862 100644 --- a/swhinjector/src/utils.hpp +++ b/swhinjector/src/utils.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "nt.hpp" @@ -14,4 +15,5 @@ namespace utils bool ReadFileToMemory(const std::string& file_path, std::vector* out_buffer); bool CreateFileFromMemory(const std::string& desired_file_path, const char* address, size_t size); uint64_t GetKernelModuleAddress(const std::string& module_name); + uint64_t FindPatternInVector(const std::vector& vector, const std::string& pattern); } \ No newline at end of file