失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 驱动蓝屏0x50 PAGE_FAULT_IN_NONPAGED_AREA

驱动蓝屏0x50 PAGE_FAULT_IN_NONPAGED_AREA

时间:2023-08-29 03:53:56

相关推荐

驱动蓝屏0x50 PAGE_FAULT_IN_NONPAGED_AREA

想写个暴力搜索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 moveax,dword ptr [edx]TRAP_FRAME: 807e3a08 -- (.trap 0xffffffff807e3a08)ErrCode = 00000000eax=82d89ffd ebx=00000000 ecx=00000019 edx=82d89ffd esi=93f33000 edi=00000004eip=93f3115e esp=807e3a7c ebp=807e3a88 iopl=0 nv up ei pl nz na po nccs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202enummod!memcmp+0x16:93f3115e 8b02 moveax,dword ptr [edx] ds:0023:82d89ffd=????????Resetting default scopeLAST_CONTROL_TRANSFER: from 82aeae71 to 82a79394STACK_TEXT: ...807e3968 82a938e3 00000050 82d8a000 00000000 nt!KeBugCheck2+0x68b807e39f0 82a545f8 00000000 82d8a000 00000000 nt!MmAccessFault+0x106807e39f0 93f3115e 00000000 82d8a000 00000000 nt!KiTrap0E+0xdc807e3a88 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+0x7ed807e3d00 82a7bf2b 8ce35cd0 00000000 85010020 nt!IopLoadUnloadDriver+0x70...FOLLOWUP_IP: enummod!memcmp+16 [d:\wbrtm\minkernel\crts\crtw32\string\i386\memcmp.c @ 70]93f3115e 8b02 moveax,dword ptr [edx]...Followup:MachineOwner---------kd> .trap 0xffffffff807e3a08ErrCode = 00000000eax=82d89ffd ebx=00000000 ecx=00000019 edx=82d89ffd esi=93f33000 edi=00000004eip=93f3115e esp=807e3a7c ebp=807e3a88 iopl=0 nv up ei pl nz na po nccs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202enummod!memcmp+0x16:93f3115e 8b02 moveax,dword ptr [edx] ds:0023:82d89ffd=????????kd> !pte 82d89ffdVA 82d89ffdPDE at C06020B0 PTE at C0416C48contains 00000000001D2063 contains 0000000002D89963pfn 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.2MmIsAddressValid的实现(我的机器是win7RTM32bit,所以只贴出源码中2级页表映射的内容):

BOOLEANMiIsAddressValid (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 #13PAGEVRFD 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 numbersC0000040 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 numbersE2000020 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 numbers42000040 flagsInitialized DataDiscardable <-------------------------------(no align specified)Read Only

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

kd> dd 82d81ffd L182d81ffd ????????kd> !pte 82d81ffdVA 82d81ffdPDE at C06020B0 PTE at C0416C08contains 00000000001D2063 contains 0000000002D81963pfn 1d2 ---DA--KWEV pfn 2d81-G-DA--KWEV

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

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

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

kd> !dh ntSECTION HEADER #13PAGEVRFD 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 82d81000PDE at C06020B0 PTE at C0416C08contains 00000000001D2063 contains 0000000002D81963pfn 1d2 ---DA--KWEV pfn 2d81 -G-DA--KWEVkd> !pte 82a06000+37C000 <-----#14节的页面对应pte是全0pteVA 82d82000PDE at C06020B0 PTE at C0416C10contains 00000000001D2063 contains 0000000000000000pfn 1d2 ---DA--KWEV not validBugCheck 50, {82d82000, 0, 9453015e, 0} <-----BugCheck 0x50 Arg1 表明蓝屏时访问的内存地址 82d82000=82a06000+37C000 正好是#14节的开始

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

如果觉得《驱动蓝屏0x50 PAGE_FAULT_IN_NONPAGED_AREA》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。