window 过滤驱动的编写

前言

有时我们需要监控操作系统内核中一些特定的操作如网络驱动的收发,键盘驱动事件,文件读写等。著名的wireshark软件就是利用过滤驱动的机制完成相关操作如下图所示:
window 过滤驱动的编写_第1张图片
我们有可以编写一个过滤驱动拦截相关请求的结果从而实现监听。

案例1

我们首先编写一个简单简单驱动接受ring 3的读写控制请求,这个驱动将来要作为我们被附加监听的驱动示例
需求设计如下:
(1) 我们这个asynring0驱动会创建一个设备MyDDKName
(2) ring 3 的读取请求直接返回异步结果
(3) ring 3 的控制请求直接将读取请求的异步结果返回
(3) ring 3 关闭文件操作,也会触发之前的读请求异步结果返回

#include 

LIST_ENTRY ListHead;

VOID Unload(PDRIVER_OBJECT driver)
{

	DbgPrint("[MyDDKName] enter Unload \r\n");
	UNICODE_STRING SymbolicLinkName = RTL_CONSTANT_STRING(L"\\??\\MyDDKLink");
	IoDeleteSymbolicLink(&SymbolicLinkName);
	IoDeleteDevice(driver->DeviceObject);

	DbgPrint("[MyDDKName] exit Unload \r\n");

}

NTSTATUS Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	UNREFERENCED_PARAMETER(DeviceObject);
	DbgPrint("[MyDDKName] enter Create \r\n");

	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	DbgPrint("[MyDDKName] exit Create \r\n");

	return STATUS_SUCCESS;
}


NTSTATUS Read(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	UNREFERENCED_PARAMETER(DeviceObject);
	DbgPrint("[MyDDKName] enter read \r\n");

	IoMarkIrpPending(Irp);

	InsertHeadList(&ListHead, &Irp->Tail.Overlay.ListEntry);//将Irp插入链表//
	
	DbgPrint("[MyDDKName] exit read \r\n");

	return STATUS_PENDING;;
}

NTSTATUS CleanUp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	UNREFERENCED_PARAMETER(DeviceObject);
	DbgPrint("[MyDDKName] enter CleanUp \r\n");
	while (!IsListEmpty(&ListHead))
	{
		PLIST_ENTRY pEntry = RemoveHeadList(&ListHead);
		PIRP pendingIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);//根据结构体某一成员的地址获取结构体的基地址//

		pendingIrp->IoStatus.Status = STATUS_SUCCESS;
		pendingIrp->IoStatus.Information = 0;
		IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);

		DbgPrint("[MyDDKName] done an IRP  pending  \r\n");

	}


	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	DbgPrint("[MyDDKName] exit CleanUp \r\n");

	return STATUS_SUCCESS;
}


NTSTATUS DispatchControl(
	_In_ struct _DEVICE_OBJECT*  DeviceObject,
	_Inout_ struct _IRP* Irp
) {
	DbgPrint("[MyDDKName] enter DispatchControl \r\n");
	CleanUp(DeviceObject, Irp);
	DbgPrint("[MyDDKName] exit DispatchControl \r\n");

	return STATUS_SUCCESS;
}
NTSTATUS Close(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	UNREFERENCED_PARAMETER(DeviceObject);
	DbgPrint("[MyDDKName] enter Close\n");
	Irp->IoStatus.Status = STATUS_SUCCESS;
	Irp->IoStatus.Information = 0;

	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	DbgPrint("[MyDDKName]  exit Close\n");
	return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver)
{
	UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\MyDDKName");
	UNICODE_STRING SymbolicLinkName = RTL_CONSTANT_STRING(L"\\??\\MyDDKLink");

	PDEVICE_OBJECT DeviceObject;
	DbgPrint("[MyDDKName]  enter DriverEntry\n");

	NTSTATUS status;
	status = IoCreateDevice(driver, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject);

	if (!NT_SUCCESS(status))
	{
		DbgPrint("[MyDDKName]  IoCreateDevice error\n");

		return status;
	}
	status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("[MyDDKName]  IoCreateSymbolicLink error\n");
		IoDeleteDevice(DeviceObject);
		return status;
	}
	InitializeListHead(&ListHead);
	driver->MajorFunction[IRP_MJ_CREATE] = Create;
	driver->MajorFunction[IRP_MJ_READ] = Read;
	driver->MajorFunction[IRP_MJ_CLEANUP] = CleanUp;
	driver->MajorFunction[IRP_MJ_CLOSE] = Close;
	driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl;

	DeviceObject->Flags |= DO_BUFFERED_IO;
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;


	driver->DriverUnload = Unload;
	DbgPrint("[MyDDKName]  exit DriverEntry\n");

	return STATUS_SUCCESS;
}

然后对应的ring 3的程序

// syn_asy三环代码.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include 
#include 
#include 

using namespace std;
using std::count;
using std::endl;

