弹窗有没有可以拦截别人短信的软件软件哪个好 推荐几款实用的弹窗有没有可以拦截别人短信的软件软件?

本公众号分享的所有技术仅用于学习交流,请勿用于其他非法活动,如有错漏,欢迎留言交流指正拦截,弹窗应用场景:假设系统中了勒索病毒,开始加密整个磁盘,这时候内核监控到并拦截(Hook,驱动过滤,回调)了这些操作,进行数据收集弹窗给用户等待处理。弹窗整体思路驱动截获攻击操作,进行数据收集驱动为了拿到应用处理完弹窗的返回的结果,建立一个WaitList(等待链表,结点包括一个标识ID(用来区分攻击事件),一个event,一个等待结果的域),通过WaitList上等待应用层处理弹窗的结果。驱动为了把收集数据传给应用层,建立一个OperList(操作链表,进程Pid,进程全路径,目标对象等), 建立一个PendingIrpList来应对OperList为空情况。把收集数据存为一个结构体放在OperList,传给应用。或者优先满足PendingIrpList的Irp。 如果此时有内容可读(链表不为空),则该独立线程向驱动发出一个读Irp来读取OperList一个结点的数据,弹出一个弹窗提示用户(比如某某进程正在往system32释放DLL文件)并倒计时等待用户操作,对弹窗处理的结果通过DeviceIoControl返回给驱动,把结果存放在WaitList里面,结点上的事件就会通知驱动来拿数据,驱动从WaitList拿到结果做出相应操作(阻止/执行某个进程的操作)如果此时没有内容可读(链表为空,系统比较健康,攻击事件比较少),则该独立线程向驱动发出的读Irp会被挂起,放在PendingIrpList中,当下次驱动截获到攻击操作的时候,不会把收集数据存为一个结构体放在OperList,而是会直接把收集的数据直接给PendingIrpList的Irp(此时PendingIrpList不为空,优先满足挂起的Irp请求),弹出一个弹窗提示用户(比如某某进程正在往system32释放DLL文件)并倒计时等待用户操作,对弹窗处理的结果通过DeviceIoControl返回给驱动,把结果存放在WaitList里面,结点上的事件就会通知驱动来拿数据,驱动从WaitList拿到结果做出相应操作(阻止/运行某个进程的操作)驱动拿到用户操作结果做出相应的动作。应用层开一个独立线程去异步读出(overlapped)驱动中OperList中的内容实战驱动流程: 1.驱动截获到攻击(在驱动IOCTL分发函数中(IOCTL_XXX_ATTACK)),生成一个WaitList结点插入等待队列,等待R3下发结果,收集信息放到一个结构体中,查看是否有未完成的pendingIRP,如果有,直接将该OperInfo传给R3;否则插入OperList,等待R3来读取2.应用层通过DipatchRead()读取R0的数据,如果为空,就把当前读Irp放到PendingIrpList中去,并注册一个CommonIrpCancel函数;不为空,直接读取数据3.在驱动IOCTL分发函数中(IOCTL_SEND_RESULT_TO_R0),将用户结果放入链表WaitList中同WaitID的结构体中,设置EVENT事件,唤醒内核层GetResultFromUser()里的等待事件4.驱动拿到用户操作结果,摘掉链表中的结点,并获取操作中的结果5.驱动根据操作结果判断是否允许或者阻止,下发结果#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; ///< Irp挂起链表
ERESOURCE
g_PendingIrpListLock; ///< 保护全局资源的读写锁共享锁,允许多人读,一个人写
ERESOURCE
g_GetResultFromUserLock; ///< 保护全局资源的读写锁共享锁,允许多人读,一个人写
ULONG g_ulCurrentWaitID = 0; ///< Student 当前攻击事件的ID
/// __stdcall表示 1.参数从右向左压入堆栈 2.函数被调用者负责栈平衡
/// 拿写锁
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);
}
/// 以让等待读优先的方式去拿写锁,StarveWriter,使写进程饥饿
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);
}
/// 用来取消Irp的例程
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的执行状态设置成STATUS_CANCELLED
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
/// 将Irp挂起,并为Irp注册一个CommonIrpCancel
VOID PendingIrpToList(PIRP pIrp, PLIST_ENTRY pIrpList, PDRIVER_CANCEL pfnCancelRoutine)
{
InsertTailList(pIrpList, &pIrp->Tail.Overlay.ListEntry); //把Irp插入到PendingIrpToList
IoMarkIrpPending(pIrp); //把Irp标记成pending状态
/// //为Irp设置一个CancelRoutine回调函数,R3调用CancelIo(handle)会触发CancelRoutine例程(假设Irp一直没有得到满足,直到客户端退出或者系统关机了还没有拿到数据,这时候只能把Irp取消掉,不然系统可能会蓝屏)
//CancelIo from r3
or IoCancelIrp to call
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;
/// 做一个简单的参数判断,读的数据长度
if (lpIrpStack->Parameters.Read.Length < sizeof(RING3_OP_INFO))
{
ntStatus = STATUS_INVALID_PARAMETER;
ulLength = 0;
goto Completed;
}
LockWrite(&g_OperListLock);
/// 如果为空,就把当前读Irp放到PendingIrpList中去,并注册一个CommonIrpCancel函数,
if (IsListEmpty(&g_OperList) == TRUE)
{
UnLockWrite(&g_OperListLock);
LockWrite(&g_PendingIrpListLock);
PendingIrpToList(lpIrp, &g_PendingIrpList, CommonIrpCancel); //将Irp挂起,并为Irp注册一个CommonIrpCancel
UnLockWrite(&g_PendingIrpListLock);
goto Pended;
}
/// 不为空,直接读取数据
lpOpInfoList = g_OperList.Flink;
lpOpInfoEntry = CONTAINING_RECORD(lpOpInfoList, OP_INFO, m_List); //拿到一个结点
RemoveEntryList(lpOpInfoList);
UnLockWrite(&g_OperListLock);
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;
}
/// @brief
MakeWaitID 用来创建一个WaitID,用来区分攻击事件;
/// @return
ULONG 返回WaitID,4个字节
ULONG MakeWaitID()
{
InterlockedIncrement(&g_ulCurrentWaitID); //原子操作,对全局变量+1。
return g_ulCurrentWaitID;
}
BOOLEAN
CompletePendingIrp(LIST_ENTRY* pIrpListHead, OP_INFO* pOpInfo)
{
LIST_ENTRY* lpIrpList = NULL;
PIRP
lpIrp = NULL;
BOOLEAN
bFound = FALSE;
BOOLEAN
bReturn = FALSE;
/// 如果PendingIrpList为空,即当前没有读Irp在等待
if (IsListEmpty(pIrpListHead) == TRUE)
{
return bReturn;
}
/// 找到Irp
for (lpIrpList = pIrpListHead->Flink; lpIrpList != pIrpListHead; lpIrpList = lpIrpList->Flink)
{
lpIrp = CONTAINING_RECORD(lpIrpList, IRP, Tail.Overlay.ListEntry); //拿到一个结点
if (IoSetCancelRoutine(lpIrp, NULL)) //把当前Irp设置成NULL并且returns the previous value of Irp->CancelRoutine(在Irp被取消的时候被调用(程序退出,系统重启等),如果注册了CancelRoutine则是之前被挂起Irp). no Cancel routine, or cancellation in progress, returns NULL.
{
RemoveEntryList(lpIrpList);
bFound = TRUE;
break;
}
}
if (bFound == FALSE)
{
return bReturn;
}
/// 把OperList结点的数据copy到pIrp->AssociatedIrp.SystemBuffer,进程就可以拿到数据了
RtlCopyMemory(lpIrp->AssociatedIrp.SystemBuffer, pOpInfo, sizeof(RING3_OP_INFO)); //只拷贝进程全路径,进程PID,攻击事件ID,
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;
LockWrite(&g_GetResultFromUserLock);
/// 生成一个结点,是个OP_INFO结构体,存放进程的名字,进程的PID,攻击事件的ID,前面三个数据放在LIST_ENTRY之前是为了方便拷贝数据
lpNewOpInfo = (OP_INFO*)ExAllocatePool(PagedPool, sizeof(OP_INFO));
/// memset(lpNewOpInfo, 0, sizeof(OP_INFO));
if (lpNewOpInfo == NULL)
{
UnLockWrite(&g_GetResultFromUserLock);
return NotifyResult;
}
/// 设置事件相关的数据,发送给R3,比如进程ID,名字,路径,以及具体操作(创建,修改,删除)等等
/// 这里只是简单的捕捉了进程的ID或者名字
ulPtr = (ULONG_PTR)PsGetCurrentProcessId();
lpNewOpInfo->m_ulProcessID = (ULONG_PTR)ulPtr;
/// @todo 通过进程pid拿到进程路径,需要完善
lpNewOpInfo->m_ulWaitID = MakeWaitID(); //生成WatitID,用来区别不同事件的ID
/// 生成Wait结点,WaitID,WaitEvent(用来同步,当应用层把弹窗结果放在Blocked之后,设置成有信号状态,驱动就通过这个信号,知道应用层已经发结果下来了,就去WaitList上拿结果)
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失败(当前没有读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); //把当前WaitList结点摘除
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);
}
UnLockWrite(&g_GetResultFromUserLock);
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->Parameters.DeviceIoControl.InputBufferLength;
//获得输出缓冲和长度
outputBuffer = Irp->AssociatedIrp.SystemBuffer;
outputBufferLength = lpIrpStack->Parameters.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;
}
/// RING3_REPLY结构体包含WaitID和Blocked这两个成员
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; //将对应的WaitList结点设置成用户选择结果
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;
//LockWrite(&g_GetResultFromUserLock); //最好是在函数内部。除非你在任何调用这个函数的地方都加锁
//KeEnterCriticalRegion(); //改成串行
notifyResult = GetResultFromUser();//这里最长会等待40s,收集数据封装成一个结构体结点,放在OperList或者满足PendingIrpList中等待的Irp,从R3获得弹框结果,是阻止还是放过
//KeLeaveCriticalRegion();
//UnLockWrite(&g_GetResultFromUserLock);
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);
DeleteLock(&g_GetResultFromUserLock);
DeleteLock(&g_OperListLock);
DeleteLock(&g_WaitListLock);
DeleteLock(&g_PendingIrpListLock);
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);
InitLock(&g_GetResultFromUserLock);
/// 初始化链表
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;//read operlist data
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
DispatchControl;//get r3 result&attack
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;
}
应用流程 1.加载驱动2.打开设备3.新建一个读线程,如果有数据读出来弹窗,如果没有数据可读则等待// PopupClientDlg.cpp : implementation file
//
#include "stdafx.h"
#include "PopupClient.h"
#include "PopupClientDlg.h"
#include "ioctlcmd.h"
#include <shlwapi.h>
#include "PopupDlg.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("PopupDrv")
#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, //这里要传入FILE_FLAG_OVERAPPED才是真正异步读
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;
::DeviceIoControl(gh_Device, IOCTL_SEND_RESULT_TO_R0, &R3Reply, sizeof(R3_REPLY), NULL, 0, &ulRet, NULL); //把R3弹窗处理的结果返回给R0
return;
}
BOOL HandleData(OP_INFO *pOpInfoData)
{
CPopupDlg dlg;
dlg.SetProcess(pOpInfoData->m_ProcessName); //进程名字
dlg.SetDetail(_T("有进程正在非法攻击")); //弹窗
dlg.DoModal(); //倒计时30s
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); //把弹窗结果返回给Ro0
}
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::DoDataExchange(CDataExchange * pDX)
{
CDialog::DoDataExchange(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::DoDataExchange(CDataExchange * pDX)
{
CDialog::DoDataExchange(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();
}
模拟攻击者向驱动发送一个IOCTL_XXX_ATTACK控制码// attacker.cpp : Defines the entry point for the console application.
//
#include "StdAfx.h"
#include <windows.h>
#include <winsvc.h>
#include <conio.h>
#include <stdio.h>
#include <winioctl.h>
#define DRIVER_NAME "PopupDrv"
#define DRIVER_PATH ".\\PopupDrv.sys"
#define IOCTL_BASE 0x800
#define MY_CTL_CODE(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTL_BASE + i, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_XXX_ATTACK MY_CTL_CODE(2)
//装载NT驱动程序
BOOL LoadDriver(char *lpszDriverName, char *lpszDriverPath)
{
char 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(char *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:DeleteSrevice() ok !\n");
}
bRet = TRUE;
BeforeLeave:
//离开前关闭打开的句柄
if (hServiceDDK)
{
CloseServiceHandle(hServiceDDK);
}
if (hServiceMgr)
{
CloseServiceHandle(hServiceMgr);
}
return bRet;
}
void TestDriver()
{
//测试驱动程序
HANDLE hDevice = CreateFile("\\\\.\\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 failed %d ! \n", GetLastError());
return;
}
CHAR bufInput[1024] = "Hello, world";
DWORD dwAttackRes = 0;
DWORD dwRet = 0;
printf("Begin to attack\n");
/// 得到的设备对象,通过DeviceIoControl发送一个控制码,模拟攻击
DeviceIoControl(hDevice, IOCTL_XXX_ATTACK, bufInput, sizeof(bufInput), &dwAttackRes, sizeof(dwAttackRes), &dwRet, NULL);
if (dwAttackRes == 0)
{
printf("Attack denied\n");
}
else
{
printf("Attack OK\n");
}
CloseHandle(hDevice);
}
int main(int argc, char *argv[])
{
//加载驱动
BOOL bRet = LoadDriver(DRIVER_NAME, DRIVER_PATH);
if (!bRet)
{
printf("LoadNTDriver error\n");
return 0;
}
//加载成功
// printf( "press any to create device!\n" );
// getch();
TestDriver();
//这时候你可以通过注册表,或其他查看符号连接的软件验证.
// printf( "press any to unload the driver!\n" );
// getch();
//卸载驱动
//
bRet = UnloadDriver(DRIVER_NAME);
//
if (!bRet)
//
{
//
printf("UnloadNTDriver error\n");
//
return 0;
//
}
return 0;
}
弹窗程序待完善的问题1.超时问题同时模拟两个攻击(几乎同时运行两个attcker.exe),对GetResultFromUserLock()加了锁后,驱动中调用GetResultFromUser()应该是串行的,第一个弹窗倒计时30s后,自动关闭,attcker.exe退出,第二弹窗开始倒计时也需要倒计时满30s后,atccker.exe才退出原因内核层程序是支持多线程并发的(可以同时(并发不是并行)拦截多个攻击事件)应用层程序只有一个线程处理假设内核层同时监测到3个攻击,发给应用层,每个攻击同时等待40s,应用层只有一个线程,只能依次把攻击事件弹窗,倒计时30s。这时候用户可能在第一个30s内只处理完第一弹窗的话,30s过后第2、3个攻击事件可能来不及弹窗,因为超时都消失了,用户来不及处理。解决方法方法1:应用层改为多线程,当内核层在很短时间间隔内截获较多攻击事件,应用层为每个攻击事件单独开一个线程来弹窗处理,但这样会导致短时间内较多弹窗,用户体验不佳方法2:将内核层发送攻击事件改为串行的 方式1:把攻击事件加到队列方式2:把GetResultFromUser()设为临界区,这样一次只能有一个线程调用GetResultFromUser()/// 加放锁放入函数内部
//LockWrite(&g_GetResultFromUserLock); //最好是在函数内部。除非你在任何调用这个函数的地方都加锁
//KeEnterCriticalRegion(); //改成串行
notifyResult = GetResultFromUser();//这里最长会等待40s,收集数据封装成一个结构体结点,放在OperList或者满足PendingIrpList中等待的Irp,从R3获得弹框结果,是阻止还是放过
//KeLeaveCriticalRegion();
//UnLockWrite(&g_GetResultFromUserLock);
@todo 共享资源锁并没有生效,还需要用windbg R3-R0联调一下2.不是真正异步读原因CreateFile()倒数第二个参数是0异步编程:线程在调用函数的时候,不管这个函数有没有拿到数据,会立即返回,后面通过回调函数或者是事件机制来拿到函数执行的结果。异步比同步效率要高。同步编程:线程在调用函数的时候,只要这个函数没有拿到数据,就一直在哪里等待,不会立即返回,直到拿到数据才会返回。eg:A在微信上向女盆友B发消息之后,A去做其他事情了,B给A回消息,会有消息声音提醒A,A打开微信拿到B回复的消息eg1:完成端口模型同步阻塞编程(Block)基于锁的(lock-based)阻塞的意思是,会睡眠让出CPU,有结果的时候就会被唤醒,一般用于读之前不确定有没有结果数据,使用阻塞比较好。eg:A在微信上向女盆友B发消息之后,A抱着手机睡着了,直到B给A回消息,会有消息声音吵醒A,A醒来打开微信拿到B回复的消息同步非阻塞编程(Non-blocking Synchronization) :根据粒度不同分为以下几类非阻塞的意思是,不会睡眠,一直在等,直到拿到结果,一般用于读之前明确知道的是有结果数据的,而且很快能拿到结果。 eg:女盆友B在微信上向A发消息之前确定A是在线的,B发完消息后,A秒回B,B直接看到到A回复的消息eg1:网络中的select模型、epoll模型,多路复用,多个IO复用同一个Event,只有Event会阻塞,读写不会阻塞解决方法CreateFile()倒数第二个参数设置成FILE_FLAG_OVERAPPEDHANDLE OpenDevice()
{
//测试驱动程序
HANDLE hDevice = CreateFile(_T("\\\\.\\PopupDrv"),
GENERIC_WRITE
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0, //这里要传入FILE_FLAG_OVERAPPED才是真正异步读
NULL);
if (hDevice != INVALID_HANDLE_VALUE)
{
printf("Create Device ok ! \n");
}
else
{
printf("Create Device faild %d ! \n", GetLastError());
return NULL;
}
return hDevice;
}
3.获取攻击进程的全路径还没完成根据PID获得进程全路径思路根据PID获得进程全路径 PID→exprocess→KeStackAttachProcess→ZwQuerylnformationProcess->ProcesslmageFileName→ZwCreateFile设备对象名转换成符号链接名 ->ObReferenceObjectByHandle→RtIVolumeDeviceToDosName->ZwQuerylnformationFile实战/**
*
@brief
GetProcessFullNameByPid 获取进程的全路径;
*
@param[in]
nPid 进程pid;
*
@param[out]
FullPath 进程的全路径;
*
@return
ntStatus 成功返回0,否则为非0,如果例程成功,则它必须返回 STATUS_SUCCESS。
*
否则,它必须返回在 ntstatus中定义的错误状态值之一;
*/
NTSTATUS GetProcessFullNameByPid(HANDLE nPid, PUNICODE_STRING FullPath)
{
HANDLE hFile = NULL;
ULONG nNeedSize = 0;
NTSTATUS nStatus = STATUS_SUCCESS;
NTSTATUS nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST;
PEPROCESS Process = NULL;
KAPC_STATE ApcState = { 0 };
PVOID lpBuffer = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
IO_STATUS_BLOCK IoStatus = { 0 };
PFILE_OBJECT FileObject = NULL;
PFILE_NAME_INFORMATION FileName = NULL;
WCHAR FileBuffer[MAX_PATH] = { 0 };
DECLARE_UNICODE_STRING_SIZE(ProcessPath, MAX_PATH);
DECLARE_UNICODE_STRING_SIZE(DosDeviceName, MAX_PATH);
PAGED_CODE();
/// 通过pid拿到进程的eprocess结构
nStatus = PsLookupProcessByProcessId(nPid, &Process);
if (NT_ERROR(nStatus))
{
KdPrint(("%s error PsLookupProcessByProcessId.\n", __FUNCTION__));
return nStatus;
}
__try
{
/// 切换到当前进程的上下文
KeStackAttachProcess(Process, &ApcState);
nStatus = ZwQueryInformationProcess(
NtCurrentProcess(),
ProcessImageFileName,
NULL,
NULL, //第一次传NULL是为了获取进程路径的大小
&nNeedSize);
if (STATUS_INFO_LENGTH_MISMATCH != nStatus)
{
KdPrint(("%s NtQueryInformationProcess error.\n", __FUNCTION__));
nStatus = STATUS_MEMORY_NOT_ALLOCATED;
__leave;
}
/// 分配一个内存来存放进程的全路径
lpBuffer = ExAllocatePoolWithTag(NonPagedPool, nNeedSize, 'GetP');
if (lpBuffer == NULL)
{
KdPrint(("%s ExAllocatePoolWithTag error.\n", __FUNCTION__));
nStatus = STATUS_MEMORY_NOT_ALLOCATED;
__leave;
}
nStatus = ZwQueryInformationProcess(
NtCurrentProcess(),
ProcessImageFileName,
lpBuffer, //在查询一遍就获得进程的全路径了
nNeedSize,
&nNeedSize);
if (NT_ERROR(nStatus))
{
KdPrint(("%s NtQueryInformationProcess error2.\n", __FUNCTION__));
__leave;
}
//获得的路径是\device\harddiskvolume3\program files\qq.exe这种格式,需要转化成用户熟悉的盘符
//\??\c:\program files\qq.exe
RtlCopyUnicodeString(&ProcessPath, (PUNICODE_STRING)lpBuffer);
InitializeObjectAttributes(
&ObjectAttributes,
&ProcessPath,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/// 打开路径得到handle
nStatus = ZwCreateFile(
&hFile,
FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT
FILE_NON_DIRECTORY_FILE,
NULL,
0);
if (NT_ERROR(nStatus))
{
hFile = NULL;
__leave;
}
nStatus = ObReferenceObjectByHandle(
hFile,
NULL,
*IoFileObjectType,
KernelMode,
(PVOID*)&FileObject, //得到handle对应的FileObject
NULL);
if (NT_ERROR(nStatus))
{
FileObject = NULL;
__leave;
}
FileName = (PFILE_NAME_INFORMATION)FileBuffer;
nStatus = ZwQueryInformationFile(
hFile,
&IoStatus,
FileName,
sizeof(WCHAR) * MAX_PATH,
FileNameInformation);
if (NT_ERROR(nStatus))
{
__leave;
}
if (FileObject->DeviceObject == NULL) //通过FileObject得到DeviceObject
{
nDeviceStatus = STATUS_DEVICE_DOES_NOT_EXIST;
__leave;
}
/// 求出进程文件所在盘符的符号链接
nDeviceStatus = RtlVolumeDeviceToDosName(FileObject->DeviceObject, &DosDeviceName);
}
__finally
{
if (NULL != FileObject)
{
ObDereferenceObject(FileObject);
}
if (NULL != hFile)
{
ZwClose(hFile);
}
if (NULL != lpBuffer)
{
ExFreePool(lpBuffer);
}
KeUnstackDetachProcess(&ApcState);
}
if (NT_SUCCESS(nStatus))
{
RtlInitUnicodeString(&ProcessPath, FileName->FileName);
if (NT_SUCCESS(nDeviceStatus))
{
/// 拼接DosDeviceName + ProcessPath
RtlCopyUnicodeString(FullPath, &DosDeviceName);
RtlUnicodeStringCat(FullPath, &ProcessPath);
}
else
{
RtlCopyUnicodeString(FullPath, &ProcessPath);
}
}
return nStatus;
}
4.也可以在内核层弹窗不仅可以应用层弹窗。内核层也调用ExRaiseHardError()来弹窗(但可定制性不高,没有计时功能,比如在反截屏中,可以弹窗提示用户)主防的几个经典问题弹窗弹的是什么?A把B怎么了?A:R3某进程。 忽略内核操作,互不干涉,内核和内核对战是没必要的,主要是阻止进程进入内核。比如五大常任理事国都有核武器,五大常任理事国一旦打架,地球重启。共同阻止其他非常任理事国突破核武器。朝鲜。B:文件/注册表/驱动/进程怎么了:创建/删除/修改/重命名/启动允许还是阻止弹框的不同颜色警示危险等级做得太弱智,老弹窗,用户会厌烦,用户也可能误判拦截到攻击自己判断处理最好,也防止用户误判,但太智能也不行,一次都没有弹窗,用户会怀疑你行不行,所以还是偶尔弹一下绿框告诉用户,拦截到某个攻击事件已经自动处理,一闪而过刷一下存在感。模式匹配正则匹配为了性能和安全的平衡,不可能监控所有文件,监控重要的文件比较合理,比如sytem32文件夹等。这时候就需要使用模式匹配了*表示零次或者任意次字符?表示零次或下一次字符eg:BOOLEAN IsPatternMatch(PUNICODE STRING Expression,
PUNICODE_STRING Name, BOOLEAN IgnoreCase)
{
/// 如果匹配成功return True,但也有局限性,只支持文件路径的正则匹配,比如注册表就不支持了
return FsRtllsNamelnExpression(
Expression, //正则式
Name, //具体某个文件的路径,
IgnoreCase, //如果这里设置为TRUE,那么Expression必须是大写的
NULL
);
}
/// 比如现在有两条规则:假设忽略大小写
L'C:\\WINDOWS\\SYSTEM32\\*.SYS"
L"C:\\WINDOWS\\SYSTEM32\\*\\*.SYS"
/// 有路径:
L"C:\\Window\\system32\\122222\\2.sys"
/// 就会匹配第一、第二条规则
/// 如果区分分文件夹,只想命中第二条规则,可以把第一条规则改成
L'C:\\WINDOWS\\SYSTEM32/*.SYS"
实战:支持任何字符串的正则匹配#include <Ntifs.h>
#include <ntddk.h>
#include <windef.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("Goodbye!\n");
}
BOOLEAN IsPatternMatch(PUNICODE_STRING Expression, PUNICODE_STRING Name, BOOLEAN IgnoreCase)
{
return FsRtlIsNameInExpression(
Expression,
Name,
IgnoreCase,//如果这里设置为TRUE,那么Expression必须是大写的
NULL
);
}
BOOL PatternMatch(WCHAR * pat, WCHAR * str)
{
register WCHAR * s;
register WCHAR * p;
BOOL star = FALSE;
loopStart:
for (s = str, p = pat; *s; ++s, ++p) {
switch (*p) {
case L'?':
if (*s == L'.') goto starCheck;
break;
case L'*':
star = TRUE;
str = s, pat = p;
if (!*++pat) return TRUE;
goto loopStart;
default:
//if (Lower(*s) != Lower(*p))
goto starCheck;
break;
}
}
if (*p == L'*') ++p;
return (!*p);
starCheck:
if (!star) return FALSE;
str++;
goto loopStart;
}
BOOL PatternNMatch(WCHAR * pat, WCHAR * str, DWORD count)
{
register WCHAR * s;
register WCHAR * p;
BOOL star = FALSE;
DWORD dwCount = count;
loopStart:
for (s = str, p = pat; dwCount>0; --dwCount, ++s, ++p) {
switch (*p) {
case L'?':
if (*s == L'.') goto starCheck;
break;
case L'*':
star = TRUE;
str = s, pat = p;
if (!*++pat) return TRUE;
goto loopStart;
default:
//if (Lower(*s) != Lower(*p))
goto starCheck;
break;
}
}
if (*p == L'*') ++p;
return (!*p);
starCheck:
if (!star) return FALSE;
str++;
dwCount--;
goto loopStart;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
UNICODE_STRING uExpression = {0};
UNICODE_STRING uName
= {0};
RtlInitUnicodeString(&uExpression, L"C:\\WINDOWS\\SYSTEM32\\*.SYS");
RtlInitUnicodeString(&uName, L"c:\\Windows\\system32\\122222\\2.sys");
if (IsPatternMatch(&uExpression, &uName, TRUE))
{
DbgPrint("Matched\n");
}
else
{
DbgPrint("Not Matched\n");
}
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
格式转换获得目标对象的全路径内核中有多种对象,对象不同获取全路径的方式不同HandleObReferenceObjectByHandle→ loQueryFileDosDeviceNameObReferenceObjectBylHandle→ ObQueryNameString(强删文件例子里)IRP查询(FILEMON4.34中FilemonQueryFile函数)FltGetName(minifilter)获得文件短名的长名windows用dir /x 查看短名 dos环境下的83格式(文件名总数<=8,扩展名<=3,太长的文件名中间部分会被~替换) 统一使用长名来做规则匹配 所以需要短名转化成长名思路: 把文件名按~来分割,从左往右依次调用ZwQueryDirectoryFile()获得长名,直至所有短名都转换成功拼接在一起就得到长名实战#include <ntifs.h>
#include <ntstrsafe.h>
#include <ntddk.h>
#include <windef.h>
BOOL IsRootDirecotry(WCHAR * wszDir)
{
SIZE_T length = wcslen(wszDir);
// c:
if((length == 2) && (wszDir[1] == L':'))
return TRUE;
//\\??\\c:
if((length == 6) &&
(_wcsnicmp(wszDir, L"\\??\\", 4) == 0) &&
(wszDir[5] == L':'))
return TRUE;
//\\DosDevices\\c:
if((length == 14) &&
(_wcsnicmp(wszDir, L"\\DosDevices\\", 12) == 0) &&
(wszDir[13] == L':'))
return TRUE;
//\\Device\\HarddiskVolume1
if((length == 23) &&
(_wcsnicmp(wszDir, L"\\Device\\HarddiskVolume", 22) == 0))
return TRUE;
return FALSE;
}
BOOL IsDirectorySep(WCHAR ch)
{
return (ch == L'\\'
ch == L'/');
}
//C:\\Program\\123456~1
//wszRootdir为:c:\\Program
//wszShortName为:123456~1
BOOL QueryDirectoryForLongName(
WCHAR * wszRootDir,
WCHAR * wszShortName,
WCHAR *wszLongName,
ULONG ulSize)
{
UNICODE_STRING
ustrRootDir
= {0};
UNICODE_STRING
ustrShortName = {0};
UNICODE_STRING
ustrLongName = {0};
OBJECT_ATTRIBUTES
oa
= {0};
IO_STATUS_BLOCK
Iosb
= {0};
NTSTATUS
ntStatus
= 0;
HANDLE
hDirHandle
= 0;
BYTE
*Buffer
= NULL;
WCHAR
*wszRoot
= NULL;
PFILE_BOTH_DIR_INFORMATION pInfo
= NULL;
RtlZeroMemory(&Iosb, sizeof(IO_STATUS_BLOCK));
Iosb.Status = STATUS_NO_SUCH_FILE;
wszRoot = ExAllocatePoolWithTag(PagedPool,
MAX_PATH * sizeof(WCHAR),
'L2S');
if(wszRoot == NULL)
{
return FALSE;
}
RtlZeroMemory(wszRoot, MAX_PATH * sizeof(WCHAR));
wcsncpy(wszRoot, wszRootDir, MAX_PATH);
RtlInitUnicodeString(&ustrRootDir, wszRoot);
RtlInitUnicodeString(&ustrShortName, wszShortName);
if(IsRootDirecotry(wszRoot))
RtlAppendUnicodeToString(&ustrRootDir, L"\\");
InitializeObjectAttributes(&oa,
&ustrRootDir,
OBJ_CASE_INSENSITIVE
OBJ_KERNEL_HANDLE,
0,
0);
ntStatus = ZwCreateFile(&hDirHandle,
GENERIC_READ
SYNCHRONIZE,
&oa,
&Iosb,
0,
FILE_ATTRIBUTE_DIRECTORY,
FILE_SHARE_READ
FILE_SHARE_WRITE
FILE_SHARE_DELETE,
FILE_OPEN,
FILE_DIRECTORY_FILE
FILE_SYNCHRONOUS_IO_NONALERT ,
0,
0);
if (!NT_SUCCESS(ntStatus))
{
ExFreePool(wszRoot);
return FALSE;
}
ExFreePool(wszRoot);
Buffer = ExAllocatePoolWithTag(PagedPool,
1024,
'L2S');
if(Buffer == NULL)
{
ZwClose(hDirHandle);
return FALSE;
}
RtlZeroMemory(Buffer, 1024);
ntStatus = ZwQueryDirectoryFile(hDirHandle,
NULL,
0,
0,
&Iosb,
Buffer,
1024,
FileBothDirectoryInformation,
TRUE,
&ustrShortName, //传回与 ustrShortName Match的项
TRUE);
if (!NT_SUCCESS(ntStatus))
{
ExFreePool(Buffer);
ZwClose(hDirHandle);
return FALSE;
}
ZwClose(hDirHandle);
pInfo = (PFILE_BOTH_DIR_INFORMATION) Buffer;
if(pInfo->FileNameLength == 0)
{
ExFreePool(Buffer);
return FALSE;
}
ustrShortName.Length
= (USHORT)pInfo->FileNameLength;
ustrShortName.MaximumLength = (USHORT)pInfo->FileNameLength;
ustrShortName.Buffer = pInfo->FileName; //长名
if(ulSize < ustrShortName.Length)
{
ExFreePool(Buffer);
return FALSE;
}
ustrLongName.Length = 0;
ustrLongName.MaximumLength = (USHORT)ulSize;
ustrLongName.Buffer = wszLongName;
RtlCopyUnicodeString(&ustrLongName, &ustrShortName);
ExFreePool(Buffer);
return TRUE;
}
BOOL QueryLongName(WCHAR * wszFullPath, WCHAR * wszLongName, ULONG size)
{
BOOL
rtn
= FALSE;
WCHAR *
pchStart
= wszFullPath;
WCHAR *
pchEnd
= NULL;
WCHAR *
wszShortName = NULL;
//c:\\Program\\Files1~1-->获得Files1~1的长名
while(*pchStart)
{
if(IsDirectorySep(*pchStart))
pchEnd = pchStart;
pchStart++;
}
//wszFullPath=c:\\Program
//pchEnd = Files~1
if(pchEnd)
{
*pchEnd++ = L'\0';
//c:\\Program\\Files1~1
//wszFullPath:c:\\Program
//pchEnd:Files1~1
wszShortName = pchEnd;
rtn = QueryDirectoryForLongName(wszFullPath, wszShortName, wszLongName, size);
*(--pchEnd) = L'\\';
//wszFullPath=c:\\Program\\Files1~1
}
return rtn;
}
//先把根目录拷贝到目标目录中,剩下的找到下一级目录是否含有~,如果有,则开始转化.
//如:c:\\Progam\\a~1\\b~1\hi~1.txt
//pchStart指向目录中前一个\\,pchEnd扫描并指向目录的下一个\\,其中如果发现了~,则是短名,需要转换.
//传c:\\Program\\a~1-->c:\\Progam\\ax
//传c:\\Program\\ax\\b~1-->c:\\Program\\ax\\by
//传c:\\Program\\ax\by\\hi~1.txt-->c:\\Program\\ax\by\\hiz.txt
BOOL ConverShortToLongName(WCHAR *wszLongName, WCHAR *wszShortName, ULONG size)
{
WCHAR
*szResult
= NULL;
WCHAR
*pchResult
= NULL;
WCHAR
*pchStart
= wszShortName;
INT
Offset
= 0;
szResult = ExAllocatePoolWithTag(PagedPool,
sizeof(WCHAR) * (MAX_PATH * 2 + 1),
'L2S');
if(szResult == NULL)
{
return FALSE;
}
RtlZeroMemory(szResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1));
pchResult = szResult;
//C:\\x\\-->\\??\\c:
if (pchStart[0] && pchStart[1] == L':')
{
*pchResult++ = L'\\';
*pchResult++ = L'?';
*pchResult++ = L'?';
*pchResult++ = L'\\';
*pchResult++ = *pchStart++;
*pchResult++ = *pchStart++;
Offset = 4;
}
//\\DosDevices\\c:\\xx-->\\??\\c:
else if (_wcsnicmp(pchStart, L"\\DosDevices\\", 12) == 0)
{
RtlStringCbCopyW(pchResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1), L"\\??\\");
pchResult += 4;
pchStart += 12;
while (*pchStart && !IsDirectorySep(*pchStart))
*pchResult++ = *pchStart++;
Offset = 4;
}
//\\Device\\HarddiskVolume1\\xx-->\\Device\\HarddiskVolume1
else if (_wcsnicmp(pchStart, L"\\Device\\HardDiskVolume", 22) == 0)
{
RtlStringCbCopyW(pchResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1),L"\\Device\\HardDiskVolume");
pchResult += 22;
pchStart += 22;
while (*pchStart && !IsDirectorySep(*pchStart))
*pchResult++ = *pchStart++;
}
//\\??\\c:\\xx-->\\??\\c:
else if (_wcsnicmp(pchStart, L"\\??\\", 4) == 0)
{
RtlStringCbCopyW(pchResult, sizeof(WCHAR) * (MAX_PATH * 2 + 1), L"\\??\\");
pchResult += 4;
pchStart += 4;
while (*pchStart && !IsDirectorySep(*pchStart))
*pchResult++ = *pchStart++;
}
else
{
ExFreePool(szResult);
return FALSE;
}
while (IsDirectorySep(*pchStart))
{
BOOL
bShortName
= FALSE;
WCHAR
*pchEnd
= NULL;
WCHAR
*pchReplacePos
= NULL;
*pchResult++ = *pchStart++;
pchEnd = pchStart;
pchReplacePos = pchResult;
while (*pchEnd && !IsDirectorySep(*pchEnd))
{
if(*pchEnd == L'~')
{
bShortName = TRUE;
}
*pchResult++ = *pchEnd++;
}
*pchResult = L'\0';
if(bShortName)
{
WCHAR
* szLong = NULL;
szLong = ExAllocatePoolWithTag(PagedPool,
sizeof(WCHAR) * MAX_PATH,
'L2S');
if(szLong)
{
RtlZeroMemory(szLong,
sizeof(WCHAR) * MAX_PATH);
if(QueryLongName(szResult, szLong, sizeof(WCHAR) * MAX_PATH))
{
RtlStringCbCopyW(pchReplacePos, sizeof(WCHAR) * (MAX_PATH * 2 + 1), szLong);
pchResult = pchReplacePos + wcslen(pchReplacePos);
}
ExFreePool(szLong);
}
}
pchStart = pchEnd;
}
wcsncpy(wszLongName, szResult + Offset, size/sizeof(WCHAR));
ExFreePool(szResult);
return TRUE;
}
BOOL IsShortNamePath(WCHAR * wszFileName)
{
WCHAR *p = wszFileName;
while(*p != L'\0')
{
if(*p == L'~')
{
return TRUE;
}
p++;
}
return FALSE;
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("Goodbye!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
//dir /x看短名
WCHAR wszShortName[MAX_PATH] =L"\\??\\C:\\PROGRA~1\\COMMON~1\\MICROS~1\\VC\\1.txt";
WCHAR wszLongName[MAX_PATH] = {0};
if(ConverShortToLongName(wszLongName, wszShortName, sizeof(wszLongName)))
{
DbgPrint("%ws\n", wszLongName);
}
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
设备名与符号链接名的转化设备名-> 符号链接名 有指定的API可以调用ZwOpenSymbolicLinkObject()得到符号链接名ZwQuerySymbolicLinkObject()得到设备名设备名<-符号链接名 没有指定的API可以调用但盘符是有限的,只有26个,A-Z可以通过枚举A-Z盘符对应的设备名是否与目标一致来找到符号链接名实战#include <ntddk.h>
#include <windef.h>
#include <ntstrsafe.h>
//输入\\??\\c:-->\\device\\\harddiskvolume1
//LinkTarget.Buffer注意要释放
NTSTATUS QuerySymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
OUT PUNICODE_STRING LinkTarget
)
{
OBJECT_ATTRIBUTES oa
= {0};
NTSTATUS
status = 0;
HANDLE
handle = NULL;
InitializeObjectAttributes(
&oa,
SymbolicLinkName,
OBJ_CASE_INSENSITIVE,
0,
0);
status = ZwOpenSymbolicLinkObject(&handle, GENERIC_READ, &oa);
if (!NT_SUCCESS(status))
{
return status;
}
LinkTarget->MaximumLength = MAX_PATH*sizeof(WCHAR);
LinkTarget->Length = 0;
LinkTarget->Buffer = ExAllocatePoolWithTag(PagedPool, LinkTarget->MaximumLength,'SOD');
if (!LinkTarget->Buffer)
{
ZwClose(handle);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(LinkTarget->Buffer, LinkTarget->MaximumLength);
status = ZwQuerySymbolicLinkObject(handle, LinkTarget, NULL);
ZwClose(handle);
if (!NT_SUCCESS(status))
{
ExFreePool(LinkTarget->Buffer);
}
return status;
}
//输入\\Device\\harddiskvolume1
//输出C:
//DosName.Buffer的内存记得释放
NTSTATUS
MyRtlVolumeDeviceToDosName(
IN PUNICODE_STRING DeviceName,
OUT PUNICODE_STRING DosName
)
/*++
Routine Description:
This routine returns a valid DOS path for the given device object.
This caller of this routine must call ExFreePool on DosName->Buffer
when it is no longer needed.
Arguments:
VolumeDeviceObject - Supplies the volume device object.
DosName - Returns the DOS name for the volume
Return Value:
NTSTATUS
--*/
{
NTSTATUS
status
= 0;
UNICODE_STRING
driveLetterName
= {0};
WCHAR
driveLetterNameBuf[128] = {0};
WCHAR
c
= L'\0';
WCHAR
DriLetter[3]
= {0};
UNICODE_STRING
linkTarget
= {0};
for (c = L'A'; c <= L'Z'; c++)
{
RtlInitEmptyUnicodeString(&driveLetterName,driveLetterNameBuf,sizeof(driveLetterNameBuf));
RtlAppendUnicodeToString(&driveLetterName, L"\\??\\");
DriLetter[0] = c;
DriLetter[1] = L':';
DriLetter[2] = 0;
RtlAppendUnicodeToString(&driveLetterName,DriLetter);
status = QuerySymbolicLink(&driveLetterName, &linkTarget);
if (!NT_SUCCESS(status))
{
continue;
}
if (RtlEqualUnicodeString(&linkTarget, DeviceName, TRUE))
{
ExFreePool(linkTarget.Buffer);
break;
}
ExFreePool(linkTarget.Buffer);
}
if (c <= L'Z')
{
DosName->Buffer = ExAllocatePoolWithTag(PagedPool, 3*sizeof(WCHAR), 'SOD');
if (!DosName->Buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
DosName->MaximumLength = 6;
DosName->Length
= 4;
*DosName->Buffer
= c;
*(DosName->Buffer+ 1) = ':';
*(DosName->Buffer+ 2) = 0;
return STATUS_SUCCESS;
}
return status;
}
//c:\\windows\\hi.txt<--\\device\\harddiskvolume1\\windows\\hi.txt
BOOL NTAPI GetNTLinkName(IN WCHAR * wszNTName, OUT WCHAR * wszFileName)
{
UNICODE_STRING
ustrFileName = {0};
UNICODE_STRING
ustrDosName = {0};
UNICODE_STRING
ustrDeviceName = {0};
WCHAR
*pPath = NULL;
ULONG
i = 0;
ULONG
ulSepNum = 0;
if (wszFileName == NULL
wszNTName == NULL
_wcsnicmp(wszNTName, L"\\device\\harddiskvolume", wcslen(L"\\device\\harddiskvolume"))!=0)
{
return FALSE;
}
ustrFileName.Buffer = wszFileName;
ustrFileName.Length = 0;
ustrFileName.MaximumLength = sizeof(WCHAR)*MAX_PATH;
while(wszNTName[i]!=L'\0')
{
if (wszNTName[i] == L'\0')
{
break;
}
if (wszNTName[i] == L'\\')
{
ulSepNum++;
}
if (ulSepNum == 3)
{
wszNTName[i] = UNICODE_NULL;
pPath = &wszNTName[i+1];
break;
}
i++;
}
if (pPath == NULL)
{
return FALSE;
}
RtlInitUnicodeString(&ustrDeviceName, wszNTName);
if (!NT_SUCCESS(MyRtlVolumeDeviceToDosName(&ustrDeviceName, &ustrDosName)))
{
return FALSE;
}
RtlCopyUnicodeString(&ustrFileName, &ustrDosName);
RtlAppendUnicodeToString(&ustrFileName, L"\\");
RtlAppendUnicodeToString(&ustrFileName, pPath);
ExFreePool(ustrDosName.Buffer);
return TRUE;
}
BOOL QueryVolumeName(WCHAR ch, WCHAR * name, USHORT size)
{
WCHAR szVolume[7] = L"\\??\\C:";
UNICODE_STRING LinkName;
UNICODE_STRING VolName;
UNICODE_STRING ustrTarget;
NTSTATUS ntStatus = 0;
RtlInitUnicodeString(&LinkName, szVolume);
szVolume[4] = ch;
ustrTarget.Buffer = name;
ustrTarget.Length = 0;
ustrTarget.MaximumLength = size;
ntStatus = QuerySymbolicLink(&LinkName, &VolName);
if (NT_SUCCESS(ntStatus))
{
RtlCopyUnicodeString(&ustrTarget, &VolName);
ExFreePool(VolName.Buffer);
}
return NT_SUCCESS(ntStatus);
}
//\\??\\c:\\windows\\hi.txt-->\\device\\harddiskvolume1\\windows\\hi.txt
BOOL NTAPI GetNtDeviceName(IN WCHAR * filename, OUT WCHAR * ntname)
{
UNICODE_STRING uVolName = {0,0,0};
WCHAR volName[MAX_PATH] = L"";
WCHAR tmpName[MAX_PATH] = L"";
WCHAR chVol = L'\0';
WCHAR * pPath = NULL;
int i = 0;
RtlStringCbCopyW(tmpName, MAX_PATH * sizeof(WCHAR), filename);
for(i = 1; i < MAX_PATH - 1; i++)
{
if(tmpName[i] == L':')
{
pPath = &tmpName[(i + 1) % MAX_PATH];
chVol = tmpName[i - 1];
break;
}
}
if(pPath == NULL)
{
return FALSE;
}
if(chVol == L'?')
{
uVolName.Length = 0;
uVolName.MaximumLength = MAX_PATH * sizeof(WCHAR);
uVolName.Buffer = ntname;
RtlAppendUnicodeToString(&uVolName, L"\\Device\\HarddiskVolume?");
RtlAppendUnicodeToString(&uVolName, pPath);
return TRUE;
}
else if(QueryVolumeName(chVol, volName, MAX_PATH * sizeof(WCHAR)))
{
uVolName.Length = 0;
uVolName.MaximumLength = MAX_PATH * sizeof(WCHAR);
uVolName.Buffer = ntname;
RtlAppendUnicodeToString(&uVolName, volName);
RtlAppendUnicodeToString(&uVolName, pPath);
return TRUE;
}
return FALSE;
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
DbgPrint("Goodbye!\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
UNICODE_STRING
ustrDeviceName
= {0};
UNICODE_STRING
ustrLinkName
= {0};
WCHAR
*wszDeviceName
= L"\\Device\\harddiskvolume1";
NTSTATUS
ntStatus
= 0;
WCHAR
DeviceName[MAX_PATH]
= L"\\Device\\harddiskvolume1\\windows\\hi.txt";
WCHAR
FileName[MAX_PATH]
= {0};
WCHAR
szDeviceName[MAX_PATH]
= {0};
RtlInitUnicodeString(&ustrDeviceName, wszDeviceName);
ntStatus = MyRtlVolumeDeviceToDosName(&ustrDeviceName, &ustrLinkName);
if (NT_SUCCESS(ntStatus))
{
DbgPrint("linkname:%wZ\n", &ustrLinkName);
if (ustrLinkName.Buffer)
{
ExFreePool(ustrLinkName.Buffer);
}
}
if (GetNTLinkName(DeviceName, FileName))
{
DbgPrint("FileName:%ws\n", FileName);
GetNtDeviceName(FileName, szDeviceName);
DbgPrint("szDeviceName:%ws", szDeviceName);
}
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
规则的下发方式用dat文件存放规则,dat文件做一些简单加密(防止木马和病毒利用,绕过监测)客户端把dat文件的规则读出,通过DeviceIoControl()发到内核,保存在内核中的链表或者树或者hash表里面,内核在拦截到攻击事件的时候,就会去遍历这个存放规则数据结构,匹配上就弹窗或者自行处理。放行问题大数据机器学习,智能放行中国杀毒软件层参加国际比赛到很高分,是针对病毒库定制的版本(查杀率很高),和用户的版本不一样,取消比赛成绩放行的条件内核态的操作不拦截 用 ExGetPreviousMode() == KernnelMode来判断是不是内核态或者用Irp->RequestorMode == kernelMode来判断是不是内核态自己进程的操作不拦截 - 在DeviceIoctrlFilter中通过PsGetCurrentProcessId()拿到进程的PID系统进程的操作不拦截 DriverEntry里处于系统上下文,再通过PsGetCurrentProcessId()拿到的就是系统进程,以后凡是这些系统进程的操作都放行应用层的Irql一般不会超过APC_LEVEL,即KeGetCurrentIrql()>APC_LEVEL放行,只拦截应用层白名单中的进程(交了钱的) 但有可能会被白利用,让白名单的程序把我做一些攻击操作,借刀杀人防范白利用,用调用链,不仅要看当前进程是好的还是坏的,还要看调用这个进程的父进程是好的还是坏的,只要有一个是坏的,就是不放行。如何放行如果通过HOOK进行监控,放行就是直接调用原来被HOOK的APIIRP(如果是在过滤驱动进行监控的)/// 把Irp往下发
IoSkipCurrentIrpStackLocation(IpIrp);
IoCallDriver();}

我要回帖

更多关于 有没有可以拦截别人短信的软件 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信