弹窗思路

85 篇文章 6 订阅
83 篇文章 9 订阅

比如有个未知进程A,运行起来被驱动拦截到,收集进程信息,把数据放到OprList里,同时也放到WaitList里,这两个表一一对应,

OperList节点会发到应用层供其弹窗,驱动层等待用户层返回到数据,WaitList存放应用层操作的结果阻塞在。

应用层会开启一个弹窗线程异步读OperList中的数据,然后DeviceIoControl通知驱动,然后驱动在WaitList找到节点进行应用层的操作。

应用层读请求可能OperList是空的,这时Irp会挂起,放在PendingIrpList。一旦驱动发现有新进程,就会先给PendingIrpList。

因为有可能多次攻击,所以给每次进程事件分配一个ID。

整体思路

1.驱动将捕获的操作放入一个等待链表中(包含一个标识ID,一个event,一个等待结果的域),同时将操作内容放入一个内容链表中,并完成来自应用层的读Pendingirp列表

2.等待事件。

 

应用层开启一个独立线程读出(overLapped)驱动链表中的内容。如果没有内容,则挂起到pending irp中

驱动提供自己控制设备的读请求,将链表中的内容提供给应用层读操作

应用层拿到操作内容,弹窗

应用层通过IOCTL下发用户指定结果。

在驱动IOCTL分发函数中,将用户结果放入链表中同ID的结构中

驱动IOCTL分发函数中设置EVENT(事件多个没名字,因为多个攻击并且都是在内核层操作)

驱动拿到用户操作结果

摘掉链表中的操作,获取操作结果

驱动根据操作结果判断允许或者阻止

下发结果

多个弹窗防止内核层超时,可以开多线程,或者可以获取攻击数据函数处加锁。这样多弹窗就是串行了。

内核层可以调用ExRaiseHardError()弹窗

代码片段

前面蓝屏,BAD_POOL_HEADER (19),分析dump文件发现

Unable to get MmSystemRangeStart
Unable to get NonPagedPoolStart
Unable to get PagedPoolStart

后发现ExZreoMemory传错长度导致

//处理应用层的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);
	
	if (IsListEmpty(&g_OperList) == TRUE)
	{
		UnLockWrite(&g_OperListLock);
		
		LockWrite(&g_PendingIrpListLock);
		PendingIrpToList(lpIrp, &g_PendingIrpList, CommonIrpCancel);//设置取消例程的原因是应用层最后可能要退出,pendingirp要取消掉
		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;
}
R3_RESULT __stdcall GetResultFromUser()//负责把攻击数据放到operList里
{
    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;
 
	UNICODE_STRING uFullPath = { 0 };
	uFullPath.MaximumLength = MAX_PATH* sizeof(WCHAR);
	uFullPath.Buffer=ExAllocatePoolWithTag(PagedPool, MAX_PATH * sizeof(WCHAR), 'ELIF');
	RtlZeroMemory(uFullPath.Buffer, MAX_PATH * sizeof(WCHAR));


    lpNewOpInfo = (OP_INFO*)ExAllocatePool(PagedPool, sizeof(OP_INFO));
	RtlZeroMemory(lpNewOpInfo, sizeof(OP_INFO));

    if (lpNewOpInfo == NULL)
    {
        return NotifyResult;
    }

    //设置事件相关的数据,发送给R3,比如进程ID,名字,路径,以及具体操作(创建,修改,删除)等等
	//当然,这里,我们只是简单的捕捉了进程的ID或者名字等
    ulPtr = (ULONG_PTR)PsGetCurrentProcessId();//获得攻击者进程PID
	//拿全路径


	GetProcessFullNameByPid((HANDLE)ulPtr, &uFullPath);
	DbgPrint("uFullPath is %wZ\n", uFullPath.Buffer);
	
	RtlCopyMemory(lpNewOpInfo->m_ProcessName, uFullPath.Buffer, uFullPath.Length);
	ExFreePool(uFullPath.Buffer);

    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(),R3向内核传递弹窗结果,将对应的WaitID事件设置用户选择结果以及//攻击拦截模仿
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;
				}
				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;  
}

应用层就是开线程弹窗,然后提供选项拦截或放行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值