首页
社区
课程
招聘
[分享]映射驱动内存到用户空间蓝屏(KERNEL_DATA_INPAGE_ERROR)的一种可能的解决方法
发表于: 2016-12-14 19:23 10551

[分享]映射驱动内存到用户空间蓝屏(KERNEL_DATA_INPAGE_ERROR)的一种可能的解决方法

2016-12-14 19:23
10551
在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期)

收藏
免费 0
支持
分享
最新回复 (11)
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
2
主动降低IRQL可能引发其他问题...
如果要降低IRQL的话,正确方法应该是开个IoWorkItem或者Thread
如果你自身是在IRP DISPATCH过程去分配的话,可以选择PendingIRP然后在线程中去处理IRP
2016-12-16 22:16
0
雪    币: 1040
活跃值: (1293)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
+1,别主动降低IRQL……这种代码商用有得BUG改……小作坊倒是无所谓
2016-12-17 00:44
0
雪    币: 36
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
我的代码果然有问题,衰。
好的,我去搜索一下您提供的关键字,谢谢~
2016-12-19 11:13
0
雪    币: 36
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
谢谢,我会继续深入研究的~组里做的研究课题,对boss来说应该是商用的,对自己来说毕业写论文的。
2016-12-19 11:16
0
雪    币: 36
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
https://msdn.microsoft.com/zh-cn/library/ff552968(v=vs.85).aspx
KeLowerIrql MSDN:

It is a fatal error to call KeLowerIrql using an input NewIrql that was not returned by the immediately preceding call to KeRaiseIrql.

意思是可以手动先升后降,不能直接降.
2016-12-19 15:25
0
雪    币: 1040
活跃值: (1293)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
人家的意思明明是你自己升的自己降别人升的你别搞事……系统把IRQL升上去明显就是不让外部调度打断,你自己降下去发生了打断会产生不可以预知的问题,听老V的谢谢,在线程和workitem里面干,别跟微软掐了……
2016-12-19 15:29
0
雪    币: 36
活跃值: (17)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
是!明白!坚决不搞事!
2016-12-19 15:33
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
我想问下      在iodevicecontrol中如何通过thread  降irql
2017-4-10 20:31
0
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
用workitem映射之后在用户空间拿到的地址无法访问怎么回事
2018-9-17 13:42
0
雪    币: 75
活跃值: (723)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
youwanmei 用workitem映射之后在用户空间拿到的地址无法访问怎么回事
因为不是在原来的进程上下文了,而是跑到System进程上下文了
2018-9-17 16:06
0
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
pccq 因为不是在原来的进程上下文了,而是跑到System进程上下文了
已经明白了,可是我在线程中进行操作,发现应用层查看映射的地址就死机,不是蓝屏,会是什么原因?我映射的是bar空间地址
2018-9-18 11:28
0
游客
登录 | 注册 方可回帖
返回
//