Core concepts

IRCAP is a standalone driver which hooks DispatchDeviceControl of the target driver.

Implementation

 1// ircap/ircap.c
 2NTSTATUS
 3DriverEntry(
 4	_In_ PDRIVER_OBJECT	DriverObject,
 5	_In_ PUNICODE_STRING	RegistryPath
 6	)
 7{
 8	...
 9	ntStatus = PsCreateSystemThread(&threadHandle,
10		THREAD_ALL_ACCESS,
11		NULL,
12		(HANDLE)0,
13		NULL,
14		ThreadIRPHooker,
15		NULL);
16
17	...
18	KeWaitForSingleObject(threadObject, Executive, KernelMode, FALSE, NULL);
19	...
20}

It is loaded at boot time and creates a system thread with ThreadIRPHooker routine.

 1// ircap/hook.h
 2VOID
 3ThreadIRPHooker(
 4	_In_ PVOID Context
 5)
 6{
 7	...
 8
 9	for (i = 0; i < 10000; i++) {
10		KDPRINTF("[ircap.sys] try hooking (%d) \n", i);
11
12		g_targetDriverObject = GetDriverObjectbyDeviceName(TARGET_DEVICE_NAME);
13		if (g_targetDriverObject)
14			break;
15
16		KeDelayExecutionThread(KernelMode, FALSE, &Time);
17	}
18	...
19}

This routine first obtains the driver object using GetDriverObjectbyDeviceName function. To get the driver object, it callsObReferenceObjectByName function with a device name.

1	// Hook a DispatchDeviceControl function. 
2	g_oriDispatchDeviceControl = g_targetDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
3	g_targetDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = hookDispatchDeviceControl;
4
5	InitializeObjectAttributes(&ObjectAttributes, &PROGRAM_FILE_PATH, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
6	ntStatus = ZwCreateFile(&g_handle, GENERIC_WRITE, &ObjectAttributes,
7		&IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
8		FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);

Then, it overwrites DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] with hookDispatchDeviceControl function and creates a file to save IRP requests.

 1NTSTATUS
 2hookDispatchDeviceControl(
 3	PDEVICE_OBJECT DeviceObject,
 4	PIRP Irp
 5)
 6
 7{
 8	...
 9
10	programInfo[0] = irpSp->Parameters.DeviceIoControl.IoControlCode;
11	programInfo[1] = inBufLength;
12	programInfo[2] = outBufLength;
13
14	ZwWriteFile(g_handle, NULL, NULL, NULL, &IoStatusBlock, (PVOID)programInfo, sizeof(programInfo), NULL, NULL);
15	ZwWriteFile(g_handle, NULL, NULL, NULL, &IoStatusBlock, (PVOID)inBuf, inBufLength, NULL, NULL);
16
17	return g_oriDispatchDeviceControl(DeviceObject, Irp);
18}

The hookDispatchDeviceControl function saves a serialized IRP request to the file and forwards it to the original DispatchDeviceControl function.