调用MmProbeAndLockPages锁定用户态内存时偶发ACCESS_VIOLATION错误求助
我尝试结合IoAllocateMdl与MmProbeAndLockPages锁定用户态进程的内存,相关锁定代码如下:
PEPROCESS TargetProcess = ... // Target process's EPROCESS PVOID virtual_address = ... // Target address SIZE_T size = ... // Target size KAPC_STATE pApcState = NULL; PMDL pMDL = NULL; KPROCESSOR_MODE access_mode = KernelMode; LOCK_OPERATION operation = IoModifyAccess; KeStackAttachProcess(TargetProcess, &pApcState); try { mdl = IoAllocateMdl(PAGE_ALIGN(virtual_address), ADDRESS_AND_SIZE_TO_SPAN_PAGES(PAGE_ALIGN(virtual_address), size) << PAGE_SHIFT, FALSE, FALSE, NULL); MmProbeAndLockPages(mdl, access_mode, operation); }except(EXCEPTION_EXECUTE_HANDLER) { DbgPrintEx(0, 0, "LockPages - Failed! VA : %p, Exception : %p", PAGE_ALIGN(virtual_address), GetExceptionCode()); if (mdl) IoFreeMdl(mdl); KeUnstackDetachProcess(&pApcState); return; }
操作完成后我会执行MmUnlockPages、IoFreeMdl进行清理。目前问题是该错误仅偶发出现,有时无异常,有时触发错误。待锁定的内存是通过VirtualAlloc以MEM_COMMIT和MEM_RESERVE参数分配的,请问该错误出现的原因是什么?
偶发失败的可能原因
目标内存页的动态状态变化:即便内存是
VirtualAlloc提交的,用户态进程仍可能在锁定操作的间隙调用VirtualFree(部分释放)、VirtualLock/VirtualUnlock,或是系统内存紧张时将该页换出到磁盘。MmProbeAndLockPages执行时,若目标页已被释放、处于未提交状态,或是正在换入换出过程中,就会触发异常,这类场景完全取决于进程操作和系统内存状态,因此是偶发的。地址范围计算的边界问题:代码中对
virtual_address做了PAGE_ALIGN,但原始地址可能非页对齐,ADDRESS_AND_SIZE_TO_SPAN_PAGES计算的是对齐后地址开始的页数。如果原始size加上对齐偏移后,超出了用户态进程实际分配的内存范围,就会触及未分配/未提交的页,这种情况不会每次触发,只有当对齐后的范围恰好踩中非法区域时才会失败。APC触发干扰:虽然调用了
KeStackAttachProcess,但目标进程的异步过程调用(APC)若在锁定操作执行时触发,可能会修改内存页状态,或是导致线程上下文切换间接破坏锁定操作的原子性,这类场景的触发时机随机,因此错误偶发。内存页保护属性不匹配:你使用
KernelMode访问模式和IoModifyAccess操作,如果目标内存页的保护属性是PAGE_READONLY这类不允许修改的权限,就会触发异常。若用户态进程动态修改了内存页的保护属性,就会导致偶发失败。MDL分配与锁定的时间窗口漏洞:
IoAllocateMdl仅分配MDL结构并标记页范围,并未立即锁定。从IoAllocateMdl到MmProbeAndLockPages的这段时间里,目标页的状态可能发生变化,进而导致后续锁定操作失败。
内容的提问来源于stack exchange,提问作者GetRektBoy724

