想写个暴力搜索nt模块中未导出函数,结果一直蓝屏:

unsigned long MatchFunc(PKLDR_DATA_TABLE_ENTRY ldrDataTabEntry)
{unsigned long found = 0x00UL, CodeFeatureLen = sizeof(CodeFeature) / sizeof(unsigned char), idx = 0;UNICODE_STRING matchModName;char* modBase = (char*)ldrDataTabEntry->DllBase;RtlInitUnicodeString(&matchModName, L"ntoskrnl.exe");if (RtlCompareUnicodeString(&matchModName, &ldrDataTabEntry->BaseDllName, TRUE) == 0){for (; idx<(ldrDataTabEntry->SizeOfImage - CodeFeatureLen); idx++){if (memcmp(&modBase[idx], CodeFeature, CodeFeatureLen) == 0){found = 0x01UL;break;}}}return found;
}

dump的内容大概如下:

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: 82d8a000, memory referenced.
Arg2: 00000000, value 0 = read operation, 1 = write operation.
Arg3: 93f3115e, If non-zero, the instruction address which referenced the bad memoryaddress.
Arg4: 00000000, (reserved)READ_ADDRESS:  82d8a000 FAULTING_IP:
enummod!memcmp+16 [d:\wbrtm\minkernel\crts\crtw32\string\i386\memcmp.c @ 70]
93f3115e 8b02            mov     eax,dword ptr [edx]TRAP_FRAME:  807e3a08 -- (.trap 0xffffffff807e3a08)
ErrCode = 00000000
eax=82d89ffd ebx=00000000 ecx=00000019 edx=82d89ffd esi=93f33000 edi=00000004
eip=93f3115e esp=807e3a7c ebp=807e3a88 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
enummod!memcmp+0x16:
93f3115e 8b02            mov     eax,dword ptr [edx]  ds:0023:82d89ffd=????????
Resetting default scopeLAST_CONTROL_TRANSFER:  from 82aeae71 to 82a79394STACK_TEXT:
...
807e3968 82a938e3 00000050 82d8a000 00000000 nt!KeBugCheck2+0x68b
807e39f0 82a545f8 00000000 82d8a000 00000000 nt!MmAccessFault+0x106
807e39f0 93f3115e 00000000 82d8a000 00000000 nt!KiTrap0E+0xdc
807e3a88 93f31128 82d89ffd 93f33000 00000019 enummod!memcmp+0x16 [d:\wbrtm\minkernel\crts\crtw32\string\i386\memcmp.c @ 70]
807e3ab8 93f31093 84f42c98 00220020 93f311de enummod!MatchFunc+0x78 [c:\studio\enummod\enummod\enummod.c @ 49]
807e3ad8 82bb1728 850a0358 850a3000 00000000 enummod!DriverEntry+0x93 [c:\studio\enummod\enummod\enummod.c @ 164]
807e3cbc 82baf499 00000001 00000000 807e3ce4 nt!IopLoadDriver+0x7ed
807e3d00 82a7bf2b 8ce35cd0 00000000 85010020 nt!IopLoadUnloadDriver+0x70
...FOLLOWUP_IP:
enummod!memcmp+16 [d:\wbrtm\minkernel\crts\crtw32\string\i386\memcmp.c @ 70]
93f3115e 8b02            mov     eax,dword ptr [edx]
...Followup:     MachineOwner
---------kd> .trap 0xffffffff807e3a08
ErrCode = 00000000
eax=82d89ffd ebx=00000000 ecx=00000019 edx=82d89ffd esi=93f33000 edi=00000004
eip=93f3115e esp=807e3a7c ebp=807e3a88 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
enummod!memcmp+0x16:
93f3115e 8b02            mov     eax,dword ptr [edx]  ds:0023:82d89ffd=????????kd> !pte 82d89ffdVA 82d89ffd
PDE at C06020B0            PTE at C0416C48
contains 00000000001D2063  contains 0000000002D89963
pfn 1d2       ---DA--KWEV  pfn 2d89      -G-DA--KWEVkd> !dd 2D89ffd L4
# 2d89ffc 00000000 00000000 00000000 00000000

