- 注册时间
- 2011-3-6
- 最后登录
- 1970-1-1
该用户从未签到
|
HIPS思路:
1.驱动将捕获的操作放入一个等待链表中(包括一个标识ID,一个event,一个等待结果的域);同时将操作内容放入一个内容链表中,并完成来自应用层的读pendingirp列表
2.wait for event
1.应用层开一个独立线程负责读出(overlapped)驱动中链表中的内容.如果此时没有内容可读,则pending入pending irp列表中
2.驱动提供自己控制设备的读请求,将链表中的内容提供给应用层的读操作
3.应用层拿到操作内容,弹窗
4.应用层通过IOCTL下发用户指定的结果
1.在驱动IOCTL分发函数中,将用户结果放入链表中同ID的结构中
2.驱动IOCTL分发函数中设置EVENT
3.驱动拿到用户操作结果
4.摘掉链表中的操作,并获取操作中的结果
5.驱动根据操作结果判断是否允许或者阻止
6.下发结果
R0将检测到的攻击行为放到一个链表中(如果没有可用IRP) 应用层发送读请求就到这个链表中取
如果有可用IRP就直接将这次行为给这个IRP(这时R3一定已经在等待了 看后面就会懂)
代码:
//设置事件相关的数据,发送给R3,比如进程ID,名字,路径,以及具体操作(创建,修改,删除)等等
//当然,这里,我们只是简单的捕捉了进程的ID或者名字等
ulPtr = (ULONG_PTR)PsGetCurrentProcessId();
lpNewOpInfo->m_ulProcessID = (ULONG_PTR)ulPtr;
lpNewOpInfo->m_ulWaitID = MakeWaitID();//区别不同事件的ID
lpNewWaitEntry = (WAIT_LIST_ENTRY*)ExAllocatePool(NonPagedPool, sizeof(WAIT_LIST_ENTRY));
if (lpNewWaitEntry == NULL)
{
goto End;
}
lpNewWaitEntry->m_ulWaitID = lpNewOpInfo->m_ulWaitID;
KeInitializeEvent(&lpNewWaitEntry->m_ulWaitEvent, SynchronizationEvent, FALSE);
// 插入等待队列,等待R3下发结果
LockWrite(&g_WaitListLock);
InsertTailList(&g_WaitList, &lpNewWaitEntry->m_List);
UnLockWrite(&g_WaitListLock);
LockWrite(&g_PendingIrpListLock);
bSuccess = CompletePendingIrp(&g_PendingIrpList, lpNewOpInfo);//查看是否有未完成的pendingIRP,直接将该OperInfo传给R3
UnLockWrite(&g_PendingIrpListLock);
if (bSuccess == FALSE) //完成pending irp失败,将lpNewOpInfo插入operlist
{
LockWrite(&g_OperListLock);
InsertTailList(&g_OperList, &lpNewOpInfo->m_List); //插入OperList,等待R3来读取
UnLockWrite(&g_OperListLock);
lpNewOpInfo = NULL;
}
[/code]
注意下:这是如果是看有没有未完成的IRP 有就直接给它了 没有就将检测到的攻击行为插入记录事件链表
CompletePendingIrp:
BOOLEAN
CompletePendingIrp(LIST_ENTRY* pIrpListHead, OP_INFO* pOpInfo)
{
LIST_ENTRY *lpIrpList = NULL;
PIRP lpIrp = NULL;
BOOLEAN bFound = FALSE;
BOOLEAN bReturn = FALSE;
if (IsListEmpty(pIrpListHead) == TRUE)
{
return bReturn;
}
for (lpIrpList = pIrpListHead->Flink; lpIrpList != pIrpListHead; lpIrpList = lpIrpList->Flink)
{
lpIrp = CONTAINING_RECORD(lpIrpList, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(lpIrp, NULL))
{
RemoveEntryList(lpIrpList);
bFound = TRUE;
break;
}
}
if (bFound == FALSE)
{
return bReturn;
}
RtlCopyMemory(lpIrp->AssociatedIrp.SystemBuffer, pOpInfo, sizeof(RING3_OP_INFO));
lpIrp->IoStatus.Information = sizeof(RING3_OP_INFO);
lpIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(lpIrp, IO_NO_INCREMENT);
bReturn = TRUE;
return bReturn;
}
[/code]
读分发函数:
NTSTATUS DispatchRead (
IN PDEVICE_OBJECT pDevObj,
IN PIRP lpIrp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG ulLength = 0;
PIO_STACK_LOCATION lpIrpStack = IoGetCurrentIrpStackLocation(lpIrp);
OP_INFO *lpOpInfoEntry = NULL;
LIST_ENTRY *lpOpInfoList = NULL;
//如果读的len小于这个结构 就返回无效的
if (lpIrpStack->arameters.Read.Length < sizeof(RING3_OP_INFO))
{
ntStatus = STATUS_INVALID_PARAMETER;
ulLength = 0;
goto Completed;
}
//先锁定Write
LockWrite(&g_OperListLock);
//如果是空的链表 将这次的IRP放入Pending链表 就是如果没有消息 就将这次的请求保存起来 等有了在给它
//当这个IRP被处理时调用CommonIrpCancel这个函数 通知R3这个IRP被处理了
if (IsListEmpty(&g_OperList) == TRUE)
{
UnLockWrite(&g_OperListLock);
LockWrite(&g_PendingIrpListLock);
PendingIrpToList(lpIrp, &g_PendingIrpList, CommonIrpCancel);
UnLockWrite(&g_PendingIrpListLock);
goto Pended;
}
//处理第一个节
lpOpInfoList = g_OperList.Flink;
//获得Entry头
lpOpInfoEntry = CONTAINING_RECORD(lpOpInfoList, OP_INFO, m_List);
//移除这个节点
RemoveEntryList(lpOpInfoList);
UnLockWrite(&g_OperListLock);
//将链表的信息窗给R3
RtlCopyMemory(lpIrp->AssociatedIrp.SystemBuffer, lpOpInfoEntry, sizeof(RING3_OP_INFO));
ntStatus = STATUS_SUCCESS;
ulLength = sizeof(RING3_OP_INFO);
ExFreePool(lpOpInfoEntry);
Completed:
lpIrp->IoStatus.Status = ntStatus;
lpIrp->IoStatus.Information = ulLength;
IoCompleteRequest(lpIrp, IO_NO_INCREMENT);
return ntStatus;
Pended:
return STATUS_PENDING;
}
[/code]
有两种情况 一种是有攻击行为 这个链表有值 这时就很好办 下面是第一种的步骤
应用层使用异步读请求--如果驱动层这时有攻击事件(记录攻击事件的链表不为空)就直接获得信息见上面的读分发函数
并将这个事件插入等待队列 等待R3的结果
返回给R3的信息包括一个进程ID 进程名称 一个标记(用于区别不同事件)
结构如下:
typedef struct _OP_INFO
{
WCHAR m_ProcessName[MAX_PATH];
DWORD m_ulProcessID;
ULONG m_ulWaitID;
LIST_ENTRY m_List;
} OP_INFO, *POP_INFO;[/code]但给R3的只给前三个数据 不需要拷贝 直接对上面的数据大小赋值sizeof(_OP_INFO_R3)
typedef struct _OP_INFO_R3
{
WCHAR m_ProcessName[MAX_PATH];
DWORD m_ulProcessID;
ULONG m_ulWaitID;[/code]}
驱动里面将这个等待事件插入等待队列 等待队列链表中结构如下
typedef struct _WAIT_LIST_ENTRY
{
LIST_ENTRY m_List;
ULONG m_ulWaitID;
KEVENT m_ulWaitEvent;
ULONG m_bBlocked;
}WAIT_LIST_ENTRY;[/code]
注意:在插入之前要为其中的的事件和等待ID(就是上面的标记)赋值 m_bBlocked留空 等R3处理后再来赋值
代码:
lpNewOpInfo = (OP_INFO*)ExAllocatePool(PagedPool, sizeof(OP_INFO));
if (lpNewOpInfo == NULL)
{
return NotifyResult;
}
//设置事件相关的数据,发送给R3,比如进程ID,名字,路径,以及具体操作(创建,修改,删除)等等
//当然,这里,我们只是简单的捕捉了进程的ID或者名字等
ulPtr = (ULONG_PTR)PsGetCurrentProcessId();
lpNewOpInfo->m_ulProcessID = (ULONG_PTR)ulPtr;
lpNewOpInfo->m_ulWaitID = MakeWaitID();//区别不同事件的ID
lpNewWaitEntry = (WAIT_LIST_ENTRY*)ExAllocatePool(NonPagedPool, sizeof(WAIT_LIST_ENTRY));
if (lpNewWaitEntry == NULL)
{
goto End;
}
lpNewWaitEntry->m_ulWaitID = lpNewOpInfo->m_ulWaitID;
KeInitializeEvent(&lpNewWaitEntry->m_ulWaitEvent, SynchronizationEvent, FALSE);
// 插入等待队列,等待R3下发结果
LockWrite(&g_WaitListLock);
InsertTailList(&g_WaitList, &lpNewWaitEntry->m_List);
UnLockWrite(&g_WaitListLock);
LockWrite(&g_PendingIrpListLock);
bSuccess = CompletePendingIrp(&g_PendingIrpList, lpNewOpInfo);//查看是否有未完成的pendingIRP,直接将该OperInfo传给R3
UnLockWrite(&g_PendingIrpListLock);
if (bSuccess == FALSE) //完成pending irp失败,将lpNewOpInfo插入operlist
{
LockWrite(&g_OperListLock);
InsertTailList(&g_OperList, &lpNewOpInfo->m_List); //插入OperList,等待R3来读取
UnLockWrite(&g_OperListLock);
lpNewOpInfo = NULL;
}
//并在这里等待40秒(R3等待30秒) [/code]
这40秒钟R3必定为发送一次读下来 读到信息后决定是否放行
R3返回结构 结构如下:
typedef struct _R3_REPLY
{
ULONG m_ulWaitID;
ULONG m_ulBlocked;
}R3_REPLY;[/code]
m_ulWaitID 为读到的ID m_ulBlocked为是否放行
填好后使用DeviceIoControl将数据发送下去
驱动收到后 根据ID遍历等待链表并返回链表头 然后设置链表中的放行状态
case IOCTL_SEND_RESULT_TO_R0://R3向内核传递弹窗结果,将对应的WaitID事件设置用户选择结果
{
RING3_REPLY *lpReply = NULL;
WAIT_LIST_ENTRY *lpWaitEntry = NULL;
if (lpIrpStack->arameters.DeviceIoControl.InputBufferLength < sizeof(RING3_REPLY))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
lpReply = (RING3_REPLY*)Irp->AssociatedIrp.SystemBuffer;
LockWrite(&g_WaitListLock);
lpWaitEntry = FindWaitEntryByID(&g_WaitList, lpReply->m_ulWaitID);//根据WaitID,找到对应的拦截事件
if (lpWaitEntry != NULL)
{
lpWaitEntry->m_bBlocked = lpReply->m_ulBlocked;
KeSetEvent(&lpWaitEntry->m_ulWaitEvent, 0, FALSE);//设置EVENT事件,唤醒GetResultFromUser()里的等待事件
}
UnLockWrite(&g_WaitListLock);
Irp->IoStatus.Information = 0;
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;[/code]
设置EVENT事件后,唤醒前面等待的线程
线程被激活后 首先将这个事件移除链表 然后对数据监测 进行放行/阻止工作 并要释放先前为链表申请的内存
// 等40秒,环3是30秒超时
WaitTimeOut.QuadPart = -40 * 10000000;
Status = KeWaitForSingleObject(&lpNewWaitEntry->m_ulWaitEvent,
Executive, KernelMode, FALSE, &WaitTimeOut);//等待R3下发允许或阻止操作
LockWrite(&g_WaitListLock);
RemoveEntryList(&lpNewWaitEntry->m_List);
UnLockWrite(&g_WaitListLock);
if (Status != STATUS_TIMEOUT)
{
if (lpNewWaitEntry->m_bBlocked == TRUE)
{
NotifyResult = R3Result_Block;
}
else
{
NotifyResult = R3Result_Pass;
}
}
else
{
NotifyResult = R3Result_DefaultNon;
}[/code]
在回调中判断 就可以了
if (notifyResult == R3Result_Block)
{
DbgPrint("阻止\n");
*(ULONG *)outputBuffer = 0;
ntStatus = STATUS_SUCCESS;
}
else if (notifyResult == R3Result_Pass)
{
DbgPrint("允许\n");
*(ULONG *)outputBuffer = 1;
ntStatus = STATUS_SUCCESS;
}
else
{
DbgPrint("超时允许\n");
*(ULONG *)outputBuffer = 1;
ntStatus = STATUS_SUCCESS;
}[/code]
这样就完成了
第二种情况 没有攻击事件,记录攻击事件的聊表为空 那怎么办呢?下面是步骤
但有时候读的时候,没有攻击事件发生,那要怎么办呢?
这就是我们使用异步读的有点,使用异步读,会产生一个IRP 这个IRP可以不用马上被处理,可以将它放入链表里 用到它的时候在拿出来
//如果是空的链表 将这次的IRP放入Pending链表 就是如果没有消息 就将这次的请求保存起来 等有了在给它
//当这个IRP被处理时调用CommonIrpCancel这个函数 通知R3这个IRP被处理了
if (IsListEmpty(&g_OperList) == TRUE)
{
UnLockWrite(&g_OperListLock);
LockWrite(&g_PendingIrpListLock);
PendingIrpToList(lpIrp, &g_PendingIrpList, CommonIrpCancel);
UnLockWrite(&g_PendingIrpListLock);
goto Pended;
}[/code]
Pended:
return STATUS_PENDING;[/code]
用它的时候
LockWrite(&g_PendingIrpListLock);
<span style="white-space:pre"> </span>bSuccess = CompletePendingIrp(&g_PendingIrpList, lpNewOpInfo);//查看是否有未完成的pendingIRP,直接将该OperInfo传给R3
<span style="white-space:pre"> </span>UnLockWrite(&g_PendingIrpListLock);[/code]
代码实现:
BOOLEAN
CompletePendingIrp(LIST_ENTRY* pIrpListHead, OP_INFO* pOpInfo)
{
LIST_ENTRY *lpIrpList = NULL;
PIRP lpIrp = NULL;
BOOLEAN bFound = FALSE;
BOOLEAN bReturn = FALSE;
if (IsListEmpty(pIrpListHead) == TRUE)
{
return bReturn;
}
for (lpIrpList = pIrpListHead->Flink; lpIrpList != pIrpListHead; lpIrpList = lpIrpList->Flink)
{
lpIrp = CONTAINING_RECORD(lpIrpList, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(lpIrp, NULL))//每一个IRP都可以对应一个取消例程 函数把IRP与取消例程进行关联,当要删除取消例程时,把第二个参数设为空即可
{
//遍历删除 如果删除失败就不是这个IRP的取消例程 如果删除成功就说明是这个IRP的取消例程
RemoveEntryList(lpIrpList);
bFound = TRUE;
break;
}
}
if (bFound == FALSE)
{
return bReturn;
}
RtlCopyMemory(lpIrp->AssociatedIrp.SystemBuffer, pOpInfo, sizeof(RING3_OP_INFO));
lpIrp->IoStatus.Information = sizeof(RING3_OP_INFO);
lpIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(lpIrp, IO_NO_INCREMENT);
bReturn = TRUE;
return bReturn;
}[/code]
我们R3使用异步读 但这次读没有数据(但会立即返回 返回结果是STATUS_PENDING),为什么返回STATUS_PENDING呢 以为我们在R0将这个IRP挂起,并将它加入队列
并返回STATUS_PENDING
这个时候看似读请求结束了 但是操作还是没有完成的 这就是ReadFile最后一个参数的作用了 最后这个参数可以记录这次操作是否完成
如果操作完成了 也就是R0检测到有攻击行为了 那么就到IRP链表中将这个IRP拿出来使用 并设置这个操作结束了
应用层可以再读之后使用WaitForSingleObject等待最后一个参数 如果被设置了 那么就说明这个操作真正完成了
就可以得到攻击行为数据并弹窗了 然后再将用户处理结果传给R0 R0再根据ID去找这个事件 找到后移除链表 放行/阻止 释放内存即可
这个HIPS是用三个链表
一个事件记录链表 当有攻击行为发送就填充数据并插入链表
一个是等待链表 将等待R3结果的行为填充(比如事件ID) 插入链表
一个是挂起链表 有的时候读的时候没有攻击行为 即事件记录聊表为空的时候 我们将这个读请求挂起并放入挂起聊表
当有攻击行为发送时,就先看看这里面有没有被挂起的IRP 如果有就将这个信息给它 让它返回
R3就负责循环发送读请求(异步)
如果没有消息就等待这个IRP被处理 然后弹窗 并发送处理结果
如果有消息就直接弹窗 并发送处理结果
整个代码:
R3:使用异步读 需要创建一个事件 然后再最后一个参数设置上 并且这个读 还是个线程
// PopupClientDlg.cpp : implementation file
//
#include "stdafx.h"
#include "opupClient.h"
#include "opupClientDlg.h"
#include "ioctlcmd.h"
#include <shlwapi.h>
#include "opupDlg.h"
#pragma comment(lib, "shlwapi.lib")
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DRIVER_NAME _T("opupDrv")
#define DRIVER_PATH _T(".\\PopupDrv.sys")
HANDLE gh_Device = INVALID_HANDLE_VALUE;
CWinThread *g_hReadThread = NULL;
BOOL g_bToExitThread = FALSE;
HANDLE g_hOverlappedEvent = NULL;
BOOL LoadDriver(TCHAR* lpszDriverName,TCHAR* lpszDriverPath)
{
TCHAR szDriverImagePath[256] = {0};
//得到完整的驱动路径
GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);
BOOL bRet = FALSE;
SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
//打开服务控制管理器
hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( hServiceMgr == NULL )
{
//OpenSCManager失败
//printf( "OpenSCManager() Failed %d ! \n", GetLastError() );
bRet = FALSE;
goto BeforeLeave;
}
else
{
////OpenSCManager成功
printf( "OpenSCManager() ok ! \n" );
}
//创建驱动所对应的服务
hServiceDDK = CreateService( hServiceMgr,
lpszDriverName, //驱动程序的在注册表中的名字
lpszDriverName, // 注册表驱动程序的 DisplayName 值
SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
szDriverImagePath, // 注册表驱动程序的 ImagePath 值
NULL, //GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList
NULL,
NULL,
NULL,
NULL);
DWORD dwRtn;
//判断服务是否失败
if( hServiceDDK == NULL )
{
dwRtn = GetLastError();
if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
{
//由于其他原因创建服务失败
//printf( "CrateService() Failed %d ! \n", dwRtn );
bRet = FALSE;
goto BeforeLeave;
}
else
{
//服务创建失败,是由于服务已经创立过
printf( "CrateService() Faild Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );
}
// 驱动程序已经加载,只需要打开
hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );
if( hServiceDDK == NULL )
{
//如果打开服务也失败,则意味错误
dwRtn = GetLastError();
//printf( "OpenService() Failed %d ! \n", dwRtn );
bRet = FALSE;
goto BeforeLeave;
}
else
{
//printf( "OpenService() ok ! \n" );
}
}
else
{
//printf( "CrateService() ok ! \n" );
}
//开启此项服务
bRet= StartService( hServiceDDK, NULL, NULL );
if( !bRet )
{
DWORD dwRtn = GetLastError();
if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )
{
//printf( "StartService() Failed %d ! \n", dwRtn );
bRet = FALSE;
goto BeforeLeave;
}
else
{
if( dwRtn == ERROR_IO_PENDING )
{
//设备被挂住
//printf( "StartService() Failed ERROR_IO_PENDING ! \n");
bRet = FALSE;
goto BeforeLeave;
}
else
{
//服务已经开启
//printf( "StartService() Failed ERROR_SERVICE_ALREADY_RUNNING ! \n");
bRet = TRUE;
goto BeforeLeave;
}
}
}
bRet = TRUE;
//离开前关闭句柄
BeforeLeave:
if(hServiceDDK)
{
CloseServiceHandle(hServiceDDK);
}
if(hServiceMgr)
{
CloseServiceHandle(hServiceMgr);
}
return bRet;
}
//卸载驱动程序
BOOL UnloadDriver( TCHAR * szSvrName )
{
BOOL bRet = FALSE;
SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
SERVICE_STATUS SvrSta;
//打开SCM管理器
hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( hServiceMgr == NULL )
{
//带开SCM管理器失败
printf( "OpenSCManager() Failed %d ! \n", GetLastError() );
bRet = FALSE;
goto BeforeLeave;
}
else
{
//带开SCM管理器失败成功
printf( "OpenSCManager() ok ! \n" );
}
//打开驱动所对应的服务
hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );
if( hServiceDDK == NULL )
{
//打开驱动所对应的服务失败
printf( "OpenService() Failed %d ! \n", GetLastError() );
bRet = FALSE;
goto BeforeLeave;
}
else
{
printf( "OpenService() ok ! \n" );
}
//停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
if( !ControlService( hServiceDDK, SERVICE_CONTROL_STOP , &SvrSta ) )
{
printf( "ControlService() Failed %d !\n", GetLastError() );
}
else
{
//打开驱动所对应的失败
printf( "ControlService() ok !\n" );
}
//动态卸载驱动程序。
if( !DeleteService( hServiceDDK ) )
{
//卸载失败
printf( "DeleteSrevice() Failed %d !\n", GetLastError() );
}
else
{
//卸载成功
printf( "DelServer:eleteSrevice() ok !\n" );
}
bRet = TRUE;
BeforeLeave:
//离开前关闭打开的句柄
if(hServiceDDK)
{
CloseServiceHandle(hServiceDDK);
}
if(hServiceMgr)
{
CloseServiceHandle(hServiceMgr);
}
return bRet;
}
HANDLE OpenDevice()
{
//测试驱动程序
HANDLE hDevice = CreateFile(_T("\\\\.\\PopupDrv"),
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if( hDevice != INVALID_HANDLE_VALUE )
{
printf( "Create Device ok ! \n" );
}
else
{
printf( "Create Device faild %d ! \n", GetLastError() );
return NULL;
}
return hDevice;
}
typedef struct _R3_REPLY
{
ULONG m_ulWaitID;
ULONG m_ulBlocked;
}R3_REPLY;
typedef struct _OP_INFO
{
WCHAR m_ProcessName[MAX_PATH];
DWORD m_ulProcessID;
ULONG m_ulWaitID;
} OP_INFO, *POP_INFO;
VOID SendResultToR0(ULONG ulWaitID, BOOL bBlocked)
{
if (gh_Device == INVALID_HANDLE_VALUE)
{
return ;
}
R3_REPLY R3Reply;
R3Reply.m_ulWaitID = ulWaitID;
R3Reply.m_ulBlocked = bBlocked;
ULONG ulRet = 0;
:eviceIoControl(gh_Device, IOCTL_SEND_RESULT_TO_R0, &R3Reply, sizeof(R3_REPLY), NULL, 0, &ulRet, NULL);
return ;
}
BOOL HandleData(OP_INFO *pOpInfoData)
{
CPopupDlg dlg;
dlg.SetProcess(pOpInfoData->m_ProcessName);
dlg.SetDetail(_T("有进程正在非法攻击"));
dlg.DoModal();
if (dlg.m_bAllow == 0)
{
return FALSE;
}
return TRUE;
}
void PopupInfoToUser(OP_INFO *pOpInfo, int Num)
{
OP_INFO * currData = pOpInfo;
CString szNum;
for(int i = 0; i < Num; i++)
{
BOOL bResult = HandleData(currData); // 此处可以弹框获得用户的结果
if (bResult)
{
SendResultToR0(pOpInfo->m_ulWaitID, TRUE);
}
else
{
SendResultToR0(pOpInfo->m_ulWaitID, FALSE);
}
currData++;
}
}
UINT ReadThreadProc(LPVOID lpContext)
{
OVERLAPPED Overlapped;
g_hOverlappedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (g_hOverlappedEvent == NULL || gh_Device == INVALID_HANDLE_VALUE)
{
return -1;
}
memset(&Overlapped, 0, sizeof(OVERLAPPED));
ULONG ulReturn = 0;
ULONG ulBytesReturn = 0;
OP_INFO OpInfo;
Overlapped.hEvent = g_hOverlappedEvent;
::SleepEx(1, TRUE);
while (TRUE)
{
ulReturn = ReadFile(gh_Device, &OpInfo, sizeof(OP_INFO), &ulBytesReturn, &Overlapped);
if (g_bToExitThread == TRUE)
{
break;
}
if (ulReturn == 0)
{
if (GetLastError() == ERROR_IO_PENDING)//没有攻击行为发生
{
ULONG ulApiReturn = WaitForSingleObject(Overlapped.hEvent, INFINITE);
if (ulApiReturn == WAIT_FAILED)
{
break;
}
if (g_bToExitThread == TRUE)
{
break;
}
}
else
{
continue;
}
}
if (ulBytesReturn == sizeof(OP_INFO))
{
PopupInfoToUser(&OpInfo, 1);
}
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg:oDataExchange(CDataExchange* pDX)
{
CDialog:oDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPopupClientDlg dialog
CPopupClientDlg::CPopupClientDlg(CWnd* pParent /*=NULL*/)
: CDialog(CPopupClientDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CPopupClientDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CPopupClientDlg:oDataExchange(CDataExchange* pDX)
{
CDialog:oDataExchange(pDX);
//{{AFX_DATA_MAP(CPopupClientDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPopupClientDlg, CDialog)
//{{AFX_MSG_MAP(CPopupClientDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
ON_WM_CLOSE()
ON_COMMAND(ID_MENU_EXIT, OnMenuExit)
ON_COMMAND(ID_MENU_RESTORE, OnMenuRestore)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_ICON_NOTIFY, OnTrayNotification)
ON_BN_CLICKED(IDOK, &CPopupClientDlg::OnBnClickedOk)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPopupClientDlg message handlers
BOOL CPopupClientDlg::OnInitDialog()
{
CDialog::OnInitDialog();
::BringWindowToTop(m_hWnd);
::SetWindowPos(
m_hWnd,
HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
NOTIFYICONDATA m_tnid;
m_tnid.cbSize=sizeof(NOTIFYICONDATA);//设置结构大小//
m_tnid.hWnd=this->m_hWnd;//设置图标对应的窗口
m_tnid.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;//图标属性
m_tnid.uCallbackMessage=WM_ICON_NOTIFY;//应用程序定义的回调消息ID
CString szToolTip;
szToolTip=_T("HIPS -- 客户端程序");
_tcscpy(m_tnid.szTip, szToolTip);//帮助信息
m_tnid.uID=IDR_MAINFRAME;//应用程序图标
m_tnid.hIcon=m_hIcon;//图标句柄
PNOTIFYICONDATA m_ptnid=&m_tnid;
::Shell_NotifyIcon(NIM_ADD,m_ptnid);//增加图标到系统盘
GetDlgItem(IDOK)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
void CPopupClientDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
if(nID == SC_MINIMIZE)
{
ShowWindow(FALSE); //隐藏窗口
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CPopupClientDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CPopupClientDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CPopupClientDlg::OnButtonStop()
{
// TODO: Add your control notification handler code here
g_bToExitThread = TRUE;
if (g_hOverlappedEvent != NULL)
{
ResetEvent(g_hOverlappedEvent);
if (g_hReadThread != NULL)
{
if (WaitForSingleObject(g_hReadThread->m_hThread, 3000) == WAIT_TIMEOUT)
{
TerminateThread(g_hReadThread->m_hThread, 0);
}
delete g_hReadThread;
g_hReadThread = NULL;
}
CloseHandle(g_hOverlappedEvent);
g_hOverlappedEvent = NULL;
}
if (gh_Device != INVALID_HANDLE_VALUE)
{
CloseHandle(gh_Device);
gh_Device = INVALID_HANDLE_VALUE;
}
//UnloadDriver(DRIVER_NAME);
GetDlgItem(IDOK)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);
}
void CPopupClientDlg::OnOK()
{
// TODO: Add extra validation here
DWORD dwThreadID = 0;
g_bToExitThread = FALSE;
//加载驱动
BOOL bRet = LoadDriver(DRIVER_NAME,DRIVER_PATH);
if (!bRet)
{
MessageBox(_T("加载驱动失败"), _T("Error"), MB_OK);
return;
}
gh_Device = OpenDevice();
if (gh_Device == NULL)
{
MessageBox(_T("打开设备失败"), _T("Error"), MB_OK);
return;
}
g_hReadThread = AfxBeginThread(ReadThreadProc, this);
g_hReadThread->SuspendThread();
g_hReadThread->m_bAutoDelete = FALSE;
g_hReadThread->ResumeThread();
if (g_hReadThread == NULL)
{
CloseHandle(gh_Device);
gh_Device = INVALID_HANDLE_VALUE;
UnloadDriver(DRIVER_NAME);
return;
}
GetDlgItem(IDOK)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(TRUE);
}
LRESULT CPopupClientDlg::OnTrayNotification(WPARAM wParam, LPARAM lParam)
{
switch(lParam)
{
case WM_LBUTTONDOWN:
{
AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOWNORMAL);
SetForegroundWindow();
break;
}
case WM_RBUTTONUP:
{
POINT point;
HMENU hMenu, hSubMenu;
GetCursorPos(&point); //鼠标位置
hMenu = LoadMenu(NULL,
MAKEINTRESOURCE(IDR_MENU_TRAY)); // 加载菜单
hSubMenu = GetSubMenu(hMenu, 0);//得到子菜单(因为弹出式菜单是子菜单)
SetMenuDefaultItem(hSubMenu, -1, FALSE);//设置缺省菜单项,-1为无缺省项
SetForegroundWindow(); // 激活窗口并置前
TrackPopupMenu(hSubMenu, 0,
point.x, point.y, 0, m_hWnd, NULL);
}
}
return 1;
}
void CPopupClientDlg::OnClose()
{
NOTIFYICONDATA nd = {0};
nd.cbSize = sizeof(NOTIFYICONDATA);
nd.hWnd = m_hWnd;
nd.uID = IDR_MAINFRAME;
nd.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
nd.uCallbackMessage = WM_ICON_NOTIFY;
nd.hIcon = m_hIcon;
Shell_NotifyIcon(NIM_DELETE, &nd);
CDialog::OnCancel();
}
void CPopupClientDlg::OnMenuExit()
{
OnClose();
}
void CPopupClientDlg::OnMenuRestore()
{
ShowWindow(SW_SHOWNORMAL);
SetForegroundWindow();
}
void CPopupClientDlg::OnDestroy()
{
CDialog::OnDestroy();
}
void CPopupClientDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
OnOK();
}
[/code]
PopupDlg.cpp
// PopupDlg.cpp : implementation file
//
#include "stdafx.h"
#include "popupclient.h"
#include "opupDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CPopupDlg dialog
#define TIMER_ELAPSE_ID 1000
CPopupDlg::CPopupDlg(CWnd* pParent /*=NULL*/)
: CDialog(CPopupDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CPopupDlg)
m_edtDetail = _T("");
m_bAllow = 1;
m_szProcess = _T("");
m_szTime = _T("还剩: 30 秒");
//}}AFX_DATA_INIT
m_lefttime = 30;
}
void CPopupDlg:oDataExchange(CDataExchange* pDX)
{
CDialog:oDataExchange(pDX);
//{{AFX_DATA_MAP(CPopupDlg)
DDX_Text(pDX, IDC_EDIT_DETAIL, m_edtDetail);
DDX_Radio(pDX, IDC_RADIO_ALLOW, m_bAllow);
DDX_Text(pDX, IDC_STATIC_PROCESS, m_szProcess);
DDX_Text(pDX, IDC_STATIC_TIME, m_szTime);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPopupDlg, CDialog)
//{{AFX_MSG_MAP(CPopupDlg)
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CPopupDlg message handlers
void CPopupDlg::OnOK()
{
// TODO: Add extra validation here
KillTimer(TIMER_ELAPSE_ID);
CDialog::OnOK();
}
void CPopupDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case TIMER_ELAPSE_ID:
UpdateData(TRUE);
m_szTime.Format(_T("还剩: %2d 秒"), --m_lefttime);
UpdateData(FALSE);
if (m_lefttime == 0)
{
KillTimer(nIDEvent);
UpdateData(TRUE);
CDialog::OnOK();
}
break;
default:
break;
}
CDialog::OnTimer(nIDEvent);
}
BOOL CPopupDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
SetTimer(TIMER_ELAPSE_ID, 1*1000, NULL);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
VOID CPopupDlg::SetMyTimer(UINT lefttime)
{
m_lefttime = lefttime;
m_szTime = _T("还剩: 30 秒");
SetTimer(TIMER_ELAPSE_ID, 1*1000, NULL);
}
VOID CPopupDlg::SetDetail(LPCTSTR lpszDetail)
{
m_edtDetail = lpszDetail;
}
VOID CPopupDlg::SetProcess(LPCTSTR lpszProcess)
{
m_szProcess = lpszProcess;
}
[/code]
ioctlcmd.h
//IOCTL_CODE
#define IOCTL_SEND_RESULT_TO_R0 (ULONG) CTL_CODE(FILE_DEVICE_UNKNOWN, 0x8001, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_XXX_ATTACK (ULONG) CTL_CODE(FILE_DEVICE_UNKNOWN, 0x8002, METHOD_BUFFERED, FILE_ANY_ACCESS)
[/code]
R0:
main.h
#define MAX_PATH 260
typedef ULONG DWORD;
#pragma warning(disable:4996)
typedef struct _OP_INFO
{
WCHAR m_ProcessName[MAX_PATH];
DWORD m_ulProcessID;
ULONG m_ulWaitID;
LIST_ENTRY m_List;
} OP_INFO, *POP_INFO;
typedef struct _RING3_OP_INFO
{
WCHAR m_ProcessName[MAX_PATH];
DWORD m_ulProcessID;
ULONG m_ulWaitID;
} RING3_OP_INFO, *PRING3_OP_INFO;
typedef struct _RING3_REPLY
{
ULONG m_ulWaitID;
ULONG m_ulBlocked;
}RING3_REPLY;
typedef struct _WAIT_LIST_ENTRY
{
LIST_ENTRY m_List;
ULONG m_ulWaitID;
KEVENT m_ulWaitEvent;
ULONG m_bBlocked;
}WAIT_LIST_ENTRY;
typedef enum _R3_RESULT
{
R3Result_Pass,
R3Result_Block,
R3Result_DefaultNon,
}R3_RESULT;
[/code]
main.c
//author tomzhou
//email:soundfuture@sohu.com
#include <ntddk.h>
#include "Ioctlcmd.h"
#include "main.h"
#define DEVICE_NAME L"\\device\\PopupDrv"
#define LINK_NAME L"\\dosDevices\\PopupDrv"
LIST_ENTRY g_OperList;
ERESOURCE g_OperListLock;
LIST_ENTRY g_WaitList;
ERESOURCE g_WaitListLock;
LIST_ENTRY g_PendingIrpList;
ERESOURCE g_PendingIrpListLock;
ULONG g_ulCurrentWaitID = 0;
VOID __stdcall LockWrite(ERESOURCE *lpLock)
{
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(lpLock, TRUE);
}
VOID __stdcall UnLockWrite(ERESOURCE *lpLock)
{
ExReleaseResourceLite(lpLock);
KeLeaveCriticalRegion();
}
VOID __stdcall LockRead(ERESOURCE *lpLock)
{
KeEnterCriticalRegion();
ExAcquireResourceSharedLite(lpLock, TRUE);
}
VOID __stdcall LockReadStarveWriter(ERESOURCE *lpLock)
{
KeEnterCriticalRegion();
ExAcquireSharedStarveExclusive(lpLock, TRUE);
}
VOID __stdcall UnLockRead(ERESOURCE *lpLock)
{
ExReleaseResourceLite(lpLock);
KeLeaveCriticalRegion();
}
VOID __stdcall InitLock(ERESOURCE *lpLock)
{
ExInitializeResourceLite(lpLock);
}
VOID __stdcall DeleteLock(ERESOURCE *lpLock)
{
ExDeleteResourceLite(lpLock);
}
VOID __stdcall InitList(LIST_ENTRY *list)
{
InitializeListHead(list);
}
VOID
CommonIrpCancel(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KIRQL CancelOldIrql = Irp->CancelIrql;
IoReleaseCancelSpinLock(DISPATCH_LEVEL);
KeLowerIrql(CancelOldIrql);
LockWrite(&g_PendingIrpListLock);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
UnLockWrite(&g_PendingIrpListLock);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
VOID
PendingIrpToList(PIRP pIrp, PLIST_ENTRY pIrpList, PDRIVER_CANCEL pfnCancelRoutine)
{
InsertTailList(pIrpList, &pIrp->Tail.Overlay.ListEntry);
IoMarkIrpPending(pIrp);
IoSetCancelRoutine(pIrp, pfnCancelRoutine);
}
//处理应用层的read()函数
NTSTATUS DispatchRead (
IN PDEVICE_OBJECT pDevObj,
IN PIRP lpIrp)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG ulLength = 0;
PIO_STACK_LOCATION lpIrpStack = IoGetCurrentIrpStackLocation(lpIrp);
OP_INFO *lpOpInfoEntry = NULL;
LIST_ENTRY *lpOpInfoList = NULL;
//如果读的len小于这个结构 就返回无效的
if (lpIrpStack->arameters.Read.Length < sizeof(RING3_OP_INFO))
{
ntStatus = STATUS_INVALID_PARAMETER;
ulLength = 0;
goto Completed;
}
//先锁定Write
LockWrite(&g_OperListLock);
//如果是空的链表 将这次的IRP放入Pending链表 就是如果没有消息 就将这次的请求保存起来 等有了在给它
//当这个IRP被处理时调用CommonIrpCancel这个函数 通知R3这个IRP被处理了
if (IsListEmpty(&g_OperList) == TRUE)
{
UnLockWrite(&g_OperListLock);
LockWrite(&g_PendingIrpListLock);
PendingIrpToList(lpIrp, &g_PendingIrpList, CommonIrpCancel);
UnLockWrite(&g_PendingIrpListLock);
goto Pended;
}
//处理第一个节
lpOpInfoList = g_OperList.Flink;
//获得Entry头
lpOpInfoEntry = CONTAINING_RECORD(lpOpInfoList, OP_INFO, m_List);
//移除这个节点
RemoveEntryList(lpOpInfoList);
UnLockWrite(&g_OperListLock);
//将链表的信息窗给R3
RtlCopyMemory(lpIrp->AssociatedIrp.SystemBuffer, lpOpInfoEntry, sizeof(RING3_OP_INFO));
ntStatus = STATUS_SUCCESS;
ulLength = sizeof(RING3_OP_INFO);
ExFreePool(lpOpInfoEntry);
Completed:
lpIrp->IoStatus.Status = ntStatus;
lpIrp->IoStatus.Information = ulLength;
IoCompleteRequest(lpIrp, IO_NO_INCREMENT);
return ntStatus;
Pended:
return STATUS_PENDING;
}
WAIT_LIST_ENTRY*
FindWaitEntryByID(PLIST_ENTRY pListHead, ULONG ulWaitID)
{
PLIST_ENTRY pList = NULL;
WAIT_LIST_ENTRY *pEntry = NULL;
for (pList = pListHead->Flink; pList != pListHead; pList = pList->Flink)
{
pEntry = CONTAINING_RECORD(pList, WAIT_LIST_ENTRY, m_List);
if (pEntry->m_ulWaitID == ulWaitID)
{
return pEntry;
}
}
return NULL;
}
ULONG MakeWaitID()
{
InterlockedIncrement(&g_ulCurrentWaitID);
return g_ulCurrentWaitID;
}
BOOLEAN
CompletePendingIrp(LIST_ENTRY* pIrpListHead, OP_INFO* pOpInfo)
{
LIST_ENTRY *lpIrpList = NULL;
PIRP lpIrp = NULL;
BOOLEAN bFound = FALSE;
BOOLEAN bReturn = FALSE;
if (IsListEmpty(pIrpListHead) == TRUE)
{
return bReturn;
}
for (lpIrpList = pIrpListHead->Flink; lpIrpList != pIrpListHead; lpIrpList = lpIrpList->Flink)
{
lpIrp = CONTAINING_RECORD(lpIrpList, IRP, Tail.Overlay.ListEntry);
if (IoSetCancelRoutine(lpIrp, NULL))//每一个IRP都可以对应一个取消例程 函数把IRP与取消例程进行关联,当要删除取消例程时,把第二个参数设为空即可
{
//遍历删除 如果删除失败就不是这个IRP的取消例程 如果删除成功就说明是这个IRP的取消例程
RemoveEntryList(lpIrpList);
bFound = TRUE;
break;
}
}
if (bFound == FALSE)
{
return bReturn;
}
RtlCopyMemory(lpIrp->AssociatedIrp.SystemBuffer, pOpInfo, sizeof(RING3_OP_INFO));
lpIrp->IoStatus.Information = sizeof(RING3_OP_INFO);
lpIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(lpIrp, IO_NO_INCREMENT);
bReturn = TRUE;
return bReturn;
}
R3_RESULT __stdcall GetResultFromUser()
{
R3_RESULT NotifyResult = R3Result_Pass;
BOOLEAN bSuccess = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
LARGE_INTEGER WaitTimeOut = {0};
OP_INFO *lpNewOpInfo = NULL;
WAIT_LIST_ENTRY *lpNewWaitEntry = NULL;
ULONG_PTR ulPtr = 0;
lpNewOpInfo = (OP_INFO*)ExAllocatePool(PagedPool, sizeof(OP_INFO));
if (lpNewOpInfo == NULL)
{
return NotifyResult;
}
//设置事件相关的数据,发送给R3,比如进程ID,名字,路径,以及具体操作(创建,修改,删除)等等
//当然,这里,我们只是简单的捕捉了进程的ID或者名字等
ulPtr = (ULONG_PTR)PsGetCurrentProcessId();
lpNewOpInfo->m_ulProcessID = (ULONG_PTR)ulPtr;
lpNewOpInfo->m_ulWaitID = MakeWaitID();//区别不同事件的ID
lpNewWaitEntry = (WAIT_LIST_ENTRY*)ExAllocatePool(NonPagedPool, sizeof(WAIT_LIST_ENTRY));
if (lpNewWaitEntry == NULL)
{
goto End;
}
lpNewWaitEntry->m_ulWaitID = lpNewOpInfo->m_ulWaitID;
KeInitializeEvent(&lpNewWaitEntry->m_ulWaitEvent, SynchronizationEvent, FALSE);
// 插入等待队列,等待R3下发结果
LockWrite(&g_WaitListLock);
InsertTailList(&g_WaitList, &lpNewWaitEntry->m_List);
UnLockWrite(&g_WaitListLock);
LockWrite(&g_PendingIrpListLock);
bSuccess = CompletePendingIrp(&g_PendingIrpList, lpNewOpInfo);//查看是否有未完成的pendingIRP,直接将该OperInfo传给R3
UnLockWrite(&g_PendingIrpListLock);
if (bSuccess == FALSE) //完成pending irp失败,将lpNewOpInfo插入operlist
{
LockWrite(&g_OperListLock);
InsertTailList(&g_OperList, &lpNewOpInfo->m_List); //插入OperList,等待R3来读取
UnLockWrite(&g_OperListLock);
lpNewOpInfo = NULL;
}
// 等40秒,环3是30秒超时
WaitTimeOut.QuadPart = -40 * 10000000;
Status = KeWaitForSingleObject(&lpNewWaitEntry->m_ulWaitEvent,
Executive, KernelMode, FALSE, &WaitTimeOut);//等待R3下发允许或阻止操作
LockWrite(&g_WaitListLock);
RemoveEntryList(&lpNewWaitEntry->m_List);
UnLockWrite(&g_WaitListLock);
if (Status != STATUS_TIMEOUT)
{
if (lpNewWaitEntry->m_bBlocked == TRUE)
{
NotifyResult = R3Result_Block;
}
else
{
NotifyResult = R3Result_Pass;
}
}
else
{
NotifyResult = R3Result_DefaultNon;
}
End:
if (lpNewWaitEntry != NULL)
{
ExFreePool(lpNewWaitEntry);
}
if (lpNewOpInfo != NULL)
{
ExFreePool(lpNewOpInfo);
}
return NotifyResult;
}
//处理应用层的DeviceIoControl()
NTSTATUS DispatchControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION lpIrpStack = NULL;
PVOID inputBuffer = NULL;
PVOID outputBuffer = NULL;
ULONG inputBufferLength = 0;
ULONG outputBufferLength = 0;
ULONG ioControlCode = 0;
NTSTATUS ntStatus = STATUS_SUCCESS;
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//获取当前IRP堆栈位置
lpIrpStack = IoGetCurrentIrpStackLocation (Irp);
//获得输入缓冲和长度
inputBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = lpIrpStack->arameters.DeviceIoControl.InputBufferLength;
//获得输出缓冲和长度
outputBuffer = Irp->AssociatedIrp.SystemBuffer;
outputBufferLength = lpIrpStack->arameters.DeviceIoControl.OutputBufferLength;
//获取控制码
ioControlCode = lpIrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode )
{
case IOCTL_SEND_RESULT_TO_R0://R3向内核传递弹窗结果,将对应的WaitID事件设置用户选择结果
{
RING3_REPLY *lpReply = NULL;
WAIT_LIST_ENTRY *lpWaitEntry = NULL;
if (lpIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(RING3_REPLY))
{
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
break;
}
lpReply = (RING3_REPLY*)Irp->AssociatedIrp.SystemBuffer;
LockWrite(&g_WaitListLock);
lpWaitEntry = FindWaitEntryByID(&g_WaitList, lpReply->m_ulWaitID);//根据WaitID,找到对应的拦截事件
if (lpWaitEntry != NULL)
{
lpWaitEntry->m_bBlocked = lpReply->m_ulBlocked;
KeSetEvent(&lpWaitEntry->m_ulWaitEvent, 0, FALSE);//设置EVENT事件,唤醒GetResultFromUser()里的等待事件
}
UnLockWrite(&g_WaitListLock);
Irp->IoStatus.Information = 0;
ntStatus = Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_XXX_ATTACK://攻击拦截模仿
{
R3_RESULT notifyResult = R3Result_DefaultNon;
notifyResult = GetResultFromUser();//从R3获得弹框结果,是阻止还是放过
if (notifyResult == R3Result_Block)
{
DbgPrint("阻止\n");
*(ULONG *)outputBuffer = 0;
ntStatus = STATUS_SUCCESS;
}
else if (notifyResult == R3Result_Pass)
{
DbgPrint("允许\n");
*(ULONG *)outputBuffer = 1;
ntStatus = STATUS_SUCCESS;
}
else
{
DbgPrint("超时允许\n");
*(ULONG *)outputBuffer = 1;
ntStatus = STATUS_SUCCESS;
}
}
Irp->IoStatus.Information = sizeof(ULONG);
Irp->IoStatus.Status = ntStatus;
break;
default:
break;
}
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return ntStatus;
}
//驱动Unload()函数
VOID DriverUnload (
IN PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING deviceLink = {0};
RtlInitUnicodeString( &deviceLink, LINK_NAME);
IoDeleteSymbolicLink( &deviceLink);
IoDeleteDevice( pDriverObject->DeviceObject );
return;
}
//处理应用层的create()函数
NTSTATUS DispatchCreate (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
//设置IO状态信息
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
//完成IRP操作,不向下层驱动发送
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
//处理应用层的close()函数
NTSTATUS DispatchClose (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
//驱动程序入口,完成各种初始化工作,创建设备对象
NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT pDevObj = NULL;
UNICODE_STRING uDevName = {0};
UNICODE_STRING uLinkName = {0};
DbgPrint("Driver Load begin!\n");
InitLock(&g_OperListLock);
InitLock(&g_WaitListLock);
InitLock(&g_PendingIrpListLock);
InitList(&g_OperList);
InitList(&g_WaitList);
InitList(&g_PendingIrpList);
//初始化各个例程
pDriverObject->MajorFunction[IRP_MJ_CREATE] =
DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] =
DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_READ] =
DispatchRead;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DispatchControl;
pDriverObject->DriverUnload =
DriverUnload;
RtlInitUnicodeString(&uDevName, DEVICE_NAME);
//创建驱动设备
status = IoCreateDevice( pDriverObject,
0,//sizeof(DEVICE_EXTENSION)
&uDevName,
FILE_DEVICE_UNKNOWN,
0, FALSE,
&pDevObj );
if (!NT_SUCCESS(status))
{
DbgPrint("IoCreateDevice Failed:%x\n", status);
return status;
}
pDevObj->Flags |= DO_BUFFERED_IO;
RtlInitUnicodeString(&uLinkName, LINK_NAME);
//创建符号链接
status = IoCreateSymbolicLink( &uLinkName, &uDevName );
if (!NT_SUCCESS(status))
{
//STATUS_INSUFFICIENT_RESOURCES 资源不足
//STATUS_OBJECT_NAME_EXISTS 指定对象名存在
//STATUS_OBJECT_NAME_COLLISION 对象名有冲突
DbgPrint("IoCreateSymbolicLink Failed:%x\n", status);
IoDeleteDevice( pDevObj );
return status;
}
DbgPrint("Driver Load success!\n");
return status;
}
[/code]
关于异步 同步 可以参考下面这篇文章
http://www.blogfshare.com/irp-synchronization-asynchronous.html |
|