最近做二进制安全研究实习生,主要看的东西是驱动,在Github上发现了款做Fuzz的工具,适用场景说大不大,说小不小。因为它支持的系统只到Windows7(x86+x64)。但是漏洞挖掘嘛,Fuzz还是很重要的,有源码自然要看看了,学习下前辈们的Fuzz方法
大部分的记录我都是直接标记在了源码中,有兴趣的可以直接在我的Github上Clone或者Fork<请务必先仔细看Readme.md>都行,这里放出的只是在看源码中遇见的一些比较重要的问题
由于编码的原因,所以都是英文记录,英语渣,凑合看吧
Github:https://github.com/Iolop/ioctlfuzzer
Important Funtion src\driver\src\driver.cpp
- KernelGetModuleBase src\driver\src\r0_common\common.cpp
- KernelGetExportAddress
KeAddSystemServiceTable
seems like an interesting function. Not sure how does this routine works , here is its assembly code.a way to find ssdt in x64 platform
kd> uf nt!KeAddSystemServiceTable
nt!KeAddSystemServiceTable:
83dc40f2 8bff mov edi,edi
83dc40f4 55 push ebp
83dc40f5 8bec mov ebp,esp // create stack,but no sub esp??
83dc40f7 837d1801 cmp dword ptr [ebp+18h],1
83dc40fb 7760 ja nt!KeAddSystemServiceTable+0x6b (83dc415d) Branch <END>
nt!KeAddSystemServiceTable+0xb:
83dc40fd 8b4518 mov eax,dword ptr [ebp+18h]
83dc4100 c1e004 shl eax,4
83dc4103 83b8c009da8300 cmp dword ptr nt!KeServiceDescriptorTable (83da09c0)[eax],0
83dc410a 7551 jne nt!KeAddSystemServiceTable+0x6b (83dc415d) Branch
nt!KeAddSystemServiceTable+0x1a: Check the instructions before and the valid address
83dc410c 8d88000ada83 lea ecx,nt!KeServiceDescriptorTableShadow (83da0a00)[eax]
83dc4112 833900 cmp dword ptr [ecx],0
83dc4115 7546 jne nt!KeAddSystemServiceTable+0x6b (83dc415d) Branch
nt!KeAddSystemServiceTable+0x25:
83dc4117 837d1801 cmp dword ptr [ebp+18h],1
83dc411b 8b5508 mov edx,dword ptr [ebp+8]
83dc411e 56 push esi
83dc411f 8b7510 mov esi,dword ptr [ebp+10h]
83dc4122 57 push edi
83dc4123 8b7d14 mov edi,dword ptr [ebp+14h]
83dc4126 8911 mov dword ptr [ecx],edx
83dc4128 8b4d0c mov ecx,dword ptr [ebp+0Ch]
83dc412b 8988040ada83 mov dword ptr nt!KeServiceDescriptorTableShadow+0x4 (83da0a04)[eax],ecx
83dc4131 89b0080ada83 mov dword ptr nt!KeServiceDescriptorTableShadow+0x8 (83da0a08)[eax],esi
83dc4137 89b80c0ada83 mov dword ptr nt!KeServiceDescriptorTableShadow+0xc (83da0a0c)[eax],edi
83dc413d 7418 je nt!KeAddSystemServiceTable+0x65 (83dc4157) Branch
nt!KeAddSystemServiceTable+0x4d:
83dc413f 8990c009da83 mov dword ptr nt!KeServiceDescriptorTable (83da09c0)[eax],edx
83dc4145 8988c409da83 mov dword ptr nt!KeServiceDescriptorTable+0x4 (83da09c4)[eax],ecx
83dc414b 89b0c809da83 mov dword ptr nt!KeServiceDescriptorTable+0x8 (83da09c8)[eax],esi
83dc4151 89b8cc09da83 mov dword ptr nt!KeServiceDescriptorTable+0xc (83da09cc)[eax],edi
nt!KeAddSystemServiceTable+0x65:
83dc4157 5f pop edi
83dc4158 b001 mov al,1
83dc415a 5e pop esi
83dc415b eb02 jmp nt!KeAddSystemServiceTable+0x6d (83dc415f) Branch
nt!KeAddSystemServiceTable+0x6b:
83dc415d 32c0 xor al,al
nt!KeAddSystemServiceTable+0x6d:
83dc415f 5d pop ebp
83dc4160 c21400 ret 14h
SetUpHooks-Hook x64 platform src\driver\src
Keep walking in this file, I found this tool seems store fuzz options in register
It contains three functions- SaveFuzzerOptions
- DeleteSavedFuzzerOptions
- LoadFuzzerOptions
DriverDispatch
most important and complicated
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))//inputBufferLength >= struct<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
);
NTSTATUS status = RtlAnsiStringToUnicodeString(&Flt.usName, &asName, TRUE);
if (!NT_SUCCESS(status))
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", status);
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.bDbgcbAction)
{
// add rule into the debugger commands list
if (f_entry = FltDbgcbAdd(&Flt, KdCommandLength))
{
Buff->Status = S_SUCCESS;
if (!m_bEnableDbgcb)
{
// try to reload symbols
if (dbg_exec(".reload"))
{
// kernel debugger communication engine is available and initialized
m_bEnableDbgcb = TRUE;
}
else
{
DbgMsg(
__FILE__, __LINE__,
__FUNCTION__"(): Kernel debugger interaction is not available\n"
);
}
}
}
}
else if (Buff->AddObject.bAllow)
{
// add filter rule into the ALLOW list
if (f_entry = FltAllowAdd(&Flt, KdCommandLength))
{
Buff->Status = S_SUCCESS;
}
}
else
{
// add filter rule into the DENY list
if (f_entry = FltDenyAdd(&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
);
}
}
}
}
__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:
{
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_
PLARGE_INTEGER FuzzThreadId = (PLARGE_INTEGER)&m_FuzzThreadId;
FuzzThreadId->HighPart = 0;
FuzzThreadId->LowPart = Buff->Options.FuzzThreadId;
#endif
if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT)
{
// fair fizzing is not available in the boot fuzzing mode
m_FuzzOptions &= ~FUZZ_OPT_FUZZ_FAIR;
// boot fuzzing mode has been enabled
SaveFuzzerOptions();
m_FuzzOptions = 0;
}
else
{
DeleteSavedFuzzerOptions();
}
if ((m_FuzzOptions & FUZZ_OPT_LOG_EXCEPTIONS) &&
Buff->Options.KiDispatchException_Offset > 0)
{
// ofsset of unexported function for exceptions monitoring
m_KiDispatchException_Offset = Buff->Options.KiDispatchException_Offset;
if (!m_bKiDispatchExceptionHooked)
{
// set up hooks for exception monitoring
m_bKiDispatchExceptionHooked = ExcptHook();
}
m_bLogExceptions = TRUE;
}
else
{
m_bLogExceptions = FALSE;
}
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
);
NTSTATUS status = RtlAnsiStringToUnicodeString(&usDeviceName, &asDeviceName, TRUE);
if (NT_SUCCESS(status))
{
// open disk device object
PDEVICE_OBJECT TargetDeviceObject = NULL;
PFILE_OBJECT TargetFileObject = NULL;
#ifdef USE_IoGetDeviceObjectPointer
status = IoGetDeviceObjectPointer(
&usDeviceName,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&TargetFileObject,
&TargetDeviceObject
);
if (NT_SUCCESS(status))
#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)
{
Buff->DeviceInfo.DriverObjectAddr = TargetDeviceObject->DriverObject;
// get driver object name by pointer
POBJECT_NAME_INFORMATION NameInfo = GetObjectName(TargetDeviceObject->DriverObject);
if (NameInfo)
{
ANSI_STRING asDriverName;
status = RtlUnicodeStringToAnsiString(&asDriverName, &NameInfo->Name, TRUE);
if (NT_SUCCESS(status))
{
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", status);
}
ExFreePool(NameInfo);
}
// get loader information entry for the driver
PLDR_DATA_TABLE_ENTRY pModuleEntry = (PLDR_DATA_TABLE_ENTRY)
TargetDeviceObject->DriverObject->DriverSection;
if (pModuleEntry &&
MmIsAddressValid(pModuleEntry) &&
ValidateUnicodeString(&pModuleEntry->FullDllName))
{
ANSI_STRING asDllName;
status = RtlUnicodeStringToAnsiString(&asDllName, &pModuleEntry->FullDllName, TRUE);
if (NT_SUCCESS(status))
{
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", status);
}
}
Buff->Status = S_SUCCESS;
}
ObDereferenceObject(TargetFileObject);
}
#ifdef USE_IoGetDeviceObjectPointer
else
{
DbgMsg(
__FILE__, __LINE__,
"IoGetDeviceObjectPointer() fails for \"%wZ\", status: 0x%.8x\n",
&usDeviceName, status
);
}
#endif
RtlFreeUnicodeString(&usDeviceName);
}
else
{
DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", status);
}
}
break;
}
case C_GET_OBJECT_NAME:
{
PFILE_OBJECT pFileObject = NULL;
NTSTATUS 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_bKiDispatchExceptionHooked ||
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
FltAllowFlushList();
FltDenyFlushList();
FltDbgcbFlushList();
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
FltAllowFlushList();
FltDenyFlushList();
FltDbgcbFlushList();
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;
}
After fixing the path,i get sys file. But when I run the ioctlfuzzer.exe in Win7 x86,it seems this exe autoload sys!
What…?
Found a piece of code in ioctlfuzzer.cpp,it could release resources.Fuxx.
Seems this exe only load the driver and set it on boot mode.So the DriverDispatch() is the actually fuzzer function.
Ring3:
- DrvDeviceRequest()-DeviceIoControl(IOCTL_DRV_CONTROL)
In DriverDispatch()
A important struct REQUEST_BUFFER
typedef struct _REQUEST_BUFFER
{
// operation status (see S_* definitions)
ULONG Status;
// operation code (see C_* definitions)
ULONG Code;
union
{
struct
{
ULONG Options;
ULONG FuzzThreadId;
FUZZING_TYPE FuzzingType;
PUSER_MODE_DATA UserModeData;
ULONG KiDispatchException_Offset;
} Options;
struct
{
PVOID DeviceObjectAddr;
PVOID DriverObjectAddr;
char szDriverObjectName[MAX_REQUEST_STRING];
char szDriverFilePath[MAX_REQUEST_STRING];
} DeviceInfo;
struct
{
// for C_ADD_IOCTL
ULONG IoctlCode;
// for all C_ADD_*
BOOLEAN bAllow;
// for C_ADD_DEVICE, C_ADD_DRIVER and C_ADD_PROCESS
char szObjectName[MAX_REQUEST_STRING];
/*
If TRUE -- debugger command, that stored in Buff[],
must be executed for every IOCTL, that has been matched
by this object.
*/
BOOLEAN bDbgcbAction;
} AddObject;
struct
{
HANDLE hObject;
char szObjectName[MAX_REQUEST_STRING];
} ObjectName;
struct
{
BOOLEAN bHooksInstalled;
} CheckHooks;
};
- ParseAllowDenySection() src\application\src\ioctlfuzzer.cpp
This function create the REQUEST_BUFFER in ring3 and complete it.
I was wrong,DriverDispatch() just check the options,
Fuzz function is here.
- new_NtDeviceControlFile()
- Fuzz_NtDeviceIoControlFile()
- FuzzContinue_NtDeviceIoControlFile()—this is the real fuzz function
//--------------------------------------------------------------------------------------
void FuzzContinue_NtDeviceIoControlFile(
KPROCESSOR_MODE PrevMode,
HANDLE FileHandle,
HANDLE Event,
PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG IoControlCode,
PVOID InputBuffer,
ULONG InputBufferLength,
PVOID OutputBuffer,
ULONG OutputBufferLength)
{
// allocate temporary buffer for original request
PUCHAR NewBuff = (PUCHAR)M_ALLOC(InputBufferLength);
if (NewBuff)
{
RtlCopyMemory(NewBuff, InputBuffer, InputBufferLength);
if (m_FuzzingType == FuzzingType_Random)
{
/**
* Fuzzing with random values
*/
for (int i = 0; i < RANDOM_FUZZING_ITERATIONS; i++)
{
ULONG TmpInputLength = InputBufferLength;
if (m_FuzzOptions & FUZZ_OPT_FUZZ_SIZE)
{
TmpInputLength = getrand(1, TmpInputLength * 4);
}
// fill buffer with random data
for (ULONG s = 0; s < InputBufferLength; s++)
{
*((PUCHAR)InputBuffer + s) = (UCHAR)getrand(1, 0xff);
}
// change previous mode to UserMode
SetPreviousMode(PrevMode);//why here?
// send fuzzed request
NTSTATUS status = old_NtDeviceIoControlFile(
FileHandle,
Event, ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
TmpInputLength,
OutputBuffer,
OutputBufferLength
);
}
}
else if (m_FuzzingType == FuzzingType_Dword)
{
/**
* Fuzzing with predefined dwords
*/
// check buffer length
ULONG FuzzingLength = XALIGN_DOWN(InputBufferLength, sizeof(ULONG));
if (FuzzingLength <= DWORD_FUZZING_MAX_LENGTH && FuzzingLength >= sizeof(ULONG))
{
// fuzz each dword value in input buffer
for (ULONG i = 0; i < FuzzingLength; i += DWORD_FUZZING_DELTA)
{
for (ULONG i_v = 0; i_v < sizeof(m_DwordFuzzingConstants) / sizeof(ULONG); i_v++)
{
// put dword constant into the buffer
ULONG OldBuffVal = *(PULONG)((PUCHAR)InputBuffer + i);
*(PULONG)((PUCHAR)InputBuffer + i) = m_DwordFuzzingConstants[i_v];
// set previous mode to UserMode
SetPreviousMode(PrevMode);
// send fuzzed request
NTSTATUS status = old_NtDeviceIoControlFile(
FileHandle,
Event, ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength
);
// restore changed dword
*(PULONG)((PUCHAR)InputBuffer + i) = OldBuffVal;
}
}
}
}
// restore buffer
RtlCopyMemory(InputBuffer, NewBuff, InputBufferLength);
ExFreePool(NewBuff);
}
else
{
DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR\n");
}
// try to fuzz missing output buffer length checks
if (OutputBufferLength > 0)
{
// ... with user-mode buffer addresses
PVOID TmpOutputBuffer = USER_BUFFER_ADDRESS;
// set previous mode to UserMode
SetPreviousMode(PrevMode);
// send fuzzed request
NTSTATUS status = old_NtDeviceIoControlFile(
FileHandle,
Event, ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
TmpOutputBuffer, 0
);
// ... with kernel-mode buffer addresses
TmpOutputBuffer = KERNEL_BUFFER_ADDRESS;
// set previous mode to UserMode
SetPreviousMode(PrevMode);
// send fuzzed request
status = old_NtDeviceIoControlFile(
FileHandle,
Event, ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
TmpOutputBuffer, 0
);
}
ULONG Method = IoControlCode & 3;
if (Method != METHOD_BUFFERED)
{
// try to fuzz buffer addresses, if method is not buffered
for (int i = 0; i < BUFFERED_FUZZING_ITERATIONS; i++)
{
// ... with user-mode addresses
PVOID TmpInputBuffer = USER_BUFFER_ADDRESS;
PVOID TmpOutputBuffer = USER_BUFFER_ADDRESS;
ULONG TmpInputBufferLength = getrand(0, 0x100);
ULONG TmpOutputBufferLength = getrand(0, 0x100);
// set previous mode to UserMode
SetPreviousMode(PrevMode);
// send fuzzed request
NTSTATUS status = old_NtDeviceIoControlFile(
FileHandle,
Event, ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
TmpInputBuffer,
TmpInputBufferLength,
TmpOutputBuffer,
TmpOutputBufferLength
);
}
for (int i = 0; i < BUFFERED_FUZZING_ITERATIONS; i++)
{
// ... with kernel-mode addresses
PVOID TmpInputBuffer = KERNEL_BUFFER_ADDRESS;
PVOID TmpOutputBuffer = KERNEL_BUFFER_ADDRESS;
ULONG TmpInputBufferLength = getrand(0, 0x100);
ULONG TmpOutputBufferLength = getrand(0, 0x100);
// change previous mode to UserMode
SetPreviousMode(PrevMode);
// send fuzzed request
NTSTATUS status = old_NtDeviceIoControlFile(
FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
TmpInputBuffer,
TmpInputBufferLength,
TmpOutputBuffer,
TmpOutputBufferLength
);
}
}
}
After hooking the nt!NtDeviceIoControlFile,new_NtDeviceControlFile()
takes place of it,and it calls FuzzContinue_NtDeviceIoControlFile().
As u see,it will generate random buffer and length.
However,there is a bad news. DeviceIoControlFile() is deprecated and replaced by DeviceIoControl(), which means we need to hook it. So,we need to re-compile the source code to get a new sys&exe file.
既然DeviceIoControlFile()已经被标记废弃,想继续使用这要工具就得自己修改源码来hook DeviceIoCotrol(),hook之后是拦截正常通信,来修改我们的buffer区域,换一个思路,我们也可直接和一个有Symbol name的对象通信,只不过这样就需要我们自己来测试或者拦截到可能的参数(ex:ControlCode BufferSize),所以想要直接通信,我们还需要其他的工具,具体的请参照此仓库https://github.com/koutto/ioctlbf中的Readme.md最后几行。