乍一看错误解释,以为是在高IRQL上引用了分页内存,心里琢磨着什么时候DriverEntry的IRQL>DISPATCHER_LEVEL了?正巧同事经过,看了一眼我的代码说:在比较内存值前先判断一下页面是否有效的,应该能解决问题~我那个激动啊,原来如此,三下五除二将修改了代码为:

unsigned long MatchFunc(PKLDR_DATA_TABLE_ENTRY ldrDataTabEntry)
{unsigned long found = 0x00UL, CodeFeatureLen = sizeof(CodeFeature) / sizeof(unsigned char), idx = 0;UNICODE_STRING matchModName;char* modBase = (char*)ldrDataTabEntry->DllBase;RtlInitUnicodeString(&matchModName, L"ntoskrnl.exe");if (RtlCompareUnicodeString(&matchModName, &ldrDataTabEntry->BaseDllName, TRUE) == 0){for (; idx<(ldrDataTabEntry->SizeOfImage - CodeFeatureLen); idx++){
            //比较内存前先判断地址是否有效if ((MmIsAddressValidAddr)(&modBase[idx])){
                //有效,然后再比较if (memcmp(&modBase[idx], CodeFeature, CodeFeatureLen) == 0){found = 0x01UL;break;}}}}return found;
}

再次加载驱动,程序还是在相同的地方出错了。说不通啊,我已经判断过页面的有效性了,能进到最内层的if进行页面比较就说明内存有效性检测已经通过了,难道是MmIsAddressValid出错了?百度了一圈,发现求助的人不少,更有人说内核API MmIsAddressValid不稳定,还引用了ddk help的原话:" Even if MmIsAddressValid returns TRUE, accessing the address can cause page faults unless the memory has been locked down or the address is a valid nonpaged pool address."

带着这样的疑惑,我查看了wrk1.2 MmIsAddressValid的实现(我的机器是win7RTM32bit,所以只贴出源码中2级页表映射的内容):


BOOLEAN
MiIsAddressValid (IN PVOID VirtualAddress,IN LOGICAL UseForceIfPossible){PMMPTE PointerPte;UNREFERENCED_PARAMETER (UseForceIfPossible);if (MI_RESERVED_BITS_CANONICAL(VirtualAddress) == FALSE) {return FALSE;}PointerPte = MiGetPdeAddress (VirtualAddress);if (PointerPte->u.Hard.Valid == 0) {return FALSE;}if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) {return TRUE;}PointerPte = MiGetPteAddress (VirtualAddress);if (PointerPte->u.Hard.Valid == 0) {return FALSE;}if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) {return FALSE;}return TRUE;
}

wrk用比较简单的方式检测页面的有效性:检测pte页表项的有效位p位是否置1,置1则认为有效,返回TRUE。这样检测有一个问题:如果代码以下面的流程执行可能会出错:

{if(MmIsAddressValid(addr)) //在IRQL<DISPATCH_LEVEL时判断页面有效性{  //通过有效性判断,同时addr被换出内存KeRaiseIrql(DISPATCH_LEVEL); //页面无法换入do access addr //访问已经被换出的内存,可能蓝屏KeLowerIrql();}
}

附:调换一下代码顺序可能就不会出错了(不过我还没有验证过),

