本文提出了一种方法可以在内核层使用“过滤”的方法来捕获Irp数据包。其中可以捕获到进入目标驱动前与目标驱动处理完后的Irp数据包。
1
Irp
现在很多驱动都在使用Irp包的方式来与R3的程序进行通信。Irp是一个结构,由一个管理器进行分配管理。Irp从不单独分配,它总是伴随着多个IO栈位置结构(_IO_STACK_LOCATION
),所以一般的驱动程序在获取真正的数据时需要使用IoGetCurrentIrpStackLocation
函数来获取其中的数据。
2
设备
Windows是以设备(DEVICE_OBJECT
)为中心的,同时Windows支持设备分层。在多层设备的结构中,一个设备是堆叠在另一个设备的上面的,看起来就像一个栈一样,这组设备被称为设备栈。
3
方法
我使用堆叠设备栈的方式,来获取Irp数据包(写过过滤驱动的肯定熟悉)。所以我们需要IoAttachDeviceToDeviceStack
函数来附加到目标设备,这样就会让调用来的时候,先到我们的派遣函数。
问题就变成了我们如何让目标驱动处理完后我们依然可以获取到数据呢?此时解决的关键就是IoSetCompletionRoutine
函数了,它可以让下层的派遣函数调用IoCompleteRequest
后到达指定的回调函数。
如下是一些关键代码:
VOID DriverUnload(PDRIVER_OBJECT pDriver) {
PDEVICE_OBJECT deviceObject = pDriver->DeviceObject;
IoDetachDevice(deviceObject->DeviceObjectExtension->AttachedTo);
IoDeleteDevice(deviceObject);
KdPrint(("[+] Release done.rn"));
}
NTSTATUS MyCompletionRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context) {
auto ioStack = IoGetCurrentIrpStackLocation(Irp);
return STATUS_SUCCESS;
}
NTSTATUS Dispatch(_DEVICE_OBJECT* DeviceObject, _IRP* Irp) {
auto ioStack = IoGetCurrentIrpStackLocation(Irp);
KdPrint(("Func: %xn", ioStack->MajorFunction));
if (ioStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
KdPrint(("IRP_DEVICE_CONTROLn"));
KdPrint(("Code: %xn", ioStack->Parameters.DeviceIoControl.IoControlCode));
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
MyCompletionRoutine,
NULL,
TRUE,
TRUE,
TRUE
);
}
return IoCallDriver(DeviceObject->DeviceObjectExtension->AttachedTo, Irp);
}
extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {
if (pDriver) {
pDriver->DriverUnload = DriverUnload;
}
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"设备名");
PDRIVER_OBJECT targetDriver;
NTSTATUS status = ObReferenceObjectByName(&name, OBJ_CASE_INSENSITIVE, nullptr, 0,
*IoDriverObjectType, KernelMode, nullptr, (PVOID*)&targetDriver);
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch;//这里我只想过滤这个函数。
if (NT_SUCCESS(status)) {
PDEVICE_OBJECT targetDevice = targetDriver->DeviceObject;
PDEVICE_OBJECT fltDev;
IoCreateDevice(
pDriver,
0,
NULL,
targetDevice->DeviceType,
0,
FALSE,
&fltDev
);
IoAttachDeviceToDeviceStack(fltDev, targetDevice);
fltDev->Flags &= ~DO_DEVICE_INITIALIZING;
ObDereferenceObject(targetDriver);
}
}
4
实验
我们针对WinARK的DeviceIoControl
的数据来进行过滤测试。
为了验证我们数据的正确性,我们查看源码选择获取驱动派遣函数的这个功能进行测试。
如上是该功能的源码,传入的是设备名字,传回去的是派遣函数数组。
安装好我们的测试驱动后 查看一下自己的派遣函数列表就能捕获到如下信息:
IRP_DEVICE_CONTROL
Code: 80002060
systemBuff:0x5c,0x0,0x64,0x0,0x72,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x72,0x0,0x5c,0x0,0x41,0x0,0x6e,0x0,0x74,0x0,0x69,0x0,0x52,0x0,0x6f,0x0,0x6f,0x0,0x74,0x0,0x6b,0x0,0x69,0x0,0x74,0x0,0x0,0x0
return:0xa0,0x1a,0x91,0x4e,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xa0,0x1a,0x91,0x4e,0x2,0xf8,0xff,0xff,0x60,0x4f,0x91,0x4e,0x2,0xf8,0xff,0xff,0xd0,0x50,0x91,0x4e,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xb0,0x1c,0x91,0x4e,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0x4f,0x91,0x4e,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff,0xc0,0xf9,0xb1,0x32,0x2,0xf8,0xff,0xff
经观察可以发现传入的内容的确为L"\driver\AntiRootkit"
,传出的内容则是派遣函数列表(总长度为0x1b * 8)。已第一个为例则是0xFFFFF8024E911AA0
,对比发现无误。
看雪ID:moshuiD
https://bbs.kanxue.com/user-home-932553.htm
#
原文始发于微信公众号(看雪学苑):R0下一种简单的Irp包数据捕获方法
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论