driver dumper for manually mapped drivers mapped with kdmapper.
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.
 
 

375 lines
11 KiB

#include "driver_util.h"
namespace driver_util
{
void* get_driver_base(const char* module_name)
{
ULONG bytes{};
NTSTATUS status = ZwQuerySystemInformation(
SystemModuleInformation,
NULL,
bytes,
&bytes
);
if (!bytes)
return NULL;
PRTL_PROCESS_MODULES modules =
(PRTL_PROCESS_MODULES)ExAllocatePool(NonPagedPool, bytes);
if (modules)
{
status = ZwQuerySystemInformation(
SystemModuleInformation,
modules,
bytes,
&bytes
);
if (!NT_SUCCESS(status))
{
ExFreePool(modules);
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;
}
}
ExFreePool(modules);
return module_base;
}
return NULL;
}
void* get_kmode_export(const char* mod_name, const char* proc_name)
{
if (!mod_name || !proc_name)
return NULL;
void* result = get_driver_base(mod_name);
if (!result)
return NULL;
return RtlFindExportedRoutineByName(result, proc_name);
}
PIMAGE_FILE_HEADER get_file_header(void* base_addr)
{
if (!base_addr || *(short*)base_addr != 0x5A4D)
return NULL;
PIMAGE_DOS_HEADER dos_headers =
reinterpret_cast<PIMAGE_DOS_HEADER>(base_addr);
PIMAGE_NT_HEADERS nt_headers =
reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<DWORD_PTR>(base_addr) + dos_headers->e_lfanew);
return &nt_headers->FileHeader;
}
void* iat_hook(void* base_addr, const char* import, void* func_addr)
{
if (!base_addr || *(short*)base_addr != 0x5A4D || !import || !func_addr)
return NULL;
PIMAGE_DOS_HEADER dos_headers =
reinterpret_cast<PIMAGE_DOS_HEADER>(base_addr);
PIMAGE_NT_HEADERS nt_headers =
reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<DWORD_PTR>(base_addr) + dos_headers->e_lfanew);
IMAGE_DATA_DIRECTORY import_dir =
nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
PIMAGE_IMPORT_DESCRIPTOR import_des =
reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(import_dir.VirtualAddress + (DWORD_PTR)base_addr);
LPCSTR lib_name = NULL;
PVOID result = NULL;
PIMAGE_IMPORT_BY_NAME func_name = NULL;
if (!import_des)
return NULL;
while (import_des->Name != NULL)
{
lib_name = (LPCSTR)import_des->Name + (DWORD_PTR)base_addr;
if (get_driver_base(lib_name))
{
PIMAGE_THUNK_DATA org_first_thunk = NULL, first_thunk = NULL;
org_first_thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)base_addr + import_des->OriginalFirstThunk);
first_thunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)base_addr + import_des->FirstThunk);
while (org_first_thunk->u1.AddressOfData != NULL)
{
func_name = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)base_addr + org_first_thunk->u1.AddressOfData);
if (strcmp(func_name->Name, import) == 0)
{
// save old function pointer
result = reinterpret_cast<PVOID>(first_thunk->u1.Function);
//
// although disabling wp bit can cause crashes, im disabling it for nano seconds. only to write 8 bytes...
// in reality this is 1 mov instruction.
//
{
//
// disable write protection
//
_disable();
auto cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
}
// swap address
first_thunk->u1.Function = reinterpret_cast<ULONG64>(func_addr);
{
//
// enable write protection
//
auto cr0 = __readcr0();
cr0 |= 0x10000;
__writecr0(cr0);
_enable();
}
return result;
}
++org_first_thunk;
++first_thunk;
}
}
++import_des;
}
return NULL;
}
PDRIVER_OBJECT get_drv_obj(PUNICODE_STRING driver_name)
{
HANDLE handle{};
OBJECT_ATTRIBUTES attributes{};
UNICODE_STRING directory_name{};
PVOID directory{};
BOOLEAN success = FALSE;
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, driver_name->Buffer) == 0)
return driver;
entry = entry->ChainLink;
}
}
ExReleasePushLockExclusiveEx(&directory_object->Lock, 0);
// Release the acquired resources back to the OS
ObDereferenceObject(directory);
ZwClose(handle);
//TODO remove
return NULL;
}
void copy_driver(PUNICODE_STRING image_path)
{
HANDLE h_file;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK status_block;
LARGE_INTEGER offset;
UNICODE_STRING name;
FILE_STANDARD_INFORMATION standard_info;
RtlZeroMemory(&standard_info, sizeof(standard_info));
InitializeObjectAttributes(
&attr,
image_path,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL, NULL
);
NTSTATUS status = ZwCreateFile(
&h_file,
GENERIC_READ,
&attr,
&status_block,
NULL,
FILE_ATTRIBUTE_NORMAL,
NULL,
FILE_OPEN_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
NULL
);
ZwQueryInformationFile(
h_file,
&status_block,
&standard_info,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation
);
void* drv_buffer = ExAllocatePool(
NonPagedPool,
standard_info.AllocationSize.QuadPart
);
status = ZwReadFile(
h_file,
NULL,
NULL,
NULL,
&status_block,
drv_buffer,
standard_info.AllocationSize.QuadPart,
&offset,
NULL
);
RtlInitUnicodeString(&name, L"\\DosDevices\\C:\\last_load_drv.sys");
InitializeObjectAttributes(&attr, &name,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL, NULL
);
ZwCreateFile(
&h_file,
GENERIC_WRITE,
&attr,
&status_block,
NULL,
FILE_ATTRIBUTE_NORMAL,
NULL,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
NULL
);
ZwWriteFile(
h_file,
NULL,
NULL,
NULL,
&status_block,
drv_buffer,
standard_info.AllocationSize.QuadPart,
&offset,
NULL
);
ZwClose(h_file);
ExFreePool(drv_buffer);
}
void mem_dump(void* base_addr, unsigned len)
{
if (!base_addr || !len)
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,
base_addr,
len,
&offset,
NULL
);
ZwClose(h_file);
}
}