【问题标题】:Windbg: break on timer / scheduler interrupt and print EIPWindbg:中断计时器/调度程序中断并打印 EIP
【发布时间】:2015-04-07 20:11:26
【问题描述】:

有没有办法在Windows上的中断服务例程上设置一个断点,负责触发线程调度并打印被中断线程的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。

【问题讨论】:

    标签: windows windbg scheduling


    【解决方案1】:

    你已经很接近了,但是由于当前运行的线程被中断打断,KTRAP_FRAME(从被中断线程保存的寄存器)当时被放入堆栈(当调用 nt!KeUpdateSystemTime() 时)。

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

    重新加载 hal 符号;见 BP 并出发:

    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
    

    好的,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])
    

    Userland 线程被中断,陷阱帧位于 0xafb47d64。让我们看看线程:

    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()(请参阅 ISR 的 !idt -a)并构建陷阱帧。陷阱帧指针当前在 ebp 寄存器中:

    0: kd> r @ebp
    ebp=afb47d64
    

    所以,EBP = 指向 KTRAP_FRAME 的指针 = 0xafb47d64

    陷阱帧就像一个“上下文”结构,因为它保留了被中断线程的所有寄存器。我们来看看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 [Inter Processor Interrupt],另一个是通常的时钟中断)。

    我会选择 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 指令重新启用中断后立即被中断,因此有两个陷阱帧而不仅仅是一)。

    【讨论】:

    • 顺便说一句,在 Windows 7 上它看起来不同。 KeUpdateSystemTime 不再从时钟中断中调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-28
    • 1970-01-01
    • 2021-02-12
    相关资源
    最近更新 更多