在Device I/O control的case分支中响应应用程序的映射请求,映射稍微大一点的空间就会蓝屏报这个错误,困惑了大概一周[原文链接:http://bbs.pediy.com/showthread.php?t=214508],这里提供一种可能的解决方法,小菜驱动新人,码贴如有缺陷,各位多多指点.
1.可能原因,MmMapLockedPagesSpecifyCache的函数说明最后一句:
If AccessMode is UserMode, the caller must be running at IRQL <= APC_LEVEL. If AccessMode is KernelMode, the caller must be running at IRQL <= DISPATCH_LEVEL.
在接近放弃之前看到了这句话,打印了一下映射函数上下的IRQL,发现是DISPATCH_LEVEL(2),而UserMode下IRQL只能是PASSIVE_LEVEL (0)或者APC_LEVEL (1),意识到从来没有关心到这个问题,开始搜索IRQL相关的函数.
2.解决方法:在调用MmMapLockedPagesSpecifyCache前保存当前IRQL,降低IRQL到APC_LEVEL或以下,用MmMapLockedPagesSpecifyCache映射地址,最后恢复IRQL到原本等级.
代码如下:
KIRQL curkirql = 0;
KIRQL oldkirql = 0;
curkirql = KeGetCurrentIrql(); //获取当前IRQL
if (curkirql > APC_LEVEL){ //若当前IRQL过高则调低到APC_LEVEL
KeLowerIrql(APC_LEVEL);
}
AppBaseAddr = MmMapLockedPagesSpecifyCache( pMdl, //映射地址
UserMode,
MmNonCached,
NULL,
FALSE,
NormalPagePriority
);
KeRaiseIrql(curkirql, &oldkirql); //恢复场地
将AppBaseAddr通过outBuffer返回给应用程序,当前应用程序进程就可以使用这个地址了。
3.不清楚这种手动切换IRQL的方法是不是有隐患,但目前解决了我的问题,16Mbytes的CommonBuffer都可以正常映射了。
4.之所以说“可能”的原因是有点自相矛盾,小size公用缓存区在没有调整IRQL时也可以做映射,大一点内存块要做映射就得加上这个调整IRQL.希望有了解的大牛能继续深入解释这个问题。
5.致谢:
OSR:Walter Steinhauser
pediy:cvcvxk
driverdevelop: mengzi,wuqix
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)