{{  //先提升IRQL,停止换页线程运行KeRaiseIrql(DISPATCH_LEVEL); if(MmIsAddressValid(addr)) //在IRQL>=DISPATCH_LEVEL时判断页面有效性do access addr //通过有效性检测 这时页面就不会被换出,可以大胆的使用KeLowerIrql();}
}

可是,我的代码并没有提升IRQL,就算访问了换页出去的页面OS也会负责将页面重新换回。在这样的背景下通过  if(MmIsAddressValid(addr))有效性检测也不可能访问到无效的页面。最后,我在一个群里得到了比较靠谱的答案:nt模块有些页面被标志位Init或者Discard,如果程序访问了这样的页面也可能会触发缺页异常。我查看了一下nt模块的PE信息,的确发现有很多被标记为Discardable的节:

kd> !dh ntSECTION HEADER #13
PAGEVRFD nameB18 virtual size37B000 virtual address <-------------蓝屏时显示我正在访问的内存所在的节 mov eax,dword ptr [edx]  ds:0023:82d81ffd=????????C00 size of raw data330A00 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
C0000040 flagsInitialized Data(no align specified)Read WriteSECTION HEADER #14INIT name44638 virtual size37C000 virtual address44800 size of raw data331600 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
E2000020 flagsCodeDiscardable <-------------------------------(no align specified)Execute Read WriteSECTION HEADER #16.reloc name1976C virtual size3F6000 virtual address19800 size of raw data3AA400 file pointer to raw data0 file pointer to relocation table0 file pointer to line numbers0 number of relocations0 number of line numbers
42000040 flagsInitialized DataDiscardable <-------------------------------(no align specified)Read Only

另外,我查看了虚拟地址0x82d81ffd处的pte,发现虽然内存0x82d81ffd未被映射,但他的pte是有效的,比较奇怪:

kd> dd 82d81ffd L1
82d81ffd  ????????
kd> !pte 82d81ffdVA 82d81ffd
PDE at C06020B0            PTE at C0416C08
contains 00000000001D2063  contains 0000000002D81963
pfn 1d2       ---DA--KWEV  pfn 2d81      -G-DA--KWEV

了解了这个知识点,我再次对程序进行了修改:先判断是否能获得物理内存,如果返回值为零,即可以获得物理内存再进行内存比较。但这种方式不尽人意,依然触发了异常,异常位置还是在memcmp处。很无奈,我只能再次分析dump文件。再次定位访问出错时CPU将要执行的指令

mov     eax,dword ptr [edx]  ds:0023:82d81ffd=????????

指令访问地址0x82d81ffd,这个地址是正好位于两个节的交界处,再加4B,就能从Section Header #13进入到Section Header #14,而Section Header #14的内存页面是标记为Discardable。由此,我猜想我在暴力搜索内存时只判断了搜索的起始位置的有效性,并未对结束位置的有效性进行判断;如果搜索的起始点在页末最后几个字节,结束位置位于这种被标记为Disacrdable的页面中,就很可能出错。

kd> !dh ntSECTION HEADER #13
PAGEVRFD nameB18 virtual size37B000 virtual address <----页面起始位于82a06000+37B000,页面对齐
...Initialized Data(no align specified)Read WriteSECTION HEADER #14INIT name44638 virtual size37C000 virtual address <----页面起始位于82a06000+37C000,页面对齐
...Discardable <-------------------------------(no align specified)Execute Read Writekd> !pte 82a06000+37B000 <----#13节的页面对应pte是有效的VA 82d81000
PDE at C06020B0            PTE at C0416C08
contains 00000000001D2063  contains 0000000002D81963
pfn 1d2       ---DA--KWEV  pfn 2d81      -G-DA--KWEVkd> !pte 82a06000+37C000 <-----#14节的页面对应pte是全0pteVA 82d82000
PDE at C06020B0            PTE at C0416C10
contains 00000000001D2063  contains 0000000000000000
pfn 1d2       ---DA--KWEV  not validBugCheck 50, {82d82000, 0, 9453015e, 0} <-----BugCheck 0x50 Arg1 表明蓝屏时访问的内存地址 82d82000=82a06000+37C000 正好是#14节的开始

结合上面的分析,验证了我的猜想。这次我同时验证将比较的内存区域的首尾是否有效,再次加载果然没有蓝屏发生。

驱动蓝屏0x50 PAGE_FAULT_IN_NONPAGED_AREA相关推荐

  1. 蓝屏代码PAGE_FAULT_IN_NONPAGED_AREA的解决方法

    蓝屏代码PAGE_FAULT_IN_NONPAGED_AREA的解决方法 参考文章: (1)蓝屏代码PAGE_FAULT_IN_NONPAGED_AREA的解决方法 (2)https://www.cn ...

  2. 蓝屏代码page_fault_in_nonpaged_area (0x00000050)

    蓝屏代码page_fault_in_nonpaged_area (0x00000050) 方法一: 关闭快速启动 "Win+X"-电源选项-其他电源设置-选择电源按钮的功能-更改当 ...

  3. intel六代/七代CPU不支持win7系统不包含USB3.0驱动/蓝屏/重启

    intel六代/七代CPU不支持win7系统不包含USB3.0驱动/蓝屏/重启 问题现象:原生Win7系统不包含USB3.0的驱动,所以无法使用USB3.0的U盘在USB3.0的设备上引导,且安装完系 ...

  4. 驱动蓝屏代码及原因,解决方案

    1.   故障检查信息 *** STOP:  0x100000d1 (0x00000000, 0x00000002, 0x00000000, 0x00000000) 其中错误的第一一是停机码(Stop ...

  5. win10 蓝屏 system_thread_exception_not_handled网卡驱动蓝屏问题解决

    更新win10的补丁之后,使用电脑不断出现蓝屏抛出错误,如下图: realtek网卡在2015年更新后也曾经出现过类似的问题,使用windg软件对蓝屏代码进行了审阅,蓝屏代码截图如下: 大概类似就是如 ...

  6. 驱动蓝屏后简单的分析dump文件

    1: kd> !analyze–v Debugging Details: ------------------ *** ERROR: Moduleload completed but symbo ...

  7. 升级显卡驱动后蓝屏,解决.

    Thinkpad新系统一直使用正常, 直到有一天升级了显卡驱动. 可怕的Intel的显卡驱动...蓝屏, 卸了安装其他版本驱动, 继续蓝屏, 最终只要卸掉显卡驱动... 还有一种症状就是休眠后启动, ...

  8. windows系统蓝屏集

    首字母A APC_INDEX_MISMATCH / APC INDEX MISMATCH 出现原因: 1.文件系统或驱动程序具有不匹配的调用序列 解决方案: 1.若最近有更新安装驱动或软件,则把更新或 ...

  9. win10蓝屏问题,关于驱动kisSaasUrlRedirectKnl64.sys 的

    上周末刚从win7升级到win10:今天出现了两次蓝屏了,都是显示: xxxxxxx 百度知道链接---http://zhidao.baidu.com/question/164141456570387 ...

最新文章

  1. 数据结构之链表反向打印
  2. Oracle序列使用:建立、删除
  3. 1.关于QT中json数据处理和密码md5加密
  4. 分布式与人工智能课程(part16)--深度学习
  5. 移动端网站,键盘弹出对页面的影响
  6. idea-spark-sbt 打包jar
  7. java开发项目实例_Alibaba内部出品Java突击手册,大量开发实战项目分享
  8. c++101rule
  9. 北京人工智能工程师职称评定政策出台,明年起一年一评
  10. ant root环境配置_Java ant环境变量配置
  11. 小程序服务器1兆宽带够用,宽带经验 篇一:200M宽带,真的适合你吗?
  12. 为什么考研的都不是班里最优秀的?
  13. easyui 输入框、选择框、文字框
  14. 高级编程语言学习概论
  15. Hilbert变换C语言实现学习
  16. java查看eth转账状态_eth交易记录input解析
  17. lisp实心圆点怎么画_实心圆点_实心小圆圈符号怎么打出来?
  18. CRT和LCD显示器的区别
  19. PHP遍历数组,分别将内容加入到table表格中
  20. java-php-python-车辆调度管理系统计算机毕业设计

热门文章

  1. AI赋能航空,从安全保障到用户体验变革即将发生
  2. 炉石传说服务器维护时间2020,炉石传说新版本更新时间 2020炉石传说版本时间表...
  3. (2.3)【遥控型木马-黑洞】
  4. 致歉!遭遇恶意团伙刷票,活动取消!改为随机抽奖方式,红包增至10名!
  5. 隐私计算加速崛起,这份技术趋势白皮书揭示了什么?
  6. PHPMailer发送中文名称附件
  7. 阿里云“贴地飞行”,未来能否继续称雄?
  8. 我的第一台电脑早已作古,怀下旧吧。
  9. js的数字四舍五入方法
  10. oracle中fn_getpy函数,SQL Server根据汉字笔划和取得拼音首字母进行排序