mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
900263ea6f
n/a
564 lines
16 KiB
C
564 lines
16 KiB
C
#include "stdafx.h"
|
|
|
|
NT_DEVICE_IO_CONTROL_FILE old_NtDeviceIoControlFile = NULL;
|
|
|
|
/**
|
|
* Fuzzing settings
|
|
*/
|
|
ULONG m_FuzzOptions = 0;
|
|
FUZZING_TYPE m_FuzzingType = FuzzingType_Random;
|
|
/**
|
|
* Exported variables for acessing to the
|
|
* last IOCTL request information from the kernel debugger.
|
|
*/
|
|
PDEVICE_OBJECT currentDeviceObject = NULL;
|
|
PDRIVER_OBJECT currentDriverObject = NULL;
|
|
ULONG currentIoControlCode = 0;
|
|
PVOID currentInputBuffer = NULL;
|
|
ULONG currentInputBufferLength = 0;
|
|
PVOID currentOutputBuffer = NULL;
|
|
ULONG currentOutputBufferLength = 0;
|
|
|
|
/**
|
|
* Handle and objetc pointer of the fuzzer's process (uses for fair fuzzing mode)
|
|
*/
|
|
HANDLE m_FuzzThreadId = 0;
|
|
PEPROCESS m_FuzzProcess = NULL;
|
|
PUSER_MODE_DATA m_UserModeData = NULL;
|
|
|
|
/**
|
|
* Some fuzzing parameters
|
|
*/
|
|
#define RANDOM_FUZZING_ITERATIONS 10
|
|
#define BUFFERED_FUZZING_ITERATIONS 5
|
|
#define DWORD_FUZZING_MAX_LENGTH 0x2000
|
|
#define DWORD_FUZZING_DELTA 4
|
|
|
|
ULONG g_newDeviceIoControlFileCallCount = 0;
|
|
|
|
#ifdef _X86_
|
|
|
|
// pointer values for invalid kernel and user buffers
|
|
#define KERNEL_BUFFER_ADDRESS (PVOID)(0xFFFF0000)
|
|
#define USER_BUFFER_ADDRESS (PVOID)(0x00001000)
|
|
|
|
#elif _AMD64_
|
|
|
|
#define KERNEL_BUFFER_ADDRESS (PVOID)(0xFFFFFFFFFFFF0000)
|
|
#define USER_BUFFER_ADDRESS (PVOID)(0x0000000000001000)
|
|
|
|
#endif
|
|
|
|
// constants for dword fuzzing
|
|
ULONG m_DwordFuzzingConstants[] =
|
|
{
|
|
0x00000000,
|
|
0x00001000,
|
|
0xFFFF0000,
|
|
0xFFFFFFFF
|
|
};
|
|
|
|
// defined in driver.cpp
|
|
extern PDEVICE_OBJECT m_DeviceObject;
|
|
extern KMUTEX m_CommonMutex;
|
|
extern PCOMMON_LST m_ProcessesList;
|
|
//--------------------------------------------------------------------------------------
|
|
PCOMMON_LST_ENTRY LookupProcessInfo(PEPROCESS Process)
|
|
{
|
|
PCOMMON_LST_ENTRY process_entry = NULL;
|
|
KIRQL OldIrql;
|
|
KeAcquireSpinLock(&m_ProcessesList->ListLock, &OldIrql);
|
|
|
|
__try
|
|
{
|
|
PCOMMON_LST_ENTRY e = m_ProcessesList->list_head;
|
|
|
|
// enumerate all processes
|
|
while (e)
|
|
{
|
|
if (e->Data && e->DataSize == sizeof(LST_PROCESS_INFO))
|
|
{
|
|
PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)e->Data;
|
|
if (Info->Process == Process)
|
|
{
|
|
process_entry = e;
|
|
break;
|
|
}
|
|
}
|
|
|
|
e = e->next;
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
KeReleaseSpinLock(&m_ProcessesList->ListLock, OldIrql);
|
|
}
|
|
|
|
return process_entry;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
void FreeProcessInfo(void)
|
|
{
|
|
KIRQL OldIrql;
|
|
KeAcquireSpinLock(&m_ProcessesList->ListLock, &OldIrql);
|
|
|
|
__try
|
|
{
|
|
PCOMMON_LST_ENTRY e = m_ProcessesList->list_head;
|
|
|
|
// enumerate all processes
|
|
while (e)
|
|
{
|
|
if (e->Data && e->DataSize == sizeof(LST_PROCESS_INFO))
|
|
{
|
|
PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)e->Data;
|
|
if (Info->usImagePath.Buffer)
|
|
{
|
|
// free process image path
|
|
RtlFreeUnicodeString(&Info->usImagePath);
|
|
}
|
|
}
|
|
|
|
e = e->next;
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
KeReleaseSpinLock(&m_ProcessesList->ListLock, OldIrql);
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
void NTAPI ProcessNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
|
|
{
|
|
PEPROCESS Process;
|
|
NTSTATUS ns = PsLookupProcessByProcessId(ProcessId, &Process);
|
|
if (NT_SUCCESS(ns))
|
|
{
|
|
KeWaitForMutexObject(&m_CommonMutex, UserRequest, KernelMode, FALSE, NULL);
|
|
|
|
__try
|
|
{
|
|
if (Create)
|
|
{
|
|
// process has been created
|
|
UNICODE_STRING ImagePath;
|
|
|
|
// get full image path for this process
|
|
if (GetProcessFullImagePath(Process, &ImagePath))
|
|
{
|
|
WCHAR wcProcess[0x200];
|
|
UNICODE_STRING usProcess;
|
|
LST_PROCESS_INFO Info;
|
|
|
|
LogData("Process "IFMT" started: '%wZ' (PID: %d)\r\n\r\n", Process, &ImagePath, ProcessId);
|
|
|
|
swprintf(wcProcess, L"'%wZ' (" IFMT_W L")", &ImagePath, Process);
|
|
RtlInitUnicodeString(&usProcess, wcProcess);
|
|
|
|
|
|
Info.Process = Process;
|
|
Info.ProcessId = ProcessId;
|
|
|
|
Info.usImagePath.Buffer = ImagePath.Buffer;
|
|
Info.usImagePath.Length = ImagePath.Length;
|
|
Info.usImagePath.MaximumLength = ImagePath.MaximumLength;
|
|
|
|
// add process information into the list
|
|
if (LstAddEntry(m_ProcessesList, &usProcess, &Info, sizeof(Info)) == NULL)
|
|
{
|
|
RtlFreeUnicodeString(&ImagePath);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PCOMMON_LST_ENTRY process_entry = NULL;
|
|
LogData("Process "IFMT" terminated\r\n\r\n", Process);
|
|
|
|
// process terminating
|
|
process_entry = LookupProcessInfo(Process);
|
|
if (process_entry)
|
|
{
|
|
if (process_entry->Data &&
|
|
process_entry->DataSize == sizeof(LST_PROCESS_INFO))
|
|
{
|
|
PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)process_entry->Data;
|
|
if (Info->usImagePath.Buffer)
|
|
{
|
|
// free process image path
|
|
RtlFreeUnicodeString(&Info->usImagePath);
|
|
}
|
|
}
|
|
|
|
// delete information about this process from list
|
|
LstDelEntry(m_ProcessesList, process_entry);
|
|
}
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
KeReleaseMutex(&m_CommonMutex, FALSE);
|
|
}
|
|
|
|
ObDereferenceObject(Process);
|
|
}
|
|
else
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, "PsLookupProcessByProcessId() fails; status: 0x%.8x\n", ns);
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
PUNICODE_STRING LookupProcessName(PEPROCESS TargetProcess)
|
|
{
|
|
PEPROCESS Process = TargetProcess;
|
|
PCOMMON_LST_ENTRY process_entry = NULL;
|
|
HANDLE ProcessId = NULL;
|
|
UNICODE_STRING ImagePath;
|
|
PUNICODE_STRING Ret = NULL;
|
|
|
|
if (Process == NULL)
|
|
{
|
|
// lookup current process information entry
|
|
Process = PsGetCurrentProcess();
|
|
}
|
|
|
|
process_entry = LookupProcessInfo(Process);
|
|
if (process_entry)
|
|
{
|
|
if (process_entry->Data &&
|
|
process_entry->DataSize == sizeof(LST_PROCESS_INFO))
|
|
{
|
|
PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)process_entry->Data;
|
|
if (Info->usImagePath.Buffer)
|
|
{
|
|
// return process image path
|
|
return &Info->usImagePath;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// information entry for current process is not found, allocate it
|
|
ProcessId = PsGetCurrentProcessId();
|
|
|
|
|
|
// get full image path for this process
|
|
if (GetProcessFullImagePath(Process, &ImagePath))
|
|
{
|
|
WCHAR wcProcess[0x200];
|
|
UNICODE_STRING usProcess;
|
|
LST_PROCESS_INFO Info;
|
|
|
|
swprintf(wcProcess, L"'%wZ' (" IFMT_W L")", &ImagePath, Process);
|
|
RtlInitUnicodeString(&usProcess, wcProcess);
|
|
|
|
|
|
Info.Process = Process;
|
|
Info.ProcessId = ProcessId;
|
|
|
|
Info.usImagePath.Buffer = ImagePath.Buffer;
|
|
Info.usImagePath.Length = ImagePath.Length;
|
|
Info.usImagePath.MaximumLength = ImagePath.MaximumLength;
|
|
|
|
// add process information into the list
|
|
if (process_entry = LstAddEntry(m_ProcessesList, &usProcess, &Info, sizeof(Info)))
|
|
{
|
|
PLST_PROCESS_INFO pInfo = (PLST_PROCESS_INFO)process_entry->Data;
|
|
Ret = &pInfo->usImagePath;
|
|
}
|
|
else
|
|
{
|
|
RtlFreeUnicodeString(&ImagePath);
|
|
}
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
BOOLEAN ValidateUnicodeString(PUNICODE_STRING usStr)
|
|
{
|
|
ULONG i = 0;
|
|
if (!MmIsAddressValid(usStr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (usStr->Buffer == NULL || usStr->Length == 0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (i = 0; i < usStr->Length; i++)
|
|
{
|
|
if (!MmIsAddressValid((PUCHAR)usStr->Buffer + i))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
NTSTATUS NTAPI new_NtDeviceIoControlFile(
|
|
HANDLE FileHandle,
|
|
HANDLE Event,
|
|
PIO_APC_ROUTINE ApcRoutine,
|
|
PVOID ApcContext,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
ULONG IoControlCode,
|
|
PVOID InputBuffer,
|
|
ULONG InputBufferLength,
|
|
PVOID OutputBuffer,
|
|
ULONG OutputBufferLength)
|
|
{
|
|
KPROCESSOR_MODE PrevMode = ExGetPreviousMode();
|
|
BOOLEAN bLogOutputBuffer = FALSE;
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
|
|
POBJECT_NAME_INFORMATION DeviceObjectName = NULL, DriverObjectName = NULL;
|
|
PFILE_OBJECT pFileObject = NULL;
|
|
NTSTATUS ns = 0;
|
|
|
|
BOOLEAN bProcessEvent = FALSE;
|
|
|
|
LARGE_INTEGER Timeout;
|
|
|
|
PVOID pDeviceObject = NULL;
|
|
PLDR_DATA_TABLE_ENTRY pModuleEntry = NULL;
|
|
|
|
PEPROCESS Process;
|
|
HANDLE ProcessId;
|
|
|
|
_InterlockedIncrement(&g_newDeviceIoControlFileCallCount);
|
|
// get device object by handle
|
|
ns = ObReferenceObjectByHandle(
|
|
FileHandle,
|
|
0, 0,
|
|
KernelMode,
|
|
(PVOID *)&pFileObject,
|
|
NULL
|
|
);
|
|
if(!NT_SUCCESS(ns))
|
|
goto end;
|
|
|
|
// validate pointer to device object
|
|
if (MmIsAddressValid(pFileObject->DeviceObject))
|
|
{
|
|
pDeviceObject = pFileObject->DeviceObject;
|
|
}
|
|
else
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
if (pDeviceObject == m_DeviceObject)
|
|
{
|
|
// don't handle requests to our driver
|
|
goto end;
|
|
}
|
|
|
|
// validate pointer to driver object
|
|
if (!MmIsAddressValid(pFileObject->DeviceObject->DriverObject))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
// get loader information entry for the driver module
|
|
pModuleEntry = (PLDR_DATA_TABLE_ENTRY)
|
|
pFileObject->DeviceObject->DriverObject->DriverSection;
|
|
|
|
if (pModuleEntry == NULL)
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
// validate pointer to loader's table and data from it
|
|
if (!MmIsAddressValid(pModuleEntry) ||
|
|
!ValidateUnicodeString(&pModuleEntry->FullDllName))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
// get device name by poinet
|
|
DeviceObjectName = GetObjectName(pDeviceObject);
|
|
if(!DeviceObjectName)
|
|
goto end;
|
|
|
|
DriverObjectName = GetObjectName(pFileObject->DeviceObject->DriverObject);
|
|
if(!DriverObjectName)
|
|
goto end;
|
|
|
|
Process = PsGetCurrentProcess();
|
|
ProcessId = PsGetCurrentProcessId();
|
|
|
|
Timeout.QuadPart = RELATIVE(SECONDS(5));
|
|
ns = KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, &Timeout);
|
|
if (ns == STATUS_TIMEOUT)
|
|
{
|
|
DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Wait timeout\n");
|
|
goto end;
|
|
}
|
|
|
|
__try
|
|
{
|
|
PWSTR Methods[] =
|
|
{
|
|
L"METHOD_BUFFERED",
|
|
L"METHOD_IN_DIRECT",
|
|
L"METHOD_OUT_DIRECT",
|
|
L"METHOD_NEITHER"
|
|
};
|
|
|
|
PWSTR lpwcMethod = Methods[IoControlCode & 3];
|
|
|
|
|
|
char *lpszKdCommand = NULL;
|
|
|
|
LARGE_INTEGER Time;
|
|
|
|
// get process image path
|
|
PUNICODE_STRING ProcessImagePath = LookupProcessName(NULL);
|
|
if(!ProcessImagePath)
|
|
__leave;
|
|
|
|
KeQuerySystemTime(&Time);
|
|
|
|
// get text name of the method
|
|
currentDeviceObject = pFileObject->DeviceObject;
|
|
currentDriverObject = pFileObject->DeviceObject->DriverObject;
|
|
currentIoControlCode = IoControlCode;
|
|
currentInputBuffer = InputBuffer;
|
|
currentInputBufferLength = InputBufferLength;
|
|
currentOutputBuffer = OutputBuffer;
|
|
currentOutputBufferLength = OutputBufferLength;
|
|
|
|
// if (m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_GLOBAL)
|
|
// {
|
|
// // log IOCTL information into the global log
|
|
// LogDataIoctls("timestamp=0x%.8x%.8x\r\n", Time.HighPart, Time.LowPart);
|
|
// LogDataIoctls("process_id=%d\r\n", ProcessId);
|
|
// LogDataIoctls("process_path=%wZ\r\n", ProcessImagePath);
|
|
// LogDataIoctls("device=%wZ\r\n", &DeviceObjectName->Name);
|
|
// LogDataIoctls("driver=%wZ\r\n", &DriverObjectName->Name);
|
|
// LogDataIoctls("image_file=%wZ\r\n", &pModuleEntry->FullDllName);
|
|
// LogDataIoctls("code=0x%.8x\r\n", IoControlCode);
|
|
// LogDataIoctls("method=%ws\r\n", lpwcMethod);
|
|
// LogDataIoctls("in_size=%d\r\n", InputBufferLength);
|
|
// LogDataIoctls("out_size=%d\r\n", OutputBufferLength);
|
|
// LogDataIoctls("\r\n");
|
|
// }
|
|
|
|
// get debugger command, that can be associated with this IOCTL
|
|
lpszKdCommand = FltGetKdCommand(
|
|
&DeviceObjectName->Name,
|
|
&DriverObjectName->Name/*pModuleEntry->FullDllName*/,
|
|
IoControlCode,
|
|
ProcessImagePath
|
|
);
|
|
|
|
bProcessEvent = FltIsMatchedRequest(
|
|
&DeviceObjectName->Name,
|
|
&pModuleEntry->FullDllName,
|
|
IoControlCode,
|
|
ProcessImagePath
|
|
);
|
|
|
|
if ((bProcessEvent || lpszKdCommand) &&
|
|
(m_FuzzOptions & FUZZ_OPT_LOG_IOCTL))
|
|
{
|
|
LogDataIoctls(
|
|
"timestamp=0x%.8x%.8x\r\n \
|
|
process_id=%d\r\n \
|
|
process_path=%wZ\r\n \
|
|
device=%wZ\r\n \
|
|
driver=%wZ\r\n \
|
|
image_file=%wZ\r\n \
|
|
code=0x%.8x\r\n \
|
|
method=%ws\r\n \
|
|
in_size=%d\r\n \
|
|
out_size=%d\r\n \
|
|
\r\n",
|
|
Time.HighPart, Time.LowPart,
|
|
ProcessId,
|
|
ProcessImagePath,
|
|
&DeviceObjectName->Name,
|
|
&DriverObjectName->Name,
|
|
&pModuleEntry->FullDllName,
|
|
IoControlCode,
|
|
lpwcMethod,
|
|
InputBufferLength,
|
|
OutputBufferLength);
|
|
|
|
if (m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_BUFFERS)
|
|
{
|
|
// log output buffer information
|
|
LogDataIoctls(" OutBuff: "IFMT", OutSize: 0x%.8x\r\n",
|
|
OutputBuffer,
|
|
OutputBufferLength);
|
|
|
|
// log input buffer information
|
|
LogDataIoctls(" InBuff: "IFMT", InSize: 0x%.8x\r\n",
|
|
InputBuffer,
|
|
InputBufferLength);
|
|
|
|
// print input buffer contents
|
|
LogDataIoctls("--------------------------------------------------------------------\r\n");
|
|
LogDataHexdump((PUCHAR)InputBuffer, min(InputBufferLength, MAX_IOCTL_BUFFER_LEGTH));
|
|
LogDataIoctls("\r\n");
|
|
}
|
|
}
|
|
}
|
|
__finally
|
|
{
|
|
KeReleaseMutex(&m_CommonMutex, FALSE);
|
|
}
|
|
end:
|
|
if(pFileObject)
|
|
ObDereferenceObject(pFileObject);
|
|
|
|
if(DriverObjectName)
|
|
ExFreePool(DriverObjectName);
|
|
|
|
if(DeviceObjectName)
|
|
ExFreePool(DeviceObjectName);
|
|
|
|
// restore KTHREAD::PreviousMode
|
|
SetPreviousMode(PrevMode);
|
|
// call original function
|
|
status = old_NtDeviceIoControlFile(
|
|
FileHandle,
|
|
Event,
|
|
ApcRoutine,
|
|
ApcContext,
|
|
IoStatusBlock,
|
|
IoControlCode,
|
|
InputBuffer,
|
|
InputBufferLength,
|
|
OutputBuffer,
|
|
OutputBufferLength
|
|
);
|
|
|
|
_InterlockedDecrement( &g_newDeviceIoControlFileCallCount );
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID WaitHookRemoveComplete()
|
|
{
|
|
LONG Count = 0;
|
|
const LARGE_INTEGER WaitTime = {(ULONG)(-50 * 1000 * 10), -1};
|
|
|
|
do
|
|
{
|
|
KeDelayExecutionThread( KernelMode , FALSE , (PLARGE_INTEGER)&WaitTime );
|
|
_InterlockedExchange( &Count , g_newDeviceIoControlFileCallCount );
|
|
} while (Count != 0 );
|
|
|
|
return;
|
|
}
|
|
//--------------------------------------------------------------------------------------
|
|
// EoF
|