|
|
|
|
|
|
|
Windows内核调试
帖子发起人: yushang 发起时间: 2009-08-12 12:12 下午 回复: 11
|
帖子排序:
|
|
|
|
2009-08-12, 12:12 下午
|
yushang
注册: 2009-08-10
发 贴: 27
|
|
|
都说在DPC级别时,不能调用导致缺页中断的函数,我猜想是不是Windows会在某个地方检查当前的IRQL,如果在DPC上就BugCheck一个IRQL_NOT_LESS_OR_EQUAL错误。如果是这样,是在哪个地方检查的呢?我试着检查了一下TRAP0E的代码,发现只要MmAccessFault返回0D0000006的话,就会导致TRAP0E BugCheck这个错误,但是MmAccessFault太长了,有人能提供一点启发吗?
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-12, 15:49 下午
|
王宇
注册: 2007-05-08
发 贴: 306
|
|
|
这个问题很简单,看看源码 / 跟一下就知道了
http://advdbg.org/forums/2018/ShowPost.aspx
首先 MmAccessFault 内部会判断:
PreviousIrql = KeGetCurrentIrql ();
......
if (
#if (_MI_PAGING_LEVELS >= 4)
(PointerPxe->u.Hard.Valid == 0) ||
#endif
#if (_MI_PAGING_LEVELS >= 3)
(PointerPpe->u.Hard.Valid == 0) ||
#endif
(PointerPde->u.Hard.Valid == 0) ||
((!MI_PDE_MAPS_LARGE_PAGE (PointerPde)) && (PointerPte->u.Hard.Valid == 0))) {
if (KeInvalidAccessAllowed (TrapInformation) == TRUE) {
return STATUS_ACCESS_VIOLATION;
}
KdPrint(("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
VirtualAddress,
PreviousIrql));
if (TrapInformation != NULL) {
MI_DISPLAY_TRAP_INFORMATION (TrapInformation);
}
//
// Signal the fatal error to the trap handler.
//
return STATUS_IN_PAGE_ERROR | 0x10000000;
}
也就是这里的 PTE 等判断失败,返回值 d0000006。这里已经“命中注定”要蓝屏了。
//
// MessageId: STATUS_IN_PAGE_ERROR
//
// MessageText:
//
// The instruction at "0x%08lx" referenced memory at "0x%08lx". The required data was not placed into memory because of an I/O error status of "0x%08lx".
//
#define STATUS_IN_PAGE_ERROR ((NTSTATUS)0xC0000006L) // winnt
----------------------------
此时再回到 _KiTrap0E 的流程做几个判断:
1. Check to determine if the fault occured in the interlocked pop entry slist code.
2. Check to determine if the page fault occured in the user mode interlocked pop entry SLIST code.
3. Did the fault occur in KiSystemService while copying arguments from user stack to kernel stack?
4. Did the fault occur in a VDM?
5. Did the fault occur in a VDM while running in protected mode?
之所以说“命中注定”是因为:
;
; test to see if reserved status code bit is set. If so, then bugchecka
;
cmp eax, STATUS_IN_PAGE_ERROR or 10000000h ; 我们的返回值
je Kt0e12 ; bugchecka
最后蓝屏:
Kt0e12:
CurrentIrql ; (eax) = OldIrql
Kt0e12a:
lock inc ds:_KiHardwareTrigger ; trip hardware analyzer
;
; bugcheck a, addr, irql, load/store, pc
;
mov ecx, [ebp]+TsErrCode ; (ecx)= error code
shr ecx, 1 ; isolate read/write bit
and ecx, _KeErrorMask ;
mov esi, [ebp]+TsEip ; [esi] = faulting instruction
stdCall _KeBugCheck2,
错误码是:IRQL_NOT_LESS_OR_EQUAL
打完收功~
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-13, 17:19 下午
|
yushang
注册: 2009-08-10
发 贴: 27
|
|
|
不过好像PreviousIrql就没有和谁比较过,似乎当前IRQL大于等于DPC的事实隐含在
if ( #if (_MI_PAGING_LEVELS >= 4) (PointerPxe->u.Hard.Valid == 0) || #endif #if (_MI_PAGING_LEVELS >= 3) (PointerPpe->u.Hard.Valid == 0) || #endif (PointerPde->u.Hard.Valid == 0) ||
((!MI_PDE_MAPS_LARGE_PAGE (PointerPde)) && (PointerPte->u.Hard.Valid == 0)))
。。。
中,可以这样理解吗?
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-14, 10:04 上午
|
王宇
注册: 2007-05-08
发 贴: 306
|
|
|
当前 IRQL 大于等于 DPC 本身不是问题
P位 标识出页不在物理内存中才是问题
所以才有那些代码
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-14, 19:53 下午
|
yushang
注册: 2009-08-10
发 贴: 27
|
|
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-15, 23:22 下午
|
yushang
注册: 2009-08-10
发 贴: 27
|
|
|
为什么PTE 等判断失败就等效于IRQL >= DPC ,谢谢?
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-17, 09:18 上午
|
王宇
注册: 2007-05-08
发 贴: 306
|
|
|
IRQL >= DPC 只要你访问的页面有效 (锁定在物理内存中的分页 / 非分页) 就没有问题
但是 IRQL >= DPC 且页面无效,这就违背了 IRQL 的基本准则。
“都说在DPC级别时,不能调用导致缺页中断的函数,我猜想是不是Windows会在某个地方检查当前的IRQL,如果在DPC上就BugCheck一个IRQL_NOT_LESS_OR_EQUAL错误。” <-- 在 DPC 上本身不是错,在 DPC 上缺页才是错
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-17, 20:30 下午
|
yushang
注册: 2009-08-10
发 贴: 27
|
|
|
但是 IRQL >= DPC 且页面无效,这就违背了 IRQL 的基本准则。
是啊,我也是这样认为的,但是系统是在什么地方判断出IRQL >= DPC 的呢?还是引用我前面问过的话:
“。。。好像PreviousIrql就没有和谁比较过。。。”,例如,是不是应该有类似这样的比较:
if ( PreviousIrql >= DISPATCH_LEVEL )
BugCheck...
谢谢
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-17, 21:56 下午
|
王宇
注册: 2007-05-08
发 贴: 306
|
|
|
大哥 你介是逼我贴代码啊 WRK 有代码引用协议的........
PreviousIrql = KeGetCurrentIrql ();
if (PreviousIrql > APC_LEVEL) { // 条件一
if ( #if (_MI_PAGING_LEVELS >= 4) (PointerPxe->u.Hard.Valid == 0) || #endif #if (_MI_PAGING_LEVELS >= 3) (PointerPpe->u.Hard.Valid == 0) || #endif (PointerPde->u.Hard.Valid == 0) ||
((!MI_PDE_MAPS_LARGE_PAGE (PointerPde)) && (PointerPte->u.Hard.Valid == 0))) { // 条件二
if (KeInvalidAccessAllowed (TrapInformation) == TRUE) { return STATUS_ACCESS_VIOLATION; }
KdPrint(("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n", VirtualAddress, PreviousIrql));
if (TrapInformation != NULL) { MI_DISPLAY_TRAP_INFORMATION (TrapInformation); }
// // Signal the fatal error to the trap handler. //
return STATUS_IN_PAGE_ERROR | 0x10000000; // ~
}
......
}
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-17, 22:23 下午
|
格蠹老雷
注册: 2005-12-19
发 贴: 1,303
|
|
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
2009-08-17, 22:40 下午
|
yushang
注册: 2009-08-10
发 贴: 27
|
|
|
回过头来看看汇编,似乎下面这一段是和所贴代码对应的 ...
call dword ptr [nt!_imp__KeGetCurrentIrql (804d9108)] ;PreviousIrql
cmp al,1 ;和APC_LEVEL比较
mov byte ptr [ebp-2],al
jbe nt!MmAccessFault+0x185
//>APC_LEVEL,进一步判断第二个条件,如果也满足就BSOD了
mov ecx,ebx
call nt!MiCheckPdeForPagedPool
...
|
|
|
IP 地址: 已记录
|
报告
|
|
|
|
高端调试 » 软件调试 » Windows内核调试 » IRQL规则
|
|
|
|
|
|