mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 20:05:26 +00:00
1354 lines
47 KiB
C
1354 lines
47 KiB
C
|
#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(
|
|||
|
"<?dml?>" __FUNCTION__ "(): ControlCode=0x%.8x KdCommand=<exec cmd=\"%s\">%s</exec>\n",
|
|||
|
f_entry->IoctlCode, f_entry->szKdCommand, f_entry->szKdCommand
|
|||
|
);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
DbgPrint(
|
|||
|
"<?dml?>" __FUNCTION__ "(): Object=\"%wZ\" KdCommand=<exec cmd=\"%s\">%s</exec>\n",
|
|||
|
&f_entry->usName, f_entry->szKdCommand, f_entry->szKdCommand
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD><C3BC><EFBFBD>
|
|||
|
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
|