Advanced Debugging
About AdvDbg Consult Train Services Products Tools Community Contact  
欢迎光临 高端调试 登录 | 注册 | FAQ
 
  ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
 
  格蠹调试套件(GDK)
  格蠹学院
  小朱书店
  老雷的微博
  《软件调试》
  《格蠹汇编》
  《软件调试(第二版)》
沪ICP备11027180号-1

Windows内核调试

帖子发起人: 明眸的心   发起时间: 2010-02-08 09:25 上午   回复: 1

Print Search
帖子排序:    
   2010-02-08, 09:25 上午
ylb001 离线,最后访问时间: 2010/11/2 8:39:20 明眸的心

发帖数前150位
注册: 2009-01-05
发 贴: 7
替换KiDisPatchException函数时蓝屏
Reply Quote
请教一下张老师,以下蓝屏可以帮我分析下?我是打算,替换CommonDispatchException()函数里的Call KiDispatchException的代码,直接CALL 我自己的HxKiDispatchException(),这代码就是WRK的,代码贴在下面了,没有改多少,蓝屏出现在这函数第一句代码
KeGetCurrentPrcb()>KeExceptionDispatchCount= 1;
DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: ffff0020, memory referenced
Arg2: 000000ff, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: b2ef2c9e, address which referenced memory

Debugging Details:
------------------

READ_ADDRESS: ffff0020

CURRENT_IRQL: ff

FAULTING_IP:
hxdbgkrnl!HxKiDispatchException+2e [f:\ÄúoËμ÷êÔÆ÷\hxdbgkrnl\hxexception.c @ 77]
b2ef2c9e ?? ???

CUSTOMER_CRASH_COUNT: 1

DEFAULT_BUCKET_ID: DRIVER_FAULT

BUGCHECK_STR: 0xD1

TRAP_FRAME: b36ae1dc -- (.trap 0xffffffffb36ae1dc)
ErrCode = 00000000
eax=00000020 ebx=b36ae660 ecx=b36ae64c edx=00000001 esi=b36ae794 edi=0000001a
eip=b2ef2c9e esp=b36ae250 ebp=b36ae630 iopl=0 nv up di ng nz na pe cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010087
hxdbgkrnl!HxKiDispatchException+0x2e:
b2ef2c9e ?? ???
Resetting default scope

LAST_CONTROL_TRANSFER: from b2ef2c9e to 80545700

STACK_TEXT:
b36ae1dc b2ef2c9e badb0d00 00000001 8a7040e8 nt!KiTrap0E+0x238
b36ae630 805430a5 b36ae64c 00000000 b36ae6a0 hxdbgkrnl!HxKiDispatchException+0x2e [f:\ÄúoËμ÷êÔÆ÷\hxdbgkrnl\hxexception.c @ 77]
b36ae698 805437fe b36ae728 80532ea1 badb0d00 nt!CommonDispatchException+0x4d
b36ae698 80532ea2 b36ae728 80532ea1 badb0d00 nt!KiTrap03+0xae
b36ae728 80532eec 00000001 b36ae794 0000001a nt!DebugService+0x1c
b36ae744 b4b4d951 b36ae77c ffffffff 00000000 nt!DebugPrint+0x1c
WARNING: Stack unwind information not available. Following frames may be wrong.
b36ae75c 8052c6fb b36ae77c ffffffff 00000000 Dbgv+0x951
b36ae9b0 8052c890 8052c870 ffffffff 00000000 nt!vDbgPrintExWithPrefix+0x101
b36ae9cc b2ef32ac b2ef6714 000000e8 00000037 nt!DbgPrint+0x1a
b36aea7c b2ef337c 8050375a 8050375a b36aeae4 hxdbgkrnl!Search_CallFunction+0xfc [f:\ÄúoËμ÷êÔÆ÷\hxdbgkrnl\hxhook.c @ 144]
b36aeaf0 b2ef255c 890c1160 89ed2cd0 88bacf68 hxdbgkrnl!StartHook+0x5c [f:\ÄúoËμ÷êÔÆ÷\hxdbgkrnl\hxhook.c @ 174]
b36aebf8 804f019f 887f6a48 88bacf68 806e7410 hxdbgkrnl!HxCtrl+0x26c [f:\ÄúoËμ÷êÔÆ÷\hxdbgkrnl\hxdbgkrnl.c @ 363]
b36aec08 80580982 88bacfd8 890c1160 88bacf68 nt!IopfCallDriver+0x31
b36aec1c 805817f7 887f6a48 88bacf68 890c1160 nt!IopSynchronousServiceTail+0x70
b36aecb8 8057a274 00000140 00000000 00000000 nt!IopXxxControlFile+0x5c5
b36aecec b6e52830 00000140 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
b36aed34 8054263c 00000140 00000000 00000000 klif+0x10830
b36aed34 7c92e514 00000140 00000000 00000000 nt!KiFastCallEntry+0xfc
0012db54 00000000 00000000 00000000 00000000 0x7c92e514


