2015-02-07 148 views
4

有没有办法在Windows上的中断服务例程上设置断点,它负责触发线程调度并打印被中断的线程的EIP?Windbg:打破定时器/调度程序中断和打印EIP

我试图用hal!HalpClockInterrupt但它似乎不是正确的地方。 nt!KeUpdateRunTime接缝更好:

Breakpoint 3 hit 
nt!KeUpdateRunTime: 
805410dc a11cf0dfff  mov  eax,dword ptr ds:[FFDFF01Ch] 
kd> !thread 
THREAD 82c23bf0 Cid 0320.0474 Teb: 7ffa2000 Win32Thread: 00000000 RUNNING on processor 0 
Impersonation token: e1c1f990 (Level Impersonation) 
Owning Process   0  Image:   <Unknown> 
Attached Process   82c2dca0  Image:   svchost.exe 
Wait Start TickCount  6298   Ticks: 14 (0:00:00:00.218) 
Context Switch Count  64    IdealProcessor: 0    
UserTime     00:00:00.453 
KernelTime    00:00:04.312 
Win32 Start Address 0x7730a5f7 
Start Address 0x7c8106f9 
Stack Init f4dc1000 Current f4dc0d34 Base f4dc1000 Limit f4dbe000 Call 0 
Priority 8 BasePriority 8 PriorityDecrement 0 DecrementCount 0 
ChildEBP RetAddr Args to Child    
f4dc0d54 805410ae 00000000 000000d1 0197fb94 nt!KeUpdateRunTime (FPO: [1,1,0]) 
f4dc0d54 806d2c9e 00000000 000000d1 0197fb94 nt!KeUpdateSystemTime+0x13e (FPO: [0,2] TrapFrame @ f4dc0cdc) 
f4dc0d54 805410ae 00000000 000000d1 0197fb94 hal!HalEndSystemInterrupt+0x4e (FPO: [2,2,0]) 
f4dc0d54 77306f5f 00000000 000000d1 0197fb94 nt!KeUpdateSystemTime+0x13e (FPO: [0,2] TrapFrame @ f4dc0d64) 
WARNING: Frame IP not in any known module. Following frames may be wrong. 
0197fb94 77308dc1 0197fbdc 025c1ec0 03478e70 0x77306f5f 
0197fbbc 77309b4a 0197fbdc 00000000 00000001 0x77308dc1 
0197ff18 7730a711 02560008 00000000 00000000 0x77309b4a 
0197ffb4 7c80b729 00000000 00000000 00000000 0x7730a711 
0197ffec 00000000 7730a5f7 00000000 00000000 0x7c80b729 

问题仍然是开放的如何获得EIP。似乎Windbg知道如何做,但我想了解如何。看起来_KTRAP_FRAME在_KTHREAD-> KernelStack-4上。

回答

4

你非常接近,但是由于当前正在运行的线程被一个中断中断,所以KTRAP_FRAME(被中断的线程保存的寄存器)被放到栈中那个时候(当调用KeUpdateSystemTime()时)。

(注意:在Windows XP SP3 x86上进行实时内核调试)。

重新加载hal符号;看到bps,同时走:

0: kd>.reload /f hal 
0: kd> bl 
0 e 805450d0  0001 (0001) nt!KeUpdateSystemTime 
1 e 806e5e54  0001 (0001) hal!HalpClockInterrupt 
0: kd> g 

OK,BP击中NT KeUpdateSystemTime:

Breakpoint 0 hit 
nt!KeUpdateSystemTime: 
805450d0 b90000dfff  mov  ecx,0FFDF0000h 

让我们看到了堆,包括FPO和陷阱帧:

0: kd> kv 
ChildEBP RetAddr Args to Child    
afb47d64 004482ef badb0d00 01bbb9c4 00000000 nt!KeUpdateSystemTime (FPO: [0,2] TrapFrame @ afb47d64) 
WARNING: Stack unwind information not available. Following frames may be wrong. 
01f9d814 004483f1 01bb0020 01bbb9c4 000006a2 gfsvc32+0x482ef 
01f9d828 004488ef 02c108c0 00081000 000003e8 gfsvc32+0x483f1 
01f9d890 0044dc92 000102ee 01f9fd8c 02c108c0 gfsvc32+0x488ef 
01f9feac 00437c59 000102ee 00000c90 00000000 gfsvc32+0x4dc92 
01f9ffb4 7c80b729 00c9cb40 01e9fffc 00000020 gfsvc32+0x37c59 
01f9ffe0 7c80b72f 00000000 00000000 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo]) 
01f9ffe4 00000000 00000000 00000000 004a6727 kernel32!BaseThreadStart+0x3d (FPO: [Non-Fpo]) 

