闲话少说,直奔主题,首先OD载入一个程序,然后执行一下单步(调试器会将TF置1)
此时,CPU会在基于当前线程上下文的环境中,进入int 1的中断门,也就是KiTrap01
kd> !idt -a
Dumping IDT:
00: 805431a0 nt!KiTrap00
01: 8054331c nt!KiTrap01 // int 1会转到这个函数执行
02: Task Selector = 0x0058 // NMI 从这里可以看到NMI是通过任务门执行的
03: 80543730 nt!KiTrap03
04: 805438b0 nt!KiTrap04
05: 80543a10 nt!KiTrap05
06: 80543b84 nt!KiTrap06
07: 805441fc nt!KiTrap07
08: Task Selector = 0x0050 // DF 因为发生DF时,寄存器可能已经出错了,所以需要任务门,加载新的环境
09: 80544600 nt!KiTrap09
然后我们看下windbg,首先在KiTrap01下断,其次通过OD的单步后,确实已经中断到windbg的KiTrap01处了,其环境也是被调试线程的环境
看下TSS中ESP0的值
kd> r tr
tr=00000028
kd> dg 28
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0028 80042000 000020ab TSS32 Busy 0 Nb By P Nl 0000008b
kd> dd 80042000
80042000 0c458b24 b23b9de0 8b080010 758b0855 //b23b9de0就是ESP0的值
intel手册中说到,在转移到中断例程入口前,会先将SS ESP EFLAGS CS EIP ErrorCode压入内核栈,所以我们看看ESP0中的值
kd> dd esp
b23b9dcc 00421480 0000001b 00000346 0012ffc0
b23b9ddc 00000023 //从这里可以得知 SS:23 ESP:12FFC0 EFLAGS:346 CS:1b EIP:421480
好了,可以进入正题了,先看下KiTrap01的执行过程
nt!KiTrap01:
8054331c 6a00 push 0 // ErrorCode
8054331e 66c74424020000 mov word ptr [esp+2],0
80543325 55 push ebp
80543326 53 push ebx
80543327 56 push esi
80543328 57 push edi
80543329 0fa0 push fs
8054332b bb30000000 mov ebx,30h
80543330 668ee3 mov fs,bx
80543333 648b1d00000000 mov ebx,dword ptr fs:[0]
8054333a 53 push ebx // ExceptionList
8054333b 83ec04 sub esp,4 // PreviousPreviousMode
8054333e 50 push eax
8054333f 51 push ecx
80543340 52 push edx
80543341 1e push ds
80543342 06 push es
80543343 0fa8 push gs
80543345 66b82300 mov ax,23h
80543349 83ec30 sub esp,30h // 到这里_KTRAP_FRAME已经填充一半了,还差30h
8054334c 668ed8 mov ds,ax
8054334f 668ec0 mov es,ax
80543352 8bec mov ebp,esp
80543354 f744247000000200 test dword ptr [esp+70h],20000h // 检测是否是虚拟8086模式
8054335c 7596 jne nt!V86_kit1_a (805432f4) // 是虚拟8086模式的话,就发生跳转,这里我们应该继续执行
8054335e fc cld
8054335f 8b5d60 mov ebx,dword ptr [ebp+60h] // 被压入栈的EBP寄存器的值,这里是12FFF0
80543362 8b7d68 mov edi,dword ptr [ebp+68h] // 被压入栈中EIP寄存器的值,这里是421480
80543365 89550c mov dword ptr [ebp+0Ch],edx // KiFastSystemCall
80543368 c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h // DbgArgMark
8054336f 895d00 mov dword ptr [ebp],ebx // DbgEbp
80543372 897d04 mov dword ptr [ebp+4],edi // DbgEip
/**************************************************************************************************************************************
/***** 执行完这几个栈操作后,我们看下栈中的值 *****
/**************************************************************************************************************************************
kd> dd ebp 其实这里都是KTRAP_FTAME的值
b23b9d64 0012fff0 00421480 badb0d00 7c92e4f4
b23b9d74 7c930208 ffffffff ffffffff 0012fff0
b23b9d84 00000000 80543349 00000008 00000196
b23b9d94 00000000 00000023 00000023 7c92e4f4
b23b9da4 0012ffb0 00000000 00000146 ffffffff
b23b9db4 00000030 7c930208 ffffffff 7ffd8000
b23b9dc4 0012fff0 00000000 00421480 0000001b
b23b9dd4 00000346 0012ffc0 00000023 805470de
80543375 64f60550000000ff test byte ptr fs:[50h],0FFh // 测试DebugActive
8054337d 0f85edfeffff jne nt!Dr_kit1_a (80543270)
80543383 64833d5400000000 cmp dword ptr fs:[54h],0
8054338b 7561 jne nt!KiTrap01+0xd2 (805433ee)
8054338d 8b4d68 mov ecx,dword ptr [ebp+68h]
80543390 81f920255480 cmp ecx,offset nt!KiFastCallEntry (80542520)
80543396 0f84c4feffff je nt!KiTrap00+0xc0 (80543260) // 测试是不是sysenter指令,如果是的话,不能步过
8054339c f7457000000200 test dword ptr [ebp+70h],20000h
805433a3 7524 jne nt!KiTrap01+0xad (805433c9) // 检测虚拟8086模式
805433a5 66f7456c0100 test word ptr [ebp+6Ch],1
805433ab 7408 je nt!KiTrap01+0x99 (805433b5) // 检测当前CPL,如果是R3的话,就不发生跳转
805433ad 66837d6c1b cmp word ptr [ebp+6Ch],1Bh
805433b2 7515 jne nt!KiTrap01+0xad (805433c9) // 如果是R3的话,CS应该是1B,如果不是的话,发生跳转
805433b4 fb sti
805433b5 816570fffeffff and dword ptr [ebp+70h],0FFFFFEFFh //EFLAGS的TF位清零
805433bc 8b5d68 mov ebx,dword ptr [ebp+68h] // (ebx)-> faulting instruction
805433bf b804000080 mov eax,80000004h // TF异常的错误码
805433c4 e94efcffff jmp nt!KiExceptionExit+0x16b (80543017)
80543017 33c9 xor ecx,ecx
80543019 e81a000000 call nt!CommonDispatchException (80543038) // Never return
接下来看看CommonDispatchException内部都做了些什么
/**********************************************************************************************
/***** Set up exception record for raising exception *****
/**********************************************************************************************
首先来看看EXCEPTION_RECORD
kd> dt _exception_record
nt!_EXCEPTION_RECORD
+0x000 ExceptionCode : Int4B
+0x004 ExceptionFlags : Uint4B
+0x008 ExceptionRecord : Ptr32 _EXCEPTION_RECORD
+0x00c ExceptionAddress : Ptr32 Void
+0x010 NumberParameters : Uint4B
+0x014 ExceptionInformation : [15] Uint4B
nt!CommonDispatchException:
80543038 83ec50 sub esp,50h // ExceptionRecordLength, allocate exception record
8054303b 890424 mov dword ptr [esp],eax // set ExceptionCode 其实也就是上文的80000004h
8054303e 33c0 xor eax,eax
80543040 89442404 mov dword ptr [esp+4],eax // set ExceptionFlags 这里为0
80543044 89442408 mov dword ptr [esp+8],eax // set associated ExceptionRecord 这里为0
80543048 895c240c mov dword ptr [esp+0Ch],ebx // set ExceptionAddress 其实也就是上文的421480
8054304c 894c2410 mov dword ptr [esp+10h],ecx // set NumberParameters 这里为0
80543050 83f900 cmp ecx,0
80543053 740c je nt!CommonDispatchException+0x29 (80543061)
//跳到了这里 set up arguments and call _KiDispatchException
80543061 8bcc mov ecx,esp // (ecx)->exception record
80543063 f7457000000200 test dword ptr [ebp+70h],20000h
8054306a 7407 je nt!CommonDispatchException+0x3b (80543073) // 因为不是虚拟8086模式,所以会发生跳转
//跳转到这里后,就该调用KiDispatchException了
stdCall _KiDispatchException,<ecx, 0, ebp, eax, 1> // 汇编中的原型
KiDispatchException ( // API中的原型
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN FirstChance
)
80543073 8b456c mov eax,dword ptr [ebp+6Ch]
80543076 83e001 and eax,1 // 通过CS段选择子,得到被调试程序的CPL, 通过与运算后,得到后面的PreviousMode
80543079 6a01 push 1 // 1 - first chance TRUE
8054307b 50 push eax // eax - PreviousMode
8054307c 55 push ebp // TrapFrame
8054307d 6a00 push 0 // ExceptionFrame
8054307f 51 push ecx // ExceptionRecord
80543080 e8e1c3fbff call nt!KiDispatchException (804ff466)
这里再看看我们的KTRAP_FRAME的具体值,这些值能很详细的说明故障信息
kd> dt _ktrap_frame b2bf3d64
nt!_KTRAP_FRAME
+0x000 DbgEbp : 0x12fff0
+0x004 DbgEip : 0x421480
+0x008 DbgArgMark : 0xbadb0d00
+0x00c DbgArgPointer : 0x7c92e4f4
+0x010 TempSegCs : 0x7c930208
+0x014 TempEsp : 0xffffffff
+0x018 Dr0 : 0xffffffff
+0x01c Dr1 : 0x12fff0
+0x020 Dr2 : 0
+0x024 Dr3 : 0x80543349
+0x028 Dr6 : 8
+0x02c Dr7 : 0x196
+0x030 SegGs : 0
+0x034 SegEs : 0x23
+0x038 SegDs : 0x23
+0x03c Edx : 0x7c92e4f4
+0x040 Ecx : 0x12ffb0
+0x044 Eax : 0
+0x048 PreviousPreviousMode : 0x146
+0x04c ExceptionList : 0xffffffff _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs : 0x30
+0x054 Edi : 0x7c930208
+0x058 Esi : 0xffffffff
+0x05c Ebx : 0x7ffd8000
+0x060 Ebp : 0x12fff0
+0x064 ErrCode : 0
+0x068 Eip : 0x421480
+0x06c SegCs : 0x1b
+0x070 EFlags : 0x246
+0x074 HardwareEsp : 0x12ffc0
+0x078 HardwareSegSs : 0x23
+0x07c V86Es : 0
+0x080 V86Ds : 0
+0x084 V86Fs : 0
+0x088 V86Gs : 0
好了,先分析到这吧,明天分析KiDispatchException这个函数......困了!
01:08:21