#include "stdafx.h"
/**
* Offsets for some undocummented structures
*/
ULONG m_KTHREAD_PrevMode = 0;
/**
* System services numbers
*/
//extern "C"
//{
ULONG m_SDT_NtDeviceIoControlFile = 0;
ULONG m_SDT_NtProtectVirtualMemory = 0;
#ifdef _AMD64_
// need for system services calling on x64 kernels
PVOID _KiServiceInternal = 0;
#endif
extern POBJECT_TYPE *IoDeviceObjectType;
extern POBJECT_TYPE *IoFileObjectType;
//}
// defined in handlers.cpp
extern NT_DEVICE_IO_CONTROL_FILE old_NtDeviceIoControlFile;
#ifdef _AMD64_
// stuff for function code patching
ULONG NtDeviceIoControlFile_BytesPatched = 0;
NT_DEVICE_IO_CONTROL_FILE f_NtDeviceIoControlFile = NULL;
#endif
RTL_OSVERSIONINFOW m_VersionInformation;
PDEVICE_OBJECT m_DeviceObject = NULL;
UNICODE_STRING m_usDosDeviceName, m_usDeviceName;
UNICODE_STRING m_RegistryPath;
PCOMMON_LST m_ProcessesList = NULL;
KMUTEX m_CommonMutex;
BOOLEAN m_bHooksInitialized = FALSE;
/**
* Fuzzing settings
* defined in handlers.cpp
*/
extern FUZZING_TYPE m_FuzzingType;
extern ULONG m_FuzzOptions;
extern HANDLE m_FuzzThreadId;
extern PEPROCESS m_FuzzProcess;
extern PUSER_MODE_DATA m_UserModeData;
PSERVICE_DESCRIPTOR_TABLE m_KeServiceDescriptorTable = NULL;
#define SYSTEM_SERVICE(_p_) m_KeServiceDescriptorTable->Entry[0].ServiceTableBase[_p_]
// defined in log.cpp
extern HANDLE m_hIoctlsLogFile;
extern UNICODE_STRING m_usIoctlsLogFilePath;
//extern "C" PUSHORT NtBuildNumber;
//extern "C" NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
//--------------------------------------------------------------------------------------
ULONG GetPrevModeOffset(void)
{
ULONG Ret = 0;
PVOID KernelBase = KernelGetModuleBase("ntoskrnl.exe");
if (KernelBase)
{
// get address of nt!ExGetPreviousMode()
ULONG Func_RVA = KernelGetExportAddress(KernelBase, "ExGetPreviousMode");
if (Func_RVA > 0)
{
PUCHAR Func = (PUCHAR)RVATOVA(KernelBase, Func_RVA);
#ifdef _X86_
/*
nt!ExGetPreviousMode:
8052b334 64a124010000 mov eax,dword ptr fs:[00000124h]
8052b33a 8a8040010000 mov al,byte ptr [eax+140h]
8052b340 c3 ret
*/
// check for mov instruction
if (*(PUSHORT)(Func + 6) == 0x808a)
{
// get offset value from second operand
Ret = *(PULONG)(Func + 8);
}
#elif _AMD64_
/*
nt!ExGetPreviousMode:
fffff800`02691d50 65488b042588010000 mov rax,qword ptr gs:[188h]
fffff800`02691d59 8a80f6010000 mov al,byte ptr [rax+1F6h]
fffff800`02691d5f c3 ret
*/
// check for mov instruction
if (*(PUSHORT)(Func + 9) == 0x808a)
{
// get offset value from second operand
Ret = *(PULONG)(Func + 11);
}
#endif
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Symbol nt!KeServiceDescriptorTable is not found\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate kernel base\n");
}
if (Ret)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): KTHREAD::PreviousMode offset is 0x%.4x\n", Ret);
}
return Ret;
}
//--------------------------------------------------------------------------------------
PVOID GetKeSDT(void)
{
PVOID Ret = NULL;
#ifdef _X86_
PVOID KernelBase = KernelGetModuleBase("ntoskrnl.exe");
if (KernelBase)
{
ULONG KeSDT_RVA = KernelGetExportAddress(KernelBase, "KeServiceDescriptorTable");
if (KeSDT_RVA > 0)
{
Ret = RVATOVA(KernelBase, KeSDT_RVA);
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Symbol nt!KeServiceDescriptorTable is not found\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate kernel base\n");
}
#elif _AMD64_
#define MAX_INST_LEN 24
PVOID KernelBase = KernelGetModuleBase("ntoskrnl.exe");
if (KernelBase)
{
ULONG Func_RVA = KernelGetExportAddress(KernelBase, "KeAddSystemServiceTable");
if (Func_RVA > 0)
{
UCHAR ud_mode = 64;
ULONG i = 0;
// initialize disassembler engine
ud_t ud_obj;
ud_init(&ud_obj);
// set mode, syntax and vendor
ud_set_mode(&ud_obj, ud_mode);
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
ud_set_vendor(&ud_obj, UD_VENDOR_INTEL);
for (i = 0; i < 0x40;)
{
ULONG InstLen = 0;
PUCHAR Inst = (PUCHAR)RVATOVA(KernelBase, Func_RVA + i);
if (!MmIsAddressValid(Inst))
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Invalid memory at "IFMT"\n", Inst);
break;
}
ud_set_input_buffer(&ud_obj, Inst, MAX_INST_LEN);
// get length of the instruction
InstLen = ud_disassemble(&ud_obj);
if (InstLen == 0)
{
// error while disassembling instruction
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't disassemble instruction at "IFMT"\n", Inst);
break;
}
/*
Check for the following code
nt!KeAddSystemServiceTable:
fffff800`012471c0 448b542428 mov r10d,dword ptr [rsp+28h]
fffff800`012471c5 4183fa01 cmp r10d,1
fffff800`012471c9 0f871ab70c00 ja nt!KeAddSystemServiceTable+0x78
fffff800`012471cf 498bc2 mov rax,r10
fffff800`012471d2 4c8d1d278edbff lea r11,0xfffff800`01000000
fffff800`012471d9 48c1e005 shl rax,5
fffff800`012471dd 4a83bc1880bb170000 cmp qword ptr [rax+r11+17BB80h],0
fffff800`012471e6 0f85fdb60c00 jne nt!KeAddSystemServiceTable+0x78
*/
if ((*(PULONG)Inst & 0x00ffffff) == 0x1d8d4c &&
(*(PUSHORT)(Inst + 0x0b) == 0x834b || *(PUSHORT)(Inst + 0x0b) == 0x834a))
{
// clculate nt!KeServiceDescriptorTableAddress
LARGE_INTEGER Addr;
Addr.QuadPart = (ULONGLONG)Inst + InstLen;
Addr.LowPart += *(PULONG)(Inst + 0x03) + *(PULONG)(Inst + 0x0f);
Ret = (PVOID)Addr.QuadPart;
break;
}
i += InstLen;
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Symbol nt!KeServiceDescriptorTable is not found\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate kernel base\n");
}
#endif
if (Ret)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): nt!KeServiceDescriptorTable is at "IFMT"\n", Ret);
}
return Ret;
}
//--------------------------------------------------------------------------------------
ULONG LoadSyscallNumber(char *lpszName)
{
ULONG Ret = -1;
UNICODE_STRING usName;
ANSI_STRING asName;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
RtlInitAnsiString(&asName, lpszName);
ns = RtlAnsiStringToUnicodeString(&usName, &asName, TRUE);
if (NT_SUCCESS(ns))
{
HANDLE hKey = NULL;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// open service key
ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);
if (NT_SUCCESS(ns))
{
PVOID Val = NULL;
ULONG ValSize = 0;
WCHAR wcValueName[0x100];
swprintf(wcValueName, L"%wZ", &usName);
if (RegQueryValueKey(hKey, wcValueName, REG_DWORD, &Val, &ValSize))
{
if (ValSize == sizeof(ULONG))
{
Ret = *(PULONG)Val;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: Invalid size for '%ws' value\n", wcValueName);
}
M_FREE(Val);
}
if (Ret == -1)
{
Ret = GetSyscallNumber(lpszName);
if (Ret != -1)
{
RegSetValueKey(hKey, wcValueName, REG_DWORD, (PVOID)&Ret, sizeof(ULONG));
}
}
ZwClose(hKey);
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns);
}
RtlFreeUnicodeString(&usName);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns);
}
return Ret;
}
//--------------------------------------------------------------------------------------
BOOLEAN InitSdtNumbers(void)
{
PVOID KernelBase = NULL;
m_SDT_NtDeviceIoControlFile = LoadSyscallNumber("NtDeviceIoControlFile");
m_SDT_NtProtectVirtualMemory = LoadSyscallNumber("NtProtectVirtualMemory");
DbgMsg(__FILE__, __LINE__, "SDT number of NtDeviceIoControlFile: 0x%.8x\n", m_SDT_NtDeviceIoControlFile);
DbgMsg(__FILE__, __LINE__, "SDT number of NtProtectVirtualMemory: 0x%.8x\n", m_SDT_NtProtectVirtualMemory);
#ifdef _AMD64_
// get nt!KiServiceInternal address
KernelBase = KernelGetModuleBase("ntoskrnl.exe");
if (KernelBase)
{
// get address of nt!ZwCreateFile()
ULONG FuncOffset = KernelGetExportAddress(KernelBase, "ZwCreateFile");
if (FuncOffset > 0)
{
PUCHAR FuncAddr = (PUCHAR)RVATOVA(KernelBase, FuncOffset);
/*
nt!ZwCreateFile:
fffff800`0169c800 488bc4 mov rax,rsp
fffff800`0169c803 fa cli
fffff800`0169c804 4883ec10 sub rsp,10h
fffff800`0169c808 50 push rax
fffff800`0169c809 9c pushfq
fffff800`0169c80a 6a10 push 10h
fffff800`0169c80c 488d052d4b0000 lea rax,[nt!KiServiceLinkage (fffff800`016a1340)]
fffff800`0169c813 50 push rax
fffff800`0169c814 b852000000 mov eax,52h
fffff800`0169c819 e962430000 jmp nt!KiServiceInternal (fffff800`016a0b80)
*/
PUCHAR JmpAddr = FuncAddr + 25;
if (*JmpAddr == 0xE9)
{
_KiServiceInternal = (PVOID)((PCHAR)JmpAddr + *(PLONG)(JmpAddr + 1) + 5);
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): nt!KiServiceInternal is at "IFMT"\n", _KiServiceInternal);
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't find nt!KiServiceInternal\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't get address of nt!ZwCreateFile\n");
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't get kernel base address\n");
}
#endif // _AMD64_
if (m_SDT_NtDeviceIoControlFile > 0 && m_SDT_NtProtectVirtualMemory > 0)
{
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetSyscallNumber() fails for one or more function\n");
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOLEAN SetUpHooks(void)
{
if (m_bHooksInitialized)
{
// hooks is allready initialized
return TRUE;
}
// lookup for SDT indexes
if (!InitSdtNumbers())
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: InitSdtNumbers() fails\n");
return FALSE;
}
if (m_KeServiceDescriptorTable = (PSERVICE_DESCRIPTOR_TABLE)GetKeSDT())
{
PULONG KiST = NULL;
LARGE_INTEGER Addr;
// disable memory write protection
ForEachProcessor(ClearWp, NULL);
#ifdef _X86_
// set up hook
old_NtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE)InterlockedExchange(
(PLONG)&SYSTEM_SERVICE(m_SDT_NtDeviceIoControlFile),
(LONG)new_NtDeviceIoControlFile
);
// DbgMsg(
// __FILE__, __LINE__,
// "Hooking nt!NtDeviceIoControlFile(): "IFMT" -> "IFMT"\n",
// old_NtDeviceIoControlFile, new_NtDeviceIoControlFile
// );
#elif _AMD64_
KiST = (PULONG)m_KeServiceDescriptorTable->Entry[0].ServiceTableBase;
/*
Calculate address of nt!NtDeviceIoControlFile() by offset
from the begining of nt!KiServiceTable.
Low 15 bits stores number of in-memory arguments.
*/
Addr.QuadPart = (LONGLONG)KiST;
if (m_VersionInformation.dwMajorVersion >= 6)
{
// Vista and newer
ULONG Val = *(KiST + m_SDT_NtDeviceIoControlFile);
Val -= *(KiST + m_SDT_NtDeviceIoControlFile) & 15;
Addr.LowPart += Val >> 4;
}
else
{
// Server 2003
Addr.LowPart += *(KiST + m_SDT_NtDeviceIoControlFile);
Addr.LowPart -= *(KiST + m_SDT_NtDeviceIoControlFile) & 15;
}
f_NtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE)Addr.QuadPart;
DbgMsg(
__FILE__, __LINE__,
__FUNCTION__"(): nt!NtDeviceIoControlFile() is at "IFMT"\n",
Addr.QuadPart
);
// DbgMsg(
// __FILE__, __LINE__,
// "Hooking nt!NtDeviceIoControlFile(): "IFMT" -> "IFMT"\n",
// f_NtDeviceIoControlFile, new_NtDeviceIoControlFile
// );
old_NtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE)Hook(
f_NtDeviceIoControlFile,
new_NtDeviceIoControlFile,
&NtDeviceIoControlFile_BytesPatched
);
#endif
// enable memory write protection
ForEachProcessor(SetWp, NULL);
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetKeSDT() fails\n");
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOLEAN RemoveHooks(void)
{
if (m_SDT_NtDeviceIoControlFile == 0)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: m_SDT_NtDeviceIoControlFile is not initialized\n");
return FALSE;
}
if (m_KeServiceDescriptorTable == NULL)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: m_KeServiceDescriptorTable is not initialized\n");
return FALSE;
}
if (old_NtDeviceIoControlFile)
{
ForEachProcessor(ClearWp, NULL);
#ifdef _X86_
// restore changed address in nt!KiServiceTable
InterlockedExchange(
(PLONG)&SYSTEM_SERVICE(m_SDT_NtDeviceIoControlFile),
(LONG)old_NtDeviceIoControlFile
);
#elif _AMD64_
// restore patched function code
memcpy(f_NtDeviceIoControlFile, old_NtDeviceIoControlFile, NtDeviceIoControlFile_BytesPatched);
#endif
ForEachProcessor(SetWp, NULL);
}
m_bHooksInitialized = FALSE;
return TRUE;
}
//--------------------------------------------------------------------------------------
void SetPreviousMode(KPROCESSOR_MODE Mode)
{
PRKTHREAD CurrentThread = KeGetCurrentThread();
*((PUCHAR)CurrentThread + m_KTHREAD_PrevMode) = (UCHAR)Mode;
}
//--------------------------------------------------------------------------------------
BOOLEAN SaveFuzzerOptions(void)
{
HANDLE hKey = NULL;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// open service key
ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);
if (NT_SUCCESS(ns))
{
UNICODE_STRING usAllowRules, usDenyRules;
RtlInitUnicodeString(&usAllowRules, L"_allow_rules");
RtlInitUnicodeString(&usDenyRules, L"_deny_rules");
// save allow rules
SaveAllowRules(hKey, &usAllowRules);
// save deny rules
SaveDenyRules(hKey, &usDenyRules);
// save options
RegSetValueKey(hKey, L"_options", REG_DWORD, (PVOID)&m_FuzzOptions, sizeof(ULONG));
// save fuzzing type
RegSetValueKey(hKey, L"_fuzzing_type", REG_DWORD, (PVOID)&m_FuzzingType, sizeof(ULONG));
ZwClose(hKey);
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns);
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOLEAN DeleteSavedFuzzerOptions(void)
{
HANDLE hKey = NULL;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// open service key
ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);
if (NT_SUCCESS(ns))
{
UNICODE_STRING usAllowRules, usDenyRules, usOptions, usFuzzingType;
RtlInitUnicodeString(&usAllowRules, L"_allow_rules");
RtlInitUnicodeString(&usDenyRules, L"_deny_rules");
RtlInitUnicodeString(&usOptions, L"_options");
RtlInitUnicodeString(&usFuzzingType, L"_fuzzing_type");
// remove saved options
ZwDeleteValueKey(hKey, &usAllowRules);
ZwDeleteValueKey(hKey, &usDenyRules);
ZwDeleteValueKey(hKey, &usOptions);
ZwDeleteValueKey(hKey, &usFuzzingType);
ZwClose(hKey);
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns);
}
return FALSE;
}
//--------------------------------------------------------------------------------------
BOOLEAN LoadFuzzerOptions(void)
{
HANDLE hKey = NULL;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES ObjAttr;
InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
// open service key
ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);
if (NT_SUCCESS(ns))
{
PVOID Val = NULL;
ULONG ValSize = 0;
BOOLEAN bBootFuzzingEnabled = FALSE;
UNICODE_STRING usAllowRules, usDenyRules;
RtlInitUnicodeString(&usAllowRules, L"_allow_rules");
RtlInitUnicodeString(&usDenyRules, L"_deny_rules");
// try to load options
if (RegQueryValueKey(hKey, L"_options", REG_DWORD, &Val, &ValSize))
{
if (ValSize == sizeof(ULONG))
{
m_FuzzOptions = *(PULONG)Val;
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): m_FuzzOptions has been set to 0x%.8x\n", m_FuzzOptions);
if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT)
{
bBootFuzzingEnabled = TRUE;
}
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: Invalid size for '_options' value\n");
}
M_FREE(Val);
}
if (bBootFuzzingEnabled)
{
if (RegQueryValueKey(hKey, L"_fuzzing_type", REG_DWORD, &Val, &ValSize))
{
if (ValSize == sizeof(ULONG))
{
m_FuzzingType = *(PULONG)Val;
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): m_FuzzingType has been set to 0x%.8x\n", m_FuzzingType);
}
else
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: Invalid size for '_fuzzing_type' value\n");
}
M_FREE(Val);
}
// load allow rules
LoadAllowRules(hKey, &usAllowRules);
// load deny rules
LoadDenyRules(hKey, &usDenyRules);
}
ZwClose(hKey);
return TRUE;
}
else
{
DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns);
}
return FALSE;
}
//--------------------------------------------------------------------------------------
PFILE_OBJECT GetDeviceObjectPointer(PUNICODE_STRING usDeviceName)
{
PFILE_OBJECT pObject = NULL;
HANDLE hDevice = NULL;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK StatusBlock;
InitializeObjectAttributes(&ObjAttr, usDeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL);
ns = ZwOpenFile(
&hDevice,
FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
&ObjAttr,
&StatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT
);
if (NT_SUCCESS(ns))
{
ns = ObReferenceObjectByHandle(hDevice, 0, *IoFileObjectType, KernelMode, (PVOID *)&pObject, NULL);
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns);
}
ZwClose(hDevice);
}
else
{
DbgMsg(
__FILE__, __LINE__, "Error while opening \"%wZ\"; status: 0x%.8x\n",
usDeviceName, ns
);
}
return pObject;
}
//--------------------------------------------------------------------------------------
NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION stack;
NTSTATUS ns = STATUS_SUCCESS;
Irp->IoStatus.Status = ns;
Irp->IoStatus.Information = 0;
stack = IoGetCurrentIrpStackLocation(Irp);
if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
{
ULONG Code = stack->Parameters.DeviceIoControl.IoControlCode;
ULONG Size = stack->Parameters.DeviceIoControl.InputBufferLength;
PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)Irp->AssociatedIrp.SystemBuffer;
#ifdef DBG_IO
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_DEVICE_CONTROL 0x%.8x\n", Code);
#endif
Irp->IoStatus.Information = Size;
switch (Code)
{
case IOCTL_DRV_CONTROL:
{
Buff->Status = S_ERROR;
if (Size >= sizeof(REQUEST_BUFFER))
{
ULONG KdCommandLength = 0;
IOCTL_FILTER Flt;
RtlZeroMemory(&Flt, sizeof(Flt));
if (Buff->AddObject.bDbgcbAction && Size > sizeof(REQUEST_BUFFER))
{
// check for zero byte at the end of the string
if (Buff->Buff[Size - sizeof(REQUEST_BUFFER) - 1] != 0)
{
goto _bad_addobj_request;
}
// debugger command available
KdCommandLength = strlen(Buff->Buff) + 1;
}
switch (Buff->Code)
{
case C_ADD_DRIVER:
case C_ADD_DEVICE:
case C_ADD_PROCESS:
case C_ADD_IOCTL:
{
// check for zero byte at the end of the string
if (Buff->AddObject.szObjectName[MAX_REQUEST_STRING - 1] != 0)
{
goto _bad_addobj_request;
}
if (Buff->Code == C_ADD_IOCTL)
{
Flt.IoctlCode = Buff->AddObject.IoctlCode;
}
else
{
ANSI_STRING asName;
RtlInitAnsiString(
&asName,
Buff->AddObject.szObjectName
);
ns = RtlAnsiStringToUnicodeString(&Flt.usName, &asName, TRUE);
if (!NT_SUCCESS(ns))
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns);
goto _bad_addobj_request;
}
}
switch (Buff->Code)
{
case C_ADD_DRIVER:
// filter by driver file name/path
Flt.Type = FLT_DRIVER_NAME;
break;
case C_ADD_DEVICE:
// filter by device name
Flt.Type = FLT_DEVICE_NAME;
break;
case C_ADD_PROCESS:
// filter by caller process executable file name/path
Flt.Type = FLT_PROCESS_PATH;
break;
case C_ADD_IOCTL:
// filter by IOCTL control code value
Flt.Type = FLT_IOCTL_CODE;
break;
}
KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL);
__try
{
PIOCTL_FILTER f_entry = NULL;
if (Buff->AddObject.bAllow)
{
// add filter rule into the ALLOW list
if (f_entry = FltAddAllowRule(&Flt, KdCommandLength))
{
Buff->Status = S_SUCCESS;
}
}
else
{
// add filter rule into the DENY list
if (f_entry = FltAddDenyRule(&Flt, KdCommandLength))
{
Buff->Status = S_SUCCESS;
}
}
if (f_entry)
{
f_entry->bDbgcbAction = Buff->AddObject.bDbgcbAction;
if (KdCommandLength > 0)
{
strcpy(f_entry->szKdCommand, Buff->Buff);
if (Buff->Code == C_ADD_IOCTL)
{
DbgPrint(
"" __FUNCTION__ "(): ControlCode=0x%.8x KdCommand=%s\n",
f_entry->IoctlCode, f_entry->szKdCommand, f_entry->szKdCommand
);
}
else
{
DbgPrint(
"" __FUNCTION__ "(): Object=\"%wZ\" KdCommand=%s\n",
&f_entry->usName, f_entry->szKdCommand, f_entry->szKdCommand
);
}
// 减少引用计数
DeferenceRuleCount(f_entry);
}
}
}
__finally
{
KeReleaseMutex(&m_CommonMutex, FALSE);
}
if (Buff->Status != S_SUCCESS &&
Buff->Code != C_ADD_IOCTL)
{
RtlFreeUnicodeString(&Flt.usName);
}
_bad_addobj_request:
break;
}
case C_DEL_OPTIONS:
{
DeleteSavedFuzzerOptions();
break;
}
case C_SET_OPTIONS:
{
PLARGE_INTEGER FuzzThreadId = NULL;
KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL);
__try
{
m_FuzzOptions = Buff->Options.Options;
if (!(m_FuzzOptions & FUZZ_OPT_NO_SDT_HOOKS))
{
// hook nt!NtDeviceIoControlFile() syscall
m_bHooksInitialized = SetUpHooks();
}
if (!(m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_GLOBAL) && m_hIoctlsLogFile)
{
ZwClose(m_hIoctlsLogFile);
m_hIoctlsLogFile = NULL;
DbgMsg(__FILE__, __LINE__, "[+] IOCTLs log closed \"%wZ\"\n", &m_usIoctlsLogFilePath);
}
m_FuzzingType = Buff->Options.FuzzingType;
m_UserModeData = Buff->Options.UserModeData;
#ifdef _X86_
m_FuzzThreadId = (HANDLE)Buff->Options.FuzzThreadId;
#elif _AMD64_
FuzzThreadId = (PLARGE_INTEGER)&m_FuzzThreadId;
FuzzThreadId->HighPart = 0;
FuzzThreadId->LowPart = Buff->Options.FuzzThreadId;
#endif
if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT)
{
// boot fuzzing mode has been enabled
SaveFuzzerOptions();
m_FuzzOptions = 0;
}
else
{
DeleteSavedFuzzerOptions();
}
Buff->Status = S_SUCCESS;
}
__finally
{
KeReleaseMutex(&m_CommonMutex, FALSE);
}
break;
}
case C_GET_DEVICE_INFO:
{
// check for zero byte at the end of the string
if (Size > sizeof(REQUEST_BUFFER) &&
Buff->Buff[Size - sizeof(REQUEST_BUFFER) - 1] == 0)
{
ANSI_STRING asDeviceName;
UNICODE_STRING usDeviceName;
RtlInitAnsiString(
&asDeviceName,
Buff->Buff
);
ns = RtlAnsiStringToUnicodeString(&usDeviceName, &asDeviceName, TRUE);
if (NT_SUCCESS(ns))
{
// open disk device object
PDEVICE_OBJECT TargetDeviceObject = NULL;
PFILE_OBJECT TargetFileObject = NULL;
#ifdef USE_IoGetDeviceObjectPointer
ns = IoGetDeviceObjectPointer(
&usDeviceName,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&TargetFileObject,
&TargetDeviceObject
);
if (NT_SUCCESS(ns))
#else
if (TargetFileObject = GetDeviceObjectPointer(&usDeviceName))
{
TargetDeviceObject = TargetFileObject->DeviceObject;
}
if (TargetFileObject)
#endif
{
// pass device object information to the caller
Buff->DeviceInfo.DeviceObjectAddr = TargetDeviceObject;
if (TargetDeviceObject->DriverObject)
{
PLDR_DATA_TABLE_ENTRY pModuleEntry = NULL;
POBJECT_NAME_INFORMATION NameInfo = NULL;
Buff->DeviceInfo.DriverObjectAddr = TargetDeviceObject->DriverObject;
// get driver object name by pointer
NameInfo = GetObjectName(TargetDeviceObject->DriverObject);
if (NameInfo)
{
ANSI_STRING asDriverName;
ns = RtlUnicodeStringToAnsiString(&asDriverName, &NameInfo->Name, TRUE);
if (NT_SUCCESS(ns))
{
strncpy(
Buff->DeviceInfo.szDriverObjectName,
asDriverName.Buffer,
min(MAX_REQUEST_STRING - 1, asDriverName.Length)
);
RtlFreeAnsiString(&asDriverName);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns);
}
ExFreePool(NameInfo);
}
// get loader information entry for the driver
pModuleEntry = (PLDR_DATA_TABLE_ENTRY)
TargetDeviceObject->DriverObject->DriverSection;
if (pModuleEntry &&
MmIsAddressValid(pModuleEntry) &&
ValidateUnicodeString(&pModuleEntry->FullDllName))
{
ANSI_STRING asDllName;
ns = RtlUnicodeStringToAnsiString(&asDllName, &pModuleEntry->FullDllName, TRUE);
if (NT_SUCCESS(ns))
{
strncpy(
Buff->DeviceInfo.szDriverFilePath,
asDllName.Buffer,
min(MAX_REQUEST_STRING - 1, asDllName.Length)
);
RtlFreeAnsiString(&asDllName);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns);
}
}
Buff->Status = S_SUCCESS;
}
ObDereferenceObject(TargetFileObject);
}
#ifdef USE_IoGetDeviceObjectPointer
else
{
DbgMsg(
__FILE__, __LINE__,
"IoGetDeviceObjectPointer() fails for \"%wZ\", status: 0x%.8x\n",
&usDeviceName, ns
);
}
#endif
RtlFreeUnicodeString(&usDeviceName);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns);
}
}
break;
}
case C_GET_OBJECT_NAME:
{
PFILE_OBJECT pFileObject = NULL;
ns = ObReferenceObjectByHandle(
Buff->ObjectName.hObject,
0,
*IoFileObjectType,
KernelMode,
(PVOID *)&pFileObject,
NULL
);
if (NT_SUCCESS(ns))
{
if (pFileObject->DeviceObject)
{
// get name of the object
POBJECT_NAME_INFORMATION NameInfo = GetObjectName(pFileObject->DeviceObject);
if (NameInfo)
{
ANSI_STRING asName;
ns = RtlUnicodeStringToAnsiString(&asName, &NameInfo->Name, TRUE);
if (NT_SUCCESS(ns))
{
strncpy(
Buff->ObjectName.szObjectName,
asName.Buffer,
min(MAX_REQUEST_STRING - 1, asName.Length)
);
Buff->Status = S_SUCCESS;
RtlFreeAnsiString(&asName);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns);
}
M_FREE(NameInfo);
}
}
ObDereferenceObject(pFileObject);
}
else
{
DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns);
}
break;
}
case C_CHECK_HOOKS:
{
if (m_bHooksInitialized)
{
Buff->CheckHooks.bHooksInstalled = TRUE;
}
else
{
Buff->CheckHooks.bHooksInstalled = FALSE;
}
break;
}
}
}
break;
}
default:
{
ns = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
break;
}
}
}
else if (stack->MajorFunction == IRP_MJ_CREATE)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CREATE\n");
#ifdef DBGPIPE
DbgOpenPipe();
#endif
KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL);
__try
{
// delete all filter rules
FltFlushAllList();
m_FuzzProcess = PsGetCurrentProcess();
ObReferenceObject(m_FuzzProcess);
}
__finally
{
KeReleaseMutex(&m_CommonMutex, FALSE);
}
}
else if (stack->MajorFunction == IRP_MJ_CLOSE)
{
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CLOSE\n");
KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL);
__try
{
// delete all filter rules
FltFlushAllList();
m_FuzzOptions = 0;
if (m_FuzzProcess)
{
ObDereferenceObject(m_FuzzProcess);
m_FuzzProcess = NULL;
}
}
__finally
{
KeReleaseMutex(&m_CommonMutex, FALSE);
}
#ifdef DBGPIPE
DbgClosePipe();
#endif
if (m_hIoctlsLogFile)
{
ZwClose(m_hIoctlsLogFile);
m_hIoctlsLogFile = NULL;
DbgMsg(__FILE__, __LINE__, "[+] IOCTLs log closed \"%wZ\"\n", &m_usIoctlsLogFilePath);
}
}
if (ns != STATUS_PENDING)
{
Irp->IoStatus.Status = ns;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return ns;
}
//--------------------------------------------------------------------------------------
void DriverUnload(PDRIVER_OBJECT DriverObject)
{
LARGE_INTEGER Timeout = { 0 };
DbgMsg(__FILE__, __LINE__, "DriverUnload()\n");
PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, TRUE);
// delete device
IoDeleteSymbolicLink(&m_usDosDeviceName);
IoDeleteDevice(m_DeviceObject);
KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL);
// unhook NtDeviceIoControlFile() system service
RemoveHooks();
WaitHookRemoveComplete();
__try
{
// delete all filter rules
FltUnInitRuleList();
}
__finally
{
KeReleaseMutex(&m_CommonMutex, FALSE);
}
FreeProcessInfo();
LstFree(m_ProcessesList);
Timeout.QuadPart = RELATIVE(SECONDS(1));
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
}
//--------------------------------------------------------------------------------------
NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
LARGE_INTEGER TickCount;
NTSTATUS ns = STATUS_UNSUCCESSFUL;
//DbgInit();
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): '%wZ' "IFMT"\n", RegistryPath, KernelGetModuleBase("ioctlfuzzer.exe"));
DriverObject->DriverUnload = DriverUnload;
RtlGetVersion(&m_VersionInformation);
ns = FltInitRuleList();
if(!NT_SUCCESS(ns))
return ns;
// initialize random number generator
KeQueryTickCount(&TickCount);
init_genrand(TickCount.LowPart);
// Get offset of KTHREAD::PreviousMode field
m_KTHREAD_PrevMode = GetPrevModeOffset();
if (m_KTHREAD_PrevMode == 0)
{
DbgMsg(__FILE__, __LINE__, "Error while obtaining KTHREAD::PreviousMode offset\n");
return STATUS_UNSUCCESSFUL;
}
m_ProcessesList = LstInit();
if (m_ProcessesList == NULL)
{
return STATUS_UNSUCCESSFUL;
}
if (AllocUnicodeString(&m_RegistryPath, RegistryPath->MaximumLength))
{
RtlCopyUnicodeString(&m_RegistryPath, RegistryPath);
}
else
{
return STATUS_UNSUCCESSFUL;
}
KeInitializeMutex(&m_CommonMutex, 0);
RtlInitUnicodeString(&m_usDeviceName, L"\\Device\\" DEVICE_NAME);
RtlInitUnicodeString(&m_usDosDeviceName, L"\\DosDevices\\" DEVICE_NAME);
// create driver communication device
ns = IoCreateDevice(
DriverObject,
0,
&m_usDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&m_DeviceObject
);
if (NT_SUCCESS(ns))
{
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch;
ns = IoCreateSymbolicLink(&m_usDosDeviceName, &m_usDeviceName);
if (NT_SUCCESS(ns))
{
ns = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, FALSE);
if (NT_SUCCESS(ns))
{
// load options for boot fuzzing (if available)
LoadFuzzerOptions();
if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT)
{
// hook nt!NtDeviceIoControlFile() syscall
m_bHooksInitialized = SetUpHooks();
}
return STATUS_SUCCESS;
}
else
{
DbgMsg(__FILE__, __LINE__, "PsSetCreateProcessNotifyRoutine() fails: 0x%.8x\n", ns);
}
IoDeleteSymbolicLink(&m_usDosDeviceName);
}
else
{
DbgMsg(__FILE__, __LINE__, "IoCreateSymbolicLink() fails: 0x%.8x\n", ns);
}
IoDeleteDevice(m_DeviceObject);
}
else
{
DbgMsg(__FILE__, __LINE__, "IoCreateDevice() fails: 0x%.8x\n", ns);
}
return STATUS_UNSUCCESSFUL;
}
//--------------------------------------------------------------------------------------
// EoF