看流星社区

 找回密码
 注册账号
查看: 2100|回复: 0

HIPS实现

[复制链接]

该用户从未签到

发表于 2017-6-1 13:33:56 | 显示全部楼层 |阅读模式
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-&gtarameters.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-&gtarameters.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 &quotopupClient.h"
#include &quotopupClientDlg.h"


#include "ioctlcmd.h"
#include <shlwapi.h>
#include &quotopupDlg.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(&quotopupDrv")
#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 &quotopupDlg.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-&gtarameters.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-&gtarameters.DeviceIoControl.InputBufferLength;
        //获得输出缓冲和长度
        outputBuffer = Irp->AssociatedIrp.SystemBuffer;
        outputBufferLength = lpIrpStack-&gtarameters.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
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-3-19 10:31

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表