STACK_COMMAND: kb

FOLLOWUP_IP:
hxdbgkrnl!HxKiDispatchException+2e [f:\ÄúoËμ÷êÔÆ÷\hxdbgkrnl\hxexception.c @ 77]
b2ef2c9e ?? ???

SYMBOL_STACK_INDEX: 1

SYMBOL_NAME: hxdbgkrnl!HxKiDispatchException+2e

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: hxdbgkrnl

IMAGE_NAME: hxdbgkrnl.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 4b686871

FAILURE_BUCKET_ID: 0xD1_hxdbgkrnl!HxKiDispatchException+2e

BUCKET_ID: 0xD1_hxdbgkrnl!HxKiDispatchException+2e

Followup: MachineOwner


VOID WINAPI
HxKiDispatchException (
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN FirstChance
)
{
CONTEXT ContextFrame;
EXCEPTION_RECORD ExceptionRecord1, ExceptionRecord2;
LONG Length;
ULONG UserStack1;
ULONG UserStack2;

//
// Move machine state from trap and exception frames to a context frame,
// and increment the number of exceptions dispatched.
//

KeGetCurrentPrcb()->KeExceptionDispatchCount= 1;
ContextFrame.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;

if ((PreviousMode == UserMode) || KdDebuggerEnabled) {
//
// For usermode exceptions always try to dispatch the floating
// point state. This allows exception handlers & debuggers to
// examine/edit the npx context if required. Plus it allows
// exception handlers to use fp instructions without destroying
// the npx state at the time of the exception.
//
// Note: If there's no 80387, ContextTo/FromKFrames will use the
// emulator's current state. If the emulator can not give the
// current state, then the context_floating_point bit will be
// turned off by ContextFromKFrames.
//

ContextFrame.ContextFlags |= CONTEXT_FLOATING_POINT;
if (KeI386XMMIPresent) {
ContextFrame.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
}
}

KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);

//
// if it is BREAK_POINT exception, we subtract 1 from EIP and report
// the updated EIP to user. This is because Cruiser requires EIP
// points to the int 3 instruction (not the instruction following int 3).
// In this case, BreakPoint exception is fatal. Otherwise we will step
// on the int 3 over and over again, if user does not handle it
//
// if the BREAK_POINT occured in V86 mode, the debugger running in the
// VDM will expect CS:EIP to point after the exception (the way the
// processor left it. this is also true for protected mode dos
// app debuggers. We will need a way to detect this.
//
//

switch (ExceptionRecord->ExceptionCode) {
case STATUS_BREAKPOINT:
ContextFrame.Eip--;
break;

case KI_EXCEPTION_ACCESS_VIOLATION:
ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
if (PreviousMode == UserMode) {
if (KiCheckForAtlThunk(ExceptionRecord,&ContextFrame) != FALSE) {
goto Handled1;
}

if ((SharedUserData->ProcessorFeatures[PF_NX_ENABLED] == TRUE) &&
(ExceptionRecord->ExceptionInformation [0] == 8/*EXCEPTION_EXECUTE_FAULT*/)) {

if (((KeFeatureBits & KF_GLOBAL_32BIT_EXECUTE) != 0) ||
(PsGetCurrentProcess()->Pcb.Flags.ExecuteEnable != 0) ||
(((KeFeatureBits & KF_GLOBAL_32BIT_NOEXECUTE) == 0) &&
(PsGetCurrentProcess()->Pcb.Flags.ExecuteDisable == 0))) {
ExceptionRecord->ExceptionInformation [0] = 0;
}
}
}
break;
}

//
// Select the method of handling the exception based on the previous mode.
//

ASSERT ((
!((PreviousMode == KernelMode) &&
(ContextFrame.EFlags & EFLAGS_V86_MASK))
));