int main()
{
	HANDLE hDevice = CreateFile(TEXT("\\\\.\\MyDDKLink"),
		GENERIC_ALL,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
		NULL);

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("打开设备失败 %d\n", GetLastError());
		return -1;
	}
	DWORD dwret;
	OVERLAPPED overlapped = { NULL };

	int flag = -1;

	while (true)
	{
		cout << "输入1: 读取驱动数据 \r\n 输入2 通知内核完成驱动异步过程" << endl;
		cin >> flag;
		if (flag == 1)
		{
			BOOL result = ReadFile(hDevice, NULL, 0, &dwret, &overlapped);

			cout << " 读取驱动数据完成 dwret " << dwret << " result " << result << endl;

			if (!result && GetLastError() == ERROR_IO_PENDING) {

				cout << "!result && GetLastError() == ERROR_IO_PENDING true " << endl;
				// I/O is pending, wait for completion
				/*result = GetOverlappedResult(
					hDevice,
					&overlapped,
					NULL,
					INFINITE
				);*/
			}
			/*if (result) {
				cout << "Write file success." << endl;
			}
			else {
				cerr << "Write file failed." << endl;
			}*/
		}
		else if (flag == 2)
		{

			BOOL result = DeviceIoControl(hDevice, 1, nullptr, 0, nullptr, 0, nullptr, &overlapped);
			if (!result && GetLastError() == ERROR_IO_PENDING) {

				cout << "DeviceIoControl !result && GetLastError() == ERROR_IO_PENDING true " << endl;
				//I/O is pending, wait for completion
				result = GetOverlappedResult(
					hDevice,
					&overlapped,
					NULL,
					INFINITE
				);
			}
			else if (result)
			{
				cout << "DeviceIoControl success " << endl;

			}
		}
		else
		{
			break;
		}


	}


	cout << "执行完成 CloseHandle" << endl;

	CloseHandle(hDevice);//在内核会触发 MJ_cleanuP 与Close派遣函数//

	getchar();
	return 0;
}

最后我们的过滤驱动


#include 
#include


LONG g_nRefCount = 0;
PDRIVER_OBJECT  g_pDriverObject;
PDEVICE_OBJECT  g_pNextDevice = NULL;

PDRIVER_DISPATCH g_OldMajorFunction[IRP_MJ_MAXIMUM_FUNCTION];


NTSTATUS DispatchCommand(
	_In_ struct _DEVICE_OBJECT*  DeviceObject,
	_Inout_ struct _IRP* Irp
) {

	DbgPrint("[Myattach] enter DispatchCommand \r\n");

	UNREFERENCED_PARAMETER(DeviceObject);
	IoCopyCurrentIrpStackLocationToNext(Irp);
	DbgPrint("[Myattach] exit DispatchCommand \r\n");

	return IoCallDriver(g_pNextDevice, Irp);
}

NTSTATUS
IoCompletionRoutine(
	_In_ PDEVICE_OBJECT DeviceObject,
	_In_ PIRP Irp,
	_In_reads_opt_(_Inexpressible_("varies")) PVOID Context
) {

	DbgPrint("[Myattach] enter IoCompletionRoutine \r\n");

	UNREFERENCED_PARAMETER(DeviceObject);
	UNREFERENCED_PARAMETER(Context);


	if (Irp->PendingReturned)
	{
		DbgPrint("[Myattach] IoCompletionRoutine  PendingReturned \r\n");

		IoMarkIrpPending(Irp);
	}
	InterlockedDecrement(&g_nRefCount);
	DbgPrint("[Myattach] exit IoCompletionRoutine \r\n");

	return Irp->IoStatus.Status;

}
NTSTATUS DispatchRead(
	_In_ struct _DEVICE_OBJECT*  DeviceObject,
	_Inout_ struct _IRP* Irp
) {
	UNREFERENCED_PARAMETER(DeviceObject);

	DbgPrint("[Myattach]  DispatchRead \r\n");


	//NTSTATUS status = (g_OldMajorFunction[IRP_MJ_READ])(DeviceObject, Irp);
	IoCopyCurrentIrpStackLocationToNext(Irp);
	IoSetCompletionRoutine(Irp, &IoCompletionRoutine, NULL, true, true, true);
	InterlockedIncrement(&g_nRefCount);
	return IoCallDriver(g_pNextDevice, Irp);


}
void detachOther() {
	IoDetachDevice(g_pNextDevice);
}

