驱动层与应用层的事件同步(主动防御原理浅析)
来源:互联网 发布:扎克伯格老婆知乎 编辑:程序博客网 时间:2024/05/21 11:30
在电脑上,大家都装有各种各样的防护软件,也习惯了防护软件弹出的各种提示框, 很多人会好奇,这些软件是如何在危险程序运行前就拦截到关键行为,并弹出提示框的呢?今天,我在这里简单讲解一下实现的原理,即驱动层与应用层的事件同步。下面切入正题。
要实现驱动层与应用层的事件同步, 主要经历下几个步骤:
1、在应用层使用CreateEvent创建事件(自动重置类型或手动重置类型);
2、将事件句柄发送到驱动程序中。
3、应用层使用WaitForSingleObject或WaitForMultipleObjects等待事件。
4、驱动层拦截到关键事件,使用KeSetEvent将事件设置为有信号。
5、应用层等待到事件信号,向驱动层发送控制消息,获取信息。
6、弹出消息提示用户。
7、设置事件为无信号,等待下一次通知。
下面,我用一个监测系统进程创建的简单例子, 简单说明一下实现的步骤。
首先,先从应用层开始。
打开VisualStudio, 创建一个基于对话框的MFC应用程序, 在界面上添加两个按钮,如图:
添加一个全局的事件对象句柄:
HANDLE g_hKernelEvent = NULL;
//创建手动重置的事件g_hKernelEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
void CKernelHanleDemoDlg::OnBnClickedBtnStart(){ DWORD dwRet; //将创建的事件句柄传入驱动程序 BOOL bRet = IOControl(IOCTL_START, &g_hKernelEvent, sizeof(g_hKernelEvent), NULL, 1024, &dwRet); //正在运行 g_bIsRunning = TRUE; //创建监听线程 HANDLE hThread = CreateThread(NULL, 0, KernelHandleThread, NULL, 0, NULL); CloseHandle(hThread); Sleep(1);}
为停止按钮添加处理代码:
void CKernelHanleDemoDlg::OnBnClickedBtnStop(){ g_bIsRunning = FALSE; DWORD dwRet; BOOL bRet = IOControl(IOCTL_STOP, NULL, 0, NULL, NULL, &dwRet);}
启动和停止按钮的功能,就是向驱动发送控制代码,实现对事件通知的控制。
代码中的IOControl函数和KernelHandleThread线程函数, 如下:
BOOL IOControl(DWORD Ctl_code, LPVOID InputBuffer, DWORD nInBufferSize, LPVOID OutputBuffer, DWORD nOutBufferSize, LPDWORD dwRet){ BOOL bRet = FALSE; //打开驱动的符号链接 HANDLE hDevice = CreateFile(L"\\\\.\\KernelHandle",GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if (INVALID_HANDLE_VALUE == hDevice) { MessageBox(NULL,L"Failed To Open Device!",NULL,MB_OK); return FALSE; } bRet = DeviceIoControl(hDevice,Ctl_code,InputBuffer,nInBufferSize,OutputBuffer,nOutBufferSize,dwRet,NULL); CloseHandle(hDevice); return bRet;}//监测线程DWORD WINAPI KernelHandleThread(LPVOID lpParameter){ DWORD dwRet; while(g_bIsRunning) { //等待同步事件信号 WaitForSingleObject(g_hKernelEvent, INFINITE); char szBuffer[20] = {0}; WCHAR szMsgBuffer[100] = {0}; int nProcessId = 0; //等待完成,向驱动发送请求,获取PID IOControl(IOCTL_GET_DATA, NULL, 0, szBuffer, 20, &dwRet); //转换成PID nProcessId = atoi(szBuffer); wsprintf(szMsgBuffer, L"有新进程创建, 进程ID:%d", nProcessId); //弹出消息 MessageBox(NULL,szMsgBuffer, L"驱动消息", MB_OK|MB_ICONINFORMATION); //设置同步事件为无信号,等待下一次通知 ResetEvent(g_hKernelEvent); } return 0;}
至此,应用层主要做的工作已经完成,即:传入事件句柄, 等待驱动通知。
下面,进行驱动层的代码部分。
驱动部分,我使用WDK 7600.16385.1 + VisualDDK开发, 请各位看官按照自己的开发环境进行改动。
首先, 添加两个全局变量, 用于保存事件句柄信息:
//同步事件对象PRKEVENT g_pEventObject = NULL;//句柄信息OBJECT_HANDLE_INFORMATION g_ObjectHandleInfo;
在DriverEntry中, 添加驱动控制分发函数:
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KernelHandleDefaultHandler;
然后添加驱动控制的处理代码:
NTSTATUS KernelHandleDefaultHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){ NTSTATUS status = STATUS_SUCCESS; ULONG ulReturn = 0; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); //驱动控制代码 ULONG ulCtrlCode = stack->Parameters.DeviceIoControl.IoControlCode; //输入输出缓冲区 PVOID InputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer; PVOID OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer; //输入输出缓冲区大小 ULONG ulInputBufferSize = stack->Parameters.DeviceIoControl.InputBufferLength; ULONG ulOutputBufferSize = stack->Parameters.DeviceIoControl.OutputBufferLength; switch(ulCtrlCode) { case IOCTL_START: { //设置同步事件 if (InputBuffer == NULL || ulInputBufferSize < sizeof(HANDLE)) { KdPrint(("Set Event Error~!\n")); break; } //取得句柄对象 HANDLE hEvent = *(HANDLE*)InputBuffer; status = ObReferenceObjectByHandle(hEvent, GENERIC_ALL, NULL, KernelMode, (PVOID*)&g_pEventObject, &g_ObjectHandleInfo); KdPrint(("g_pEventObject = 0x%X\n", g_pEventObject)); //设置进程创建通知函数 if (!g_bIsNotifyRoutineSetted) { PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, FALSE); g_bIsNotifyRoutineSetted = TRUE; } break; } case IOCTL_STOP: { if (g_bIsNotifyRoutineSetted) { //移除进程创建通知函数 PsSetCreateProcessNotifyRoutine(CreateProcessNotifyFunction, TRUE); g_bIsNotifyRoutineSetted = FALSE; } //释放对象引用 if (g_pEventObject != NULL) { ObDereferenceObject(g_pEventObject); g_pEventObject = NULL; } break; } case IOCTL_GET_DATA: { int nLength = strlen(g_szPIDInfo); if (OutputBuffer == NULL && ulOutputBufferSize < nLength) { KdPrint(("OutputBufferSize is too small ~!\n")); break; } //复制进程PID到输出缓冲区 RtlCopyBytes((PCHAR)OutputBuffer, g_szPIDInfo, nLength+1); break; } default: break; }Irp->IoStatus.Status = STATUS_SUCCESS;Irp->IoStatus.Information = ulOutputBufferSize;IoCompleteRequest(Irp, IO_NO_INCREMENT);return Irp->IoStatus.Status;}
在驱动中,拦截进程创建, 一般使用Hook NtCreateProcess来实现,但在我们的这个例子里,只需要获取进程创建的进程ID, 那么,有一个更加简单的方法,即使用PsSetCreateProcessNotifyRoutine函数, 可以方便的获取进程的创建信息。
函数原型如下:
NTSTATUS PsSetCreateProcessNotifyRoutine( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, _In_ BOOLEAN Remove);
其中,NotifyRoutine指定了处理进程创建通知的函数, Remove为False时,代表添加通知函数, 为TRUE时,代表移除通知函数。
NotifyRoutine是一个函数指针,原型为:
VOID(*PCREATE_PROCESS_NOTIFY_ROUTINE) ( IN HANDLE ParentId, IN HANDLE ProcessId, IN BOOLEAN Create );
无需解释过多,Create为True时,代表进程创建,为False时,代表进程退出,因此,我们的处理函数,就写成如下面这样:
//PID信息CHAR g_szPIDInfo[20];VOID CreateProcessNotifyFunction(IN HANDLE hParentId, IN HANDLE hProcessId, IN BOOLEAN bCreate ){ //如果是进程创建 if (bCreate) { //格式化字符串 RtlZeroMemory(g_szPIDInfo, 20); RtlStringCchPrintfA(g_szPIDInfo, 20, "%d", (int)hProcessId); //设置事件为有信号,通知应用层 KeSetEvent(g_pEventObject, 0, FALSE); }}
这样, 当有进程创建时, 就会将创建的进程的PID发送到缓冲区,应用层接收事件信号后,就会读取缓冲区中的PID内容,将弹出消息提示了, 如图:
文章中的代码, 讲解了主要的代码部分,省略了部分代码, 完整的代码,我已上传到网盘。
链接: http://pan.baidu.com/s/1bn9zxHP 密码: 9t7j
解压密码:000000
注:
本文代码的开发环境为:
Visual Studio 2010 + WDK 7600.16385.1 + VisualDDK, 编译成功后,请手动加载驱动。
本帖为原创,转帖请说明出处,谢谢合作。
本帖地址:http://blog.csdn.net/sonsie007/article/details/38356961
- 驱动层与应用层的事件同步(主动防御原理浅析)
- 应用层与驱动层同步事件处理方法
- 应用层与驱动层同步事件处理方法
- 应用层与驱动层同步事件处理方法
- 应用层与驱动层同步事件处理方法
- 浅析防御僵尸网络基于应用层的DDOS攻击
- 应用层和驱动层的同步与异步的处理逻辑及底层实现
- 应用层和驱动层的同步与异步的处理逻辑及底层实现
- 应用层和驱动层的同步与异步的处理逻辑及底层实现
- 驱动层和应用层的同步通信
- 驱动层主动发数据到应用层
- 应用层上的同步原理
- 应用层上的同步原理
- 应用层上的同步原理(2)
- 基于应用层DDoS攻击的剖析与防御
- 驱动层与应用层通信的实现
- 应用层与驱动层通信DeviceIoControl
- 驱动与应用层之间的共享内存通信与事件通知
- HDU 1796 How many integers can you find(组合数学-容斥原理)
- 复习 c#基础加强
- oracle常见操作语句
- Linux网络编程(五) select函数
- 9 Maya模型基础--复制nurbs面片、在曲面上投影曲线、偏移表面
- 驱动层与应用层的事件同步(主动防御原理浅析)
- 余凯在清华的讲座笔记
- hdu 1269 迷宫城堡 (tarjan算法)
- 主席树介绍
- [ZOJ 3354] DoIt is Being Flooded [最短路+并查集]
- DIY 光立方
- js中的preventDefault和stopPropagation
- 外观模式
- hdu 4901 The Romantic Hero