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.
369 lines
10 KiB
369 lines
10 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);
|
|
|
|
{
|
|
//
|
|
// disable write protection
|
|
//
|
|
auto cr0 = __readcr0();
|
|
cr0 &= 0xfffffffffffeffff;
|
|
__writecr0(cr0);
|
|
_disable();
|
|
}
|
|
|
|
// swap address
|
|
first_thunk->u1.Function = reinterpret_cast<ULONG64>(func_addr);
|
|
|
|
{
|
|
//
|
|
// enable write protection
|
|
//
|
|
auto cr0 = __readcr0();
|
|
cr0 |= 0x10000;
|
|
_enable();
|
|
__writecr0(cr0);
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
} |