//这个函数被注册用于驱动卸载调用
VOID myUnload(struct _DRIVER_OBJECT* DriverObject) {
	UNREFERENCED_PARAMETER(DriverObject);
	DbgPrint("[Myattach]  enter myUnload \r\n");



	//解除附加驱动
	detachOther();

	DbgPrint("[Myattach]  myUnload g_nRefCount %d \r\n", g_nRefCount);



	while (g_nRefCount != 0);
	DbgPrint("[Myattach]  myUnload done %d \r\n");

	if (DriverObject->DeviceObject != NULL)
	{
		IoDeleteDevice(DriverObject->DeviceObject);
	}
	DbgPrint("[Myattach]  exit myUnload \r\n");


}
void attachOtherDriver(PDRIVER_OBJECT pDriverObject) {
	DbgPrint("[Myattach]  enter attachOtherDriver \r\n ");


	UNICODE_STRING  ustrDevName;
	PFILE_OBJECT pFileObject = NULL;
	PDEVICE_OBJECT pTargetDevice = NULL;
	RtlInitUnicodeString(&ustrDevName, L"\\Device\\MyDDKName");
	//获取命名设备的设备对象 并传入到DeviceObject
	NTSTATUS  Status = IoGetDeviceObjectPointer(&ustrDevName, FILE_ALL_ACCESS, &pFileObject, &pTargetDevice);

	DbgPrint("[Myattach]  pTargetDevice:%p \r\n", pTargetDevice);

	if (!NT_SUCCESS(Status))
	{
		//获取设备对象对应的驱动
		DbgPrint("[Myattach] HookKeyboard failure IoGetDeviceObjectPointer \r\n");
		return;
	}



	//创建设备
	UNICODE_STRING  ustrMyDevName;
	RtlInitUnicodeString(&ustrMyDevName, L"\\Device\\Myattach");
	PDEVICE_OBJECT pSourceDevice = NULL;
	Status = IoCreateDevice(pDriverObject, 0, &ustrMyDevName, pTargetDevice->DeviceType, pTargetDevice->Characteristics, FALSE, &pSourceDevice);


	if (!NT_SUCCESS(Status)) {
		DbgPrint("[Myattach] HookKeyboard failure IoCreateDevice \r\n");
		return;
	}

	pSourceDevice->Flags = pTargetDevice->Flags;
	//执行附加
	g_pNextDevice = IoAttachDeviceToDeviceStack(pSourceDevice, pTargetDevice);

	DbgPrint("[My learning] HookKeyboard  g_pNextDevice  %p \r\n", g_pNextDevice);

	if (g_pNextDevice == NULL)
	{
		IoDeleteDevice(pSourceDevice);
	}

	DbgPrint("[Myattach]  exit attachOtherDriver \r\n ");

}


//驱动被加载的时候会调用此函数
extern "C"
NTSTATUS
DriverEntry(
	_In_ struct _DRIVER_OBJECT* DriverObject,
	_In_ PUNICODE_STRING    RegistryPath
)
{

	DbgPrint("[Myattach]  enter DriverEntry \r\n ");

	//如果你没有用到参数需要告诉系统。
	UNREFERENCED_PARAMETER(RegistryPath);

	//设置相关回调
	for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
	{
		DriverObject->MajorFunction[i] = &DispatchCommand;
	}
	DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;

	//附加到其他驱动上
	attachOtherDriver(DriverObject);

	//设置卸载
	DriverObject->DriverUnload = myUnload;
	
	DbgPrint("[Myattach]  exit DriverEntry \r\n ");

	return STATUS_SUCCESS;
}

我们编译后的产物如下:
window 过滤驱动的编写_第2张图片

安装完驱动的输出

[MyDDKName]  enter DriverEntry
[MyDDKName]  exit DriverEntry
[Myattach]  enter DriverEntry 
[Myattach]  enter attachOtherDriver 
[MyDDKName] enter Create 
[MyDDKName] exit Create 
[MyDDKName] enter CleanUp 
[MyDDKName] exit CleanUp 
[Myattach]  pTargetDevice:FFFFE001B0BF9C20 
[My learning] HookKeyboard  g_pNextDevice  FFFFE001B0BF9C20 
[Myattach]  exit attachOtherDriver 
[Myattach]  exit DriverEntry 

window 过滤驱动的编写_第3张图片

[Myattach] enter DispatchCommand 
[Myattach] exit DispatchCommand 
[MyDDKName] enter Create 
[MyDDKName] exit Create 

输入1之后
window 过滤驱动的编写_第4张图片

[Myattach] DispatchRead 
[MyDDKName] enter read 
[MyDDKName] exit read

window 过滤驱动的编写_第5张图片

[Myattach] enter DispatchCommand 
[Myattach] exit DispatchCommand 
[MyDDKName] enter DispatchControl 
[MyDDKName] enter CleanUp 
[Myattach] enter IoCompletionRoutine 
[Myattach] IoCompletionRoutine  PendingReturned 
[Myattach] exit IoCompletionRoutine 
[MyDDKName] done an IRP  pending  
[MyDDKName] exit CleanUp 
[MyDDKName] exit DispatchControl 

window 过滤驱动的编写_第6张图片

源代码

github源码(内涵过滤键盘驱动)

参考

IRP的同步完成与异步完成

你可能感兴趣的:(安全)