在之前的文章中LyShark
一直都在教大家如何让驱动程序与应用层进行正向通信
,而在某些时候我们不仅仅只需要正向通信,也需要反向通信,例如杀毒软件如果驱动程序拦截到恶意操作则必须将这个请求动态的转发到应用层以此来通知用户,而这种通信方式的实现有多种,通常可以使用创建Socket套接字的方式实现,亦或者使用本章所介绍的通过事件同步
的方法实现反向通信。
基于事件同步方式实现的通信需要用的最重要函数IoCreateNotificationEvent()
这是微软定为开发者提供的。
IoCreateNotificationEvent 例程创建或打开一个命名通知事件,用于通知一个或多个执行线程已发生事件。
PKEVENT IoCreateNotificationEvent(
[in] PUNICODE_STRING EventName,
[out] PHANDLE EventHandle
);
其中的第二个参数EventHandle
指向返回事件对象的内核句柄的位置的指针。此处为了能更好的接收和管理指针与进程之间的关系我们最好定义一个DEVICE_EXTEN
结构体。
// 自定义设备扩展
typedef struct
{
HANDLE hProcess; // HANDLE
PKEVENT pkProcessEvent; // 事件对象
HANDLE hProcessId; // PID
HANDLE hpParProcessId; // PPID
BOOLEAN bIsCreateMark; // Flag
}DEVICE_EXTEN, *PDEVICE_EXTEN;
驱动入口处PsSetCreateProcessNotifyRoutine
则用于创建一个进程回调,该回调函数被指定为pMyCreateProcessThreadRoutine
当回调函数被创建后,一旦有新进程创建则会执行函数内部的具体流程。
如代码所示,在pMyCreateProcessThreadRoutine
函数内首先通过(PDEVICE_EXTEN)GlobalDevObj->DeviceExtension
得到了自定义设备扩展指针,接着将当前进程的PID,PPID,isCreate
等属性赋予到扩展指针中,当一切准备就绪后,通过调用KeSetEvent
将当前进程事件设置为有信号状态,设置后重置为默认值。
// 自定义回调函数
VOID pMyCreateProcessThreadRoutine(IN HANDLE pParentId, HANDLE hProcessId, BOOLEAN bisCreate)
{
PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
// 将进行信息依次复制到结构体中
pDeviceExten->hProcessId = hProcessId;
pDeviceExten->hpParProcessId = pParentId;
pDeviceExten->bIsCreateMark = bisCreate;
// 设置为有信号
KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE);
// 重置状态信号
KeResetEvent(pDeviceExten->pkProcessEvent);
}
此时由于客户端中通过OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME)
打开了内核对象,并通过WaitForSingleObject(hProcessEvent, INFINITE)
一直在等待事件,一旦内核驱动KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE)
设置为有信号状态,则应用层会通过DeviceIoControl
向内核层发送IOCTL
控制信号并等待接收数据。
此时主派遣函数DisPatchIoControl
被触发执行,通过(PPROCESS_PTR)pUserOutPutBuffer
获取到应用层缓冲区设备指针,并依次通过pBuffer->
的方式设置参数,最后返回状态码,此时应用层PROCESS_PTR
中也就得到了进程创建的相关信息。
pBuffer = (PPROCESS_PTR)pUserOutPutBuffer;
uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
uReadLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
uWriteLen = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (uIoControl)
{
case IOCTL:
pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
pBuffer->hProcessId = pDeviceExten->hProcessId;
pBuffer->hpParProcessId = pDeviceExten->hpParProcessId;
pBuffer->bIsCreateMark = pDeviceExten->bIsCreateMark;
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
uWriteLen = 0;
break;
}
如上就是内核层与应用层的部分代码功能分析,接下来我将完整代码分享出来,大家可以自行测试效果。
驱动程序WinDDK.sys完整代码;
// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#include <ntifs.h>
#include <ntstrsafe.h>
#define IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
UNICODE_STRING GlobalSym = { 0 };
PDEVICE_OBJECT GlobalDevObj;
// 自定义设备扩展
typedef struct
{
HANDLE hProcess; // HANDLE
PKEVENT pkProcessEvent; // 事件对象
HANDLE hProcessId; // PID
HANDLE hpParProcessId; // PPID
BOOLEAN bIsCreateMark; // Flag
}DEVICE_EXTEN, *PDEVICE_EXTEN;
// 自定义结构体(临时)
typedef struct
{
HANDLE hProcessId;
HANDLE hpParProcessId