mqac文件函数ACDeviceControl漏洞分析
函数描述
在Windows中,驱动程序使用设备控制代码(Device Control Codes,即IOCTLs)来接收来自应用程序的命令,或者向应用程序提供信息。
- 解析从用户空间传来的指定命令(如打开、读取、写入或者配置设备的操作)。
- 在硬件层面上执行这些操作。
- 将结果返回给发起请求的应用程序。
函数分析
ACDeviceControl
ACDeviceControl是一个回调函数,用来处理用户端发来的设备控制命令。
进入到函数内,参数二a2是一个IRP类型的数据结构。
目标调用处用到的几个参数,都来自a2
Information = ACSendMessage(
Irp,
Options,
(CQueue *)FileObject->FsContext,
(struct CACSendParameters *)UserBuffer);
几个参数定义
Options = CurrentStackLocation->Parameters.Create.Options;
FileObject = CurrentStackLocation->FileObject;
UserBuffer = (void **)Irp->UserBuffer;
接着进入到ACSendMessage函数内部。
ACSendMessage
先初始化两个内存指针
接着判断(CQueue *)this是否有效,CFG 检查。
随后检查是否合法(UserBuffer)a4
把(UserBuffer)a4
指向v19
,共循环5次,每次偏移0x80
接着再交换4个指针,然后调用ACDeepProbeSendParams
把用户态发的的数据复制到内核态中。
ACDeepProbeSendParams
进入ACDeepProbeSendParams函数后,依次判断UserBuffer偏移0x94
、0x98
、0x9c
、0xA0
如果为假,设置对应的偏移0x49
、0x4B
、0x4D
、0x4F
处指针指向0
还调用了ACDeepProbeMsgPropsForSend(a1, a2);
进一步的复制,这里不进一步跟踪。
然后分别判断(char *)*((_QWORD *)a1 + 0x49)
和(char *)*((_QWORD *)a1 + 0x4B)
为否为真,如果为真,分别调用函数ACDeepCopyQueueFormat来复制队列格式。
这个函数接收三个参数,用户层队列格式,大小,内核层队列格式
然后会根据这个大小来在内核层分配内存
如果没成功,分配另一种标签的内核内存
这个分页内存块的大小是从UserBuffer中获取的,也就是说来自用户,并且分配的时候没有锁。这是很不安全的。
最后,如果内存没有分配成功,调用ACFreeDeepCopyQueueFormat来释放未分配成功的内存块。
ACFreeDeepCopyQueueFormat
通过交叉引用可以看到,ACSendMessage函数也调用了该释放函数。跟进看一下
释放内存的大小,是从UserBuffer获取的,而不是创建时候的值。
进入到函数内部,看一下具体怎么释放
根据不同的类型确定从不同的偏移量释放,每次释放0x20
大小
如果类型为3或者8,从偏移0x8处释放,
如果类型为6,从偏移0x10处是释放
直到NumElement减为0,所有的元素释放完,开始释放掉这个分页内存。
同样的,这里释放内存的时候没有上锁。
漏洞触发
这种情况下就存在条件竞争的可能。一个线程一直分配内存,分配的内存设置小一点,另一个线程直接在内存中修改分配分页内存的大小,从而影响释放内存时的释放大小,从而释放任意内存。
在分配分页内存和释放内存处分别设置断点,并打印两个内存的大小值。可以看到,在最后依次,一个大小为1,另一个大小为10000,接着就触发崩溃程序
随机性很大,这里第4次就触发了