if (PreviousMode == KernelMode) {

//
// Previous mode was kernel.
//
// If the kernel debugger is active, then give the kernel debugger the
// first chance to handle the exception. If the kernel debugger handles
// the exception, then continue execution. Else attempt to dispatch the
// exception to a frame based handler. If a frame based handler handles
// the exception, then continue execution.
//
// If a frame based handler does not handle the exception,
// give the kernel debugger a second chance, if it's present.
//
// If the exception is still unhandled, call KeBugCheck().
//

if (FirstChance == TRUE) {

if ((KiDebugRoutine != NULL) &&
(((KiDebugRoutine) (TrapFrame,
ExceptionFrame,
ExceptionRecord,
&ContextFrame,
PreviousMode,
FALSE)) != FALSE)) {

goto Handled1;
}

// Kernel debugger didn't handle exception.

if (RtlDispatchException(ExceptionRecord, &ContextFrame) == TRUE) {
goto Handled1;
}
}

//
// This is the second chance to handle the exception.
//

if ((KiDebugRoutine != NULL) &&
(((KiDebugRoutine) (TrapFrame,
ExceptionFrame,
ExceptionRecord,
&ContextFrame,
PreviousMode,
TRUE)) != FALSE)) {

goto Handled1;
}

KeBugCheckEx(
KERNEL_MODE_EXCEPTION_NOT_HANDLED,
ExceptionRecord->ExceptionCode,
(ULONG)ExceptionRecord->ExceptionAddress,
(ULONG)TrapFrame,
0);

} else {

//
// Previous mode was user.
//
// If this is the first chance and the current process has a debugger
// port, then send a message to the debugger port and wait for a reply.
// If the debugger handles the exception, then continue execution. Else
// transfer the exception information to the user stack, transition to
// user mode, and attempt to dispatch the exception to a frame based
// handler. If a frame based handler handles the exception, then continue
// execution with the continue system service. Else execute the
// NtRaiseException system service with FirstChance == FALSE, which
// will call this routine a second time to process the exception.
//
// If this is the second chance and the current process has a debugger
// port, then send a message to the debugger port and wait for a reply.
// If the debugger handles the exception, then continue execution. Else
// if the current process has a subsystem port, then send a message to
// the subsystem port and wait for a reply. If the subsystem handles the
// exception, then continue execution. Else terminate the process.
//


if (FirstChance == TRUE) {

//
// This is the first chance to handle the exception.
//

if ((KiDebugRoutine != NULL) &&
((PsGetCurrentProcess()->DebugPort == NULL /*&&
!KdIgnoreUmExceptions*/) ||
(KdIsThisAKdTrap(ExceptionRecord, &ContextFrame, UserMode)))) {
//
// Now dispatch the fault to the kernel debugger.
//

if ((((KiDebugRoutine) (TrapFrame,
ExceptionFrame,
ExceptionRecord,
&ContextFrame,
PreviousMode,
FALSE)) != FALSE)) {

goto Handled1;
}
}

if (HxDbgkForwardException(ExceptionRecord, TRUE, FALSE)) {
goto Handled2;
}

//
// Transfer exception information to the user stack, transition
// to user mode, and attempt to dispatch the exception to a frame
// based handler.

ExceptionRecord1.ExceptionCode = 0; // satisfy no_opt compilation

repeat:
try {

//
// If the SS segment is not 32 bit flat, there is no point
// to dispatch exception to frame based exception handler.
//

if (TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK) ||
TrapFrame->EFlags & EFLAGS_V86_MASK ) {
ExceptionRecord2.ExceptionCode = STATUS_ACCESS_VIOLATION;
ExceptionRecord2.ExceptionFlags = 0;
ExceptionRecord2.NumberParameters = 0;
ExRaiseException(&ExceptionRecord2);
}

//
// Compute length of context record and new aligned user stack
// pointer.
//

UserStack1 = (ContextFrame.Esp & ~CONTEXT_ROUND) - CONTEXT_ALIGNED_SIZE;

//
// Probe user stack area for writability and then transfer the
// context record to the user stack.
//

ProbeForWrite((PCHAR)UserStack1, CONTEXT_ALIGNED_SIZE, CONTEXT_ALIGN);
RtlCopyMemory((PULONG)UserStack1, &ContextFrame, sizeof(CONTEXT));

//
// Compute length of exception record and new aligned stack
// address.
//

Length = (sizeof(EXCEPTION_RECORD) - (EXCEPTION_MAXIMUM_PARAMETERS -
ExceptionRecord->NumberParameters) * sizeof(ULONG) +3) &
(~3);
UserStack2 = UserStack1 - Length;

//
// Probe user stack area for writeability and then transfer the
// context record to the user stack area.
// N.B. The probing length is Length+8 because there are two
// arguments need to be pushed to user stack later.
//

ProbeForWrite((PCHAR)(UserStack2 - 8), Length + 8, sizeof(ULONG));
RtlCopyMemory((PULONG)UserStack2, ExceptionRecord, Length);

//
// Push address of exception record, context record to the
// user stack. They are the two parameters required by
// _KiUserExceptionDispatch.
//

*(PULONG)(UserStack2 - sizeof(ULONG)) = UserStack1;
*(PULONG)(UserStack2 - 2*sizeof(ULONG)) = UserStack2;

//
// Set new stack pointer to the trap frame.
//

KiSegSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
KiEspToTrapFrame(TrapFrame, (UserStack2 - sizeof(ULONG)*2));

//
// Force correct R3 selectors into TrapFrame.
//

TrapFrame->SegCs = SANITIZE_SEG(KGDT_R3_CODE, PreviousMode);
TrapFrame->SegDs = SANITIZE_SEG(KGDT_R3_DATA, PreviousMode);
TrapFrame->SegEs = SANITIZE_SEG(KGDT_R3_DATA, PreviousMode);
TrapFrame->SegFs = SANITIZE_SEG(KGDT_R3_TEB, PreviousMode);
TrapFrame->SegGs = 0;

//
// Set the address of the exception routine that will call the
// exception dispatcher and then return to the trap handler.
// The trap handler will restore the exception and trap frame
// context and continue execution in the routine that will
// call the exception dispatcher.
//

TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
return;

} except (KiCopyInformation(&ExceptionRecord1,
(GetExceptionInformation())->ExceptionRecord)) {

//
// If the exception is a stack overflow, then attempt
// to raise the stack overflow exception. Otherwise,
// the user's stack is not accessible, or is misaligned,
// and second chance processing is performed.
//

if (ExceptionRecord1.ExceptionCode == STATUS_STACK_OVERFLOW) {
ExceptionRecord1.ExceptionAddress = ExceptionRecord->ExceptionAddress;
RtlCopyMemory((PVOID)ExceptionRecord,
&ExceptionRecord1, sizeof(EXCEPTION_RECORD));
goto repeat;
}
}
}

//
// This is the second chance to handle the exception.
//

if (HxDbgkForwardException(ExceptionRecord, TRUE, TRUE)) {
goto Handled2;
} else if (HxDbgkForwardException(ExceptionRecord, FALSE, TRUE)) {
goto Handled2;
} else {
ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
KeBugCheckEx(
KERNEL_MODE_EXCEPTION_NOT_HANDLED,
ExceptionRecord->ExceptionCode,
(ULONG)ExceptionRecord->ExceptionAddress,
(ULONG)TrapFrame,
0);
}
}

//
// Move machine state from context frame to trap and exception frames and
// then return to continue execution with the restored state.
//

Handled1:

KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame,
ContextFrame.ContextFlags, PreviousMode);

//
// Exception was handled by the debugger or the associated subsystem
// and state was modified, if necessary, using the get state and set
// state capabilities. Therefore the context frame does not need to
// be transferred to the trap and exception frames.
//

Handled2:
return;
}
IP 地址: 已记录   报告
   2010-02-08, 20:58 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: 替换KiDisPatchException函数时蓝屏
Reply Quote

首先,WRK的代码是有协议保护的,建议只在协议许可的方式和范围内使用。

KiDispatchException是系统中分发异常的枢纽,是非常繁忙而且重要的一个函数。使用WinDBG调试时,甚至不可以对这个函数设置断点,一旦设置,便会导致目标立刻重启......

从贴出的信息来看,是访问当前CPU的处理器控制块(KPRCB)时导致异常了。

对于单处理系统,CPU的KPCR结构的位置是固定的FFDFF000,因此KeGetCurrentPrcb()通常被编译为:

mov     eax,dword ptr ds:[FFDFF020h]

因为KPCR结构偏移0x20处是Prcb字段。

对于多处理器系统,会使用FS段来索引KPCR,因此KeGetCurrentPrcb()通常被编译为:

mov     eax,dword ptr fs:[00000020h]

从异常信息来看,访问的地址是ffff0020:

Arg1: ffff0020, memory referenced

从这个地址来看,很可能是把KPCR的位置当做是ffff0000,然后读偏移0x20处的Prcb字段。

但是ffff0020这个地址不可读,CPU报告异常。对于正常情况KPCR一定是常驻内存的。所以现在出问题应该是没有找到KPCR的正确位置,或者出现了严重的内存问题。

建议执行如下命令看一下:

!pcrb

dg fs

另外想知道,是运行一段时间出问题时,还是一运行(驱动加载)就出问题?

 


IP 地址: 已记录   报告
高端调试 » 软件调试 » Windows内核调试 » 替换KiDisPatchException函数时蓝屏

 
Legal Notice Privacy Statement Corporate Governance Corporate Governance
(C)2004-2020 ADVDBG.ORG All Rights Reserved.