You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
9.5 KiB
311 lines
9.5 KiB
#include "DriverUtil.h"
|
|
|
|
namespace DriverUtil
|
|
{
|
|
// This function was created with help from wlan
|
|
//
|
|
// Links to his work:
|
|
// https://github.com/not-wlan/driver-hijack
|
|
// https://www.unknowncheats.me/forum/c-and-c-/274073-iterating-driver_objects.html
|
|
// https://www.unknowncheats.me/forum/anti-cheat-bypass/274881-memedriver-driver-object-hijack-poc.html
|
|
|
|
PDRIVER_OBJECT GetDriverObject(PUNICODE_STRING lpDriverName)
|
|
{
|
|
HANDLE handle{};
|
|
OBJECT_ATTRIBUTES attributes{};
|
|
UNICODE_STRING directory_name{};
|
|
PVOID directory{};
|
|
BOOLEAN success = FALSE;
|
|
FAST_IO_DISPATCH fastIoDispatch;
|
|
bool installedHook = false;
|
|
RtlZeroMemory(&fastIoDispatch, sizeof(FAST_IO_DISPATCH));
|
|
RtlInitUnicodeString(&directory_name, L"\\Driver");
|
|
InitializeObjectAttributes(
|
|
&attributes,
|
|
&directory_name,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
// open OBJECT_DIRECTORY for \\Driver
|
|
auto status = ZwOpenDirectoryObject(
|
|
&handle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
&attributes
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT("ZwOpenDirectoryObject Failed");
|
|
return NULL;
|
|
}
|
|
|
|
// Get OBJECT_DIRECTORY pointer from HANDLE
|
|
status = ObReferenceObjectByHandle(
|
|
handle,
|
|
DIRECTORY_ALL_ACCESS,
|
|
nullptr,
|
|
KernelMode,
|
|
&directory,
|
|
nullptr
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT("ObReferenceObjectByHandle Failed");
|
|
ZwClose(handle);
|
|
return NULL;
|
|
}
|
|
|
|
const auto directory_object = POBJECT_DIRECTORY(directory);
|
|
if (!directory_object)
|
|
return NULL;
|
|
|
|
ExAcquirePushLockExclusiveEx(&directory_object->Lock, 0);
|
|
|
|
// traverse hash table with 37 entries
|
|
// when a new object is created, the object manager computes a hash value in the range zero to 36 from the object name and creates an OBJECT_DIRECTORY_ENTRY.
|
|
// http://www.informit.com/articles/article.aspx?p=22443&seqNum=7
|
|
for (auto entry : directory_object->HashBuckets)
|
|
{
|
|
if (!entry)
|
|
continue;
|
|
|
|
while (entry && entry->Object)
|
|
{
|
|
auto driver = PDRIVER_OBJECT(entry->Object);
|
|
if (!driver)
|
|
continue;
|
|
|
|
if (wcscmp(driver->DriverExtension->ServiceKeyName.Buffer, lpDriverName->Buffer) == 0)
|
|
return driver;
|
|
}
|
|
}
|
|
|
|
ExReleasePushLockExclusiveEx(&directory_object->Lock, 0);
|
|
// Release the acquired resources back to the OS
|
|
ObDereferenceObject(directory);
|
|
ZwClose(handle);
|
|
//TODO remove
|
|
return NULL;
|
|
}
|
|
|
|
PVOID GetDriverBase(LPCSTR module_name)
|
|
{
|
|
ULONG bytes{};
|
|
NTSTATUS status = ZwQuerySystemInformation(
|
|
SystemModuleInformation,
|
|
NULL,
|
|
bytes,
|
|
&bytes
|
|
);
|
|
if (!bytes)
|
|
return NULL;
|
|
PRTL_PROCESS_MODULES modules =
|
|
(PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPool, bytes, POOLTAG);
|
|
|
|
if (modules)
|
|
{
|
|
status = ZwQuerySystemInformation(
|
|
SystemModuleInformation,
|
|
modules,
|
|
bytes,
|
|
&bytes
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
ExFreePoolWithTag(modules, POOLTAG);
|
|
return NULL;
|
|
}
|
|
|
|
PRTL_PROCESS_MODULE_INFORMATION module = modules->Modules;
|
|
PVOID module_base{}, module_size{};
|
|
for (ULONG i = 0; i < modules->NumberOfModules; i++)
|
|
{
|
|
if (strcmp(reinterpret_cast<char*>(module[i].FullPathName + module[i].OffsetToFileName), module_name) == 0)
|
|
{
|
|
module_base = module[i].ImageBase;
|
|
module_size = (PVOID)module[i].ImageSize;
|
|
break;
|
|
}
|
|
}
|
|
ExFreePoolWithTag(modules, POOLTAG);
|
|
return module_base;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PVOID GetSystemModuleExport(LPCSTR ModName, LPCSTR RoutineName)
|
|
{
|
|
PVOID result = GetDriverBase(ModName);
|
|
if (!result)
|
|
return NULL;
|
|
return RtlFindExportedRoutineByName(result, RoutineName);
|
|
}
|
|
|
|
PVOID IATHook(PVOID lpBaseAddress, CHAR* lpcStrImport, PVOID lpFuncAddress)
|
|
{
|
|
if (!lpBaseAddress || !lpcStrImport || !lpFuncAddress)
|
|
return NULL;
|
|
|
|
PIMAGE_DOS_HEADER dosHeaders =
|
|
reinterpret_cast<PIMAGE_DOS_HEADER>(lpBaseAddress);
|
|
|
|
PIMAGE_NT_HEADERS ntHeaders =
|
|
reinterpret_cast<PIMAGE_NT_HEADERS>(
|
|
reinterpret_cast<DWORD_PTR>(lpBaseAddress) + dosHeaders->e_lfanew);
|
|
|
|
IMAGE_DATA_DIRECTORY importsDirectory =
|
|
ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
|
|
PIMAGE_IMPORT_DESCRIPTOR importDescriptor =
|
|
reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(importsDirectory.VirtualAddress + (DWORD_PTR)lpBaseAddress);
|
|
|
|
LPCSTR libraryName = NULL;
|
|
PVOID result = NULL;
|
|
PIMAGE_IMPORT_BY_NAME functionName = NULL;
|
|
|
|
if (!importDescriptor)
|
|
return NULL;
|
|
|
|
while (importDescriptor->Name != NULL)
|
|
{
|
|
libraryName = (LPCSTR)importDescriptor->Name + (DWORD_PTR)lpBaseAddress;
|
|
if (GetDriverBase(libraryName))
|
|
{
|
|
PIMAGE_THUNK_DATA originalFirstThunk = NULL, firstThunk = NULL;
|
|
originalFirstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)lpBaseAddress + importDescriptor->OriginalFirstThunk);
|
|
firstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)lpBaseAddress + importDescriptor->FirstThunk);
|
|
while (originalFirstThunk->u1.AddressOfData != NULL)
|
|
{
|
|
functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)lpBaseAddress + originalFirstThunk->u1.AddressOfData);
|
|
if (strcmp(functionName->Name, lpcStrImport) == 0)
|
|
{
|
|
// save old function pointer
|
|
result = reinterpret_cast<PVOID>(firstThunk->u1.Function);
|
|
Memory::WriteProtectOff();
|
|
// swap address
|
|
firstThunk->u1.Function = reinterpret_cast<ULONG64>(lpFuncAddress);
|
|
Memory::WriteProtectOn();
|
|
return result;
|
|
}
|
|
++originalFirstThunk;
|
|
++firstThunk;
|
|
}
|
|
}
|
|
importDescriptor++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PVOID DriverIATHook(PDRIVER_OBJECT pDriverObject, CHAR* lpcStrImport, PVOID lpFuncAddress)
|
|
{
|
|
if (!pDriverObject || !lpcStrImport)
|
|
return NULL;
|
|
return IATHook(pDriverObject->DriverStart, lpcStrImport, lpFuncAddress);
|
|
}
|
|
|
|
VOID DumpDriver(PDRIVER_OBJECT lpDriverObject)
|
|
{
|
|
DumpDriver(lpDriverObject->DriverStart);
|
|
}
|
|
|
|
VOID DumpDriver(PVOID lpBaseAddress)
|
|
{
|
|
if (!lpBaseAddress || *(short*) lpBaseAddress != 0x5A4D)
|
|
return;
|
|
|
|
PIMAGE_DOS_HEADER dosHeaders =
|
|
reinterpret_cast<PIMAGE_DOS_HEADER>(lpBaseAddress);
|
|
|
|
PIMAGE_NT_HEADERS ntHeaders =
|
|
reinterpret_cast<PIMAGE_NT_HEADERS>(
|
|
reinterpret_cast<DWORD_PTR>(lpBaseAddress) + dosHeaders->e_lfanew);
|
|
|
|
HANDLE hFile;
|
|
UNICODE_STRING uniName;
|
|
OBJECT_ATTRIBUTES objAttr;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
LARGE_INTEGER offset{};
|
|
|
|
RtlInitUnicodeString(&uniName, L"\\DosDevices\\C:\\DriverDump.sys");
|
|
InitializeObjectAttributes(&objAttr, &uniName,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL, NULL
|
|
);
|
|
|
|
ZwCreateFile(&hFile,
|
|
GENERIC_WRITE,
|
|
&objAttr,
|
|
&ioStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL,
|
|
FILE_OVERWRITE_IF,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
ZwWriteFile(
|
|
hFile,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
lpBaseAddress,
|
|
ntHeaders->OptionalHeader.SizeOfImage,
|
|
&offset,
|
|
NULL
|
|
);
|
|
|
|
ZwClose(hFile);
|
|
}
|
|
|
|
void MemDump(void* BaseAddress, unsigned Size)
|
|
{
|
|
if (!BaseAddress || !Size)
|
|
return;
|
|
|
|
HANDLE h_file;
|
|
UNICODE_STRING name;
|
|
OBJECT_ATTRIBUTES attr;
|
|
IO_STATUS_BLOCK status_block;
|
|
LARGE_INTEGER offset{ NULL };
|
|
|
|
RtlInitUnicodeString(&name, L"\\DosDevices\\C:\\dump.bin");
|
|
InitializeObjectAttributes(&attr, &name,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
NULL, NULL
|
|
);
|
|
|
|
auto status = ZwCreateFile(
|
|
&h_file,
|
|
GENERIC_WRITE,
|
|
&attr,
|
|
&status_block,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL,
|
|
FILE_OVERWRITE_IF,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
status = ZwWriteFile(
|
|
h_file,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&status_block,
|
|
BaseAddress,
|
|
Size,
|
|
&offset,
|
|
NULL
|
|
);
|
|
ZwClose(h_file);
|
|
}
|
|
} |