用户级线程被中断,陷阱帧位于0x afb47d64。让我们来看看线程:

0: kd> !thread 
THREAD 8a3702e8 Cid 0c90.0cf8 Teb: 7ffd5000 Win32Thread: e198a360 RUNNING on processor 0 
Not impersonating 
DeviceMap     e1f236f0 
Owning Process   0  Image:   <Unknown> 
Attached Process   89e7fda0  Image:   testk.exe 
Wait Start TickCount  21252   Ticks: 2 (0:00:00:00.031) 
Context Switch Count  45160   IdealProcessor: 0     LargeStack 
UserTime     00:00:18.281 
KernelTime    00:00:20.125 
Win32 Start Address 0x004a6727 
Start Address kernel32!BaseThreadStartThunk (0x7c810729) 
Stack Init afb48000 Current afb479c4 Base afb48000 Limit afb44000 Call 0 
Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 16 
ChildEBP RetAddr Args to Child    
afb47d64 004482ef badb0d00 01bbb9c4 00000000 nt!KeUpdateSystemTime (FPO: [0,2] TrapFrame @ afb47d64) 
WARNING: Stack unwind information not available. Following frames may be wrong. 
01f9d814 004483f1 01bb0020 01bbb9c4 000006a2 gfsvc32+0x482ef 
01f9d828 004488ef 02c108c0 00081000 000003e8 gfsvc32+0x483f1 
01f9d890 0044dc92 000102ee 01f9fd8c 02c108c0 gfsvc32+0x488ef 
01f9feac 00437c59 000102ee 00000c90 00000000 gfsvc32+0x4dc92 
01f9ffb4 7c80b729 00c9cb40 01e9fffc 00000020 gfsvc32+0x37c59 
01f9ffe0 7c80b72f 00000000 00000000 00000000 kernel32!BaseThreadStart+0x37 (FPO: [Non-Fpo]) 
01f9ffe4 00000000 00000000 00000000 004a6727 kernel32!BaseThreadStart+0x3d (FPO: [Non-Fpo]) 

所以,当线程被中断,HAL HalpClockInterrupt()被调用(见IDT -a为ISR的!),又是陷阱框架是建立!陷阱帧指针是当前在EBP寄存器:

0: kd> r @ebp 
ebp=afb47d64 

所以,EBP =指针KTRAP_FRAME = 0X afb47d64

陷阱帧像,因为它使所有寄存器从“上下文”结构中断的线程。让我们来看看什么是EIP的偏移:

0: kd> dt nt!_ktrap_frame eip 
    +0x068 Eip : Uint4B 

EIP是在KTRAP_FRAME结构偏移0x68。只需应用偏移量:

0: kd> dd @ebp+0x68 L1 
afb47dcc 004482ef 

在EIP = 0x4482ef时用户面线程被中断。让我们证实了这一点使用“.trap”命令(可能是” .trap afb47d64' 而不是使用@ebp):

0: kd> .trap @ebp 
ErrCode = 00000000 
eax=00002ba2 ebx=00c9cb40 ecx=01bb0020 edx=01bbb9c4 esi=00c9cb40 edi=01e9fffc 
eip=004482ef esp=01f9d814 ebp=01f9d814 iopl=0   nv up ei pl nz na po nc 
cs=001b ss=0023 ds=0023 es=0023 fs=0030 gs=0000    efl=00000202 
gfsvc32+0x482ef: 
001b:004482ef eb07   jmp  gfsvc32+0x482f8 (004482f8) 

顺便说一句,你可以很容易地看到陷阱框架是如何构建的HAL HalpClockInterrupt(! ),通过分解它:

0: kd> u hal!HalpClockInterrupt L0n10 
hal!HalpClockInterrupt: 
806e5e54 54    push esp 
806e5e55 55    push ebp 
806e5e56 53    push ebx 
806e5e57 56    push esi 
806e5e58 57    push edi 
806e5e59 83ec54   sub  esp,54h 
806e5e5c 8bec   mov  ebp,esp 
806e5e5e 89442444  mov  dword ptr [esp+44h],eax 
806e5e62 894c2440  mov  dword ptr [esp+40h],ecx 
806e5e66 8954243c  mov  dword ptr [esp+3Ch],edx 

见上面的偏移量对应于KTRAP_FRAME成员偏移如何:

0: kd> dt nt!_ktrap_frame eax 
    +0x044 Eax : Uint4B 
0: kd> dt nt!_ktrap_frame ecx 
    +0x040 Ecx : Uint4B 
0: kd> dt nt!_ktrap_frame edx 
    +0x03c Edx : Uint4B 

希望这回答了你的问题。

- 编辑 -

由于我的例子是在Win XP SP3,则可能对其他Windows系统不同的功能名称。

Win8.1(x86)上的示例。如果你不能找到时钟中断函数的名字,我会想办法先检查IDT:

0: kd>idt -a 
[...snip...] 
6b2ac55a000000d1: 81a237c8 hal!HalpTimerClockInterrupt 
6b2ac55a000000d2: 81a23aa4 hal!HalpTimerClockIpiRoutine 
[...snip...] 

只有两个256个向量都具有“时钟”,在他们的名字(注意,一个是IPI [处理器间中断],另一个是通常的时钟中断)。

我会去hal!HalpTimerClockInterrupt,尝试进入这个函数,看看哪些函数稍后调用。

它发生,你可以打破NT KiUpdateTime或NT KiUpdateRunTime功能:

0: kd> !thread 
THREAD 9d0af680 Cid 0bec.0bf0 Teb: 7f8ae000 Win32Thread: 9ce51470 RUNNING on processor 0 
Not impersonating 
DeviceMap     a0971118 
Owning Process   9d161c40  Image:   calc.exe 
Attached Process   N/A   Image:   N/A 
Wait Start TickCount  63249   Ticks: 3 (0:00:00:00.046) 
Context Switch Count  66956   IdealProcessor: 0    
UserTime     00:01:12.609 
KernelTime    00:00:01.281 
Win32 Start Address calc!WinMainCRTStartup (0x003db8d4) 
Stack Init ac49bfe0 Current ac49be04 Base ac49c000 Limit ac499000 Call 0 
Priority 10 BasePriority 8 UnusualBoost 0 ForegroundBoost 2 IoPriority 2 PagePriority 5 
ChildEBP RetAddr Args to Child    
ac49bcf4 81ad2ef6 81c63c50 00000002 00000000 nt!KiUpdateRunTime (FPO: [Non-Fpo]) 
ac49bd40 81bdf7a7 ac49be38 ffd0fc98 00000002 nt!KiUpdateTime+0x23c (FPO: [Non-Fpo]) 
ac49bd90 81a134ae 81a10858 ffffffff ac49beb8 nt!KeClockInterruptNotify+0x67 (FPO: [0,15,4]) 
ac49bda0 81a23993 00000002 000000d1 00000000 hal!HalpTimerClockInterruptCommon+0x3e (FPO: [0,0,4]) 
ac49bda0 81a10858 00000002 000000d1 00000000 hal!HalpTimerClockInterrupt+0x1cb (FPO: [0,2] TrapFrame @ ac49be38) 
ac49beb8 81a239f3 00000000 ac49bf54 00200006 hal!HalEndSystemInterrupt+0xe8 (FPO: [Non-Fpo]) 
ac49beb8 0041be09 00000000 ac49bf54 00200006 hal!HalpTimerClockInterrupt+0x22b (FPO: [0,2] TrapFrame @ ac49bf54) 
0094c978 003c55f2 00000000 00000031 00ad55bc calc!WindowsCodecs_NULL_THUNK_DATA_DLB+0x79 
0094c994 003c586b 00aded98 0094c9b8 003c599d calc!CUIController::displayEvent+0x76 (FPO: [1,1,4]) 
0094c9a0 003c599d 00ad5574 00adeea0 00aded98 calc!CDisplayEvent::deliver+0x1a (FPO: [Non-Fpo]) 
0094c9b8 003d5177 00aded98 5b5012f1 00000000 calc!CEventRegistry::fire+0x28 (FPO: [Non-Fpo]) 
0094c9e4 003d575a 00aded98 00adeea0 03bf38ec calc!CCalculatorState::SetBinaryDigitDisplay+0x75 (FPO: [Non-Fpo]) 

(边注:!不支付对上述两个陷阱框架过多关注,它似乎是第一个例程一旦它使用STI指令重新启用中断,就会中断,所以有两个陷阱帧,而不是一个)。

+0

非常好的答案,谢谢! – 2015-02-08 12:56:37

+0

顺便说一句,它似乎在Windows 7上看起来不同。 KeUpdateSystemTime不再被时钟中断调用。 – 2015-02-08 18:24:04