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内核调试

帖子发起人: compiler   发起时间: 2009-04-18 15:18 下午   回复: 2

Print Search
帖子排序:    
   2009-04-18, 15:18 下午
compiler 离线,最后访问时间: 2011/8/11 15:19:46 compiler

发帖数前50位
注册: 2008-04-22
发 贴: 21
从csrss弹出的ASSERT对话框谈起
Reply Quote

 

昨天遇到一件怪事,在进行远程线程注入的时候从csrss进程中竟然弹出了vc的ASSERT对话框。根据对话框提示信息找到了断言的位置在mfc的auxdata.cpp的第95行代码:
void AUX_DATA::UpdateSysMetrics()
{
 // System metrics
 cxIcon = GetSystemMetrics(SM_CXICON);
 cyIcon = GetSystemMetrics(SM_CYICON);

 // System metrics which depend on subsystem version
 afxData.cxVScroll = GetSystemMetrics(SM_CXVSCROLL) + CX_BORDER;
 afxData.cyHScroll = GetSystemMetrics(SM_CYHSCROLL) + CY_BORDER;

 // Device metrics for screen
 HDC hDCScreen = GetDC(NULL);
 ASSERT(hDCScreen != NULL); <------------------就是这个断言
 cxPixelsPerInch = GetDeviceCaps(hDCScreen, LOGPIXELSX);
 cyPixelsPerInch = GetDeviceCaps(hDCScreen, LOGPIXELSY);
 ReleaseDC(NULL, hDCScreen);
}
具体的环境就是win xp进行多用户登陆:首先登陆一个windows帐号user1, session id = 0, 对csrss进程成功进行了远程线程注入。接着在保持user1登陆的情况下切换用户登陆

到user2,进去之后同样的对新的session(session id = 1)的csrss进程进行远程线程注入,没什么问题。但是切回到user1后发现界面上有一个断言对话框,显示了上面代码位置

的断言失败。查看这个对话框所在的进程确实是session 0的csrss进程。因为是一个稳定的重现的问题,使用windbg远程附加到session 0的csrss进程,查看弹出对话框的线程调

用栈如下:
 ChildEBP RetAddr 
        0071f8d8 77d193f5 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        0071f910 77d2688a USER32!NtUserWaitMessage+0xc
        0071f938 77d3b7c5 USER32!InternalDialogBox+0xd0 (FPO: [6,1,4])
        0071fbf8 77d3b12b USER32!SoftModalMessageBox+0x938 (FPO: [1,165,4])
        0071fd48 77d65fdf USER32!MessageBoxWorker+0x2ba (FPO: [1,78,4])
        0071fda0 764f9b1b USER32!MessageBoxTimeoutW+0x7a (FPO: [6,19,0])
        0071fe7c 764f9d5b winsrv!HardErrorHandler+0x2e8 (FPO: [0,44,4])
        0071fe9c 764fb0f1 winsrv!ProcessHardErrorRequest+0x9b (FPO: [1,3,4])
        0071febc 764fb173 winsrv!UserHardErrorEx+0x234 (FPO: [3,2,4])
        0071fed0 75aa47a0 winsrv!UserHardError+0x12 (FPO: [2,0,0])
        0071fff4 00000000 CSRSRV!CsrApiRequestThread+0x18a (FPO: [Non-Fpo])
这里很奇怪,断言的调用链里面应该会出现__crtMessageBoxA,除非是符号不对,但是调用栈里面所有的返回地址都有符号。
难道是调用栈不完整,于是结合汇编代码对调用栈进行核实---没问题。一个偶然的原因在ReactOS上面看了一下CsrApiRequestThread函数的源代码才意识到这个对话框是通过LPC

端口投递过来的消息显示。winsrv!UserHardError是最后一个出错处理回调例程。
用户态调试查不出这个LPC是哪里投递过来的,转而使用内核态调试。
根据从运程线程注入的结果,对session 1的csrss进程进行的远程线程一直没有收到注入成功的回复,很自然想到看一下session 1的csrss进程的情况。

kd> !process 81a81468 
PROCESS 81a81468  SessionId: 1  Cid: 0238    Peb: 7ffd5000  ParentCid: 0240
    DirBase: 084003e0  ObjectTable: e178ca80  HandleCount: 128.
    Image: csrss.exe
    VadRoot 81711920 Vads 100 Clone 0 Private 702. Modified 2674. Locked 0.
    DeviceMap e10000b8
    Token                             e1474138
    ElapsedTime                       00:01:01.984
    UserTime                          00:00:01.500
    KernelTime                        00:00:01.921
    QuotaPoolUsage[PagedPool]         123956
    QuotaPoolUsage[NonPagedPool]      4160
    Working Set Sizes (now,min,max)  (125, 50, 345) (500KB, 200KB, 1380KB)
    PeakWorkingSetSize                2818
    VirtualSize                       59 Mb
    PeakVirtualSize                   76 Mb
    PageFaultCount                    3524
    MemoryPriority                    BACKGROUND
    BasePriority                      13
    CommitCharge                      874

        /////略去一些无关线程信息

        THREAD 8170eda8  Cid 0238.096c  Teb: 7ffd3000 Win32Thread: e24c1ba0 WAIT: (WrLpcReply) UserMode Non-Alertable
            8170ef9c  Semaphore Limit 0x1
        Waiting for reply to LPC MessageId 0000209e:
        Current LPC port e1353840
        Not impersonating
        DeviceMap                 e10000b8
        Owning Process            81a81468       Image:         csrss.exe
        Wait Start TickCount      13207          Ticks: 2483 (0:00:00:38.796)
        Context Switch Count      17                 LargeStack
        UserTime                  00:00:00.140
        KernelTime                00:00:00.015
        Win32 Start Address 0x7ff90000
        Start Address KERNEL32!BaseThreadStartThunk (0x7c810856)
        Stack Init f72f1000 Current f72f0a94 Base f72f1000 Limit f72ee000 Call 0
        Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 0
        ChildEBP RetAddr 
        f72f0aac 8050117a nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4])
        f72f0ab8 804fa9be nt!KiSwapThread+0x46 (FPO: [0,0,0])
        f72f0ae0 805989d5 nt!KeWaitForSingleObject+0x1c2 (FPO: [Non-Fpo])
        f72f0b18 80598b21 nt!LpcpRequestWaitReplyPort+0x43d (FPO: [Non-Fpo])
        f72f0b30 8060a467 nt!LpcRequestWaitReplyPortEx+0x21 (FPO: [Non-Fpo])
        f72f0cd4 8060a8c5 nt!ExpRaiseHardError+0x1bd (FPO: [Non-Fpo])
        f72f0d44 8053d808 nt!NtRaiseHardError+0x16b (FPO: [Non-Fpo])
        f72f0d44 7c92eb94 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f72f0d64)
        0350b348 7c92e273 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        0350b34c 77d65d43 ntdll!NtRaiseHardError+0xc (FPO: [6,0,0])
        0350b3a8 77d48ffe USER32!ServiceMessageBox+0x145 (FPO: [Non-Fpo])
        0350b504 77d65fdf USER32!MessageBoxWorker+0x13e (FPO: [Non-Fpo])
        0350b55c 77d66084 USER32!MessageBoxTimeoutW+0x7a (FPO: [Non-Fpo])
        0350b590 77d50598 USER32!MessageBoxTimeoutA+0x9c (FPO: [Non-Fpo])
        0350b5b0 77d50550 USER32!MessageBoxExA+0x1b (FPO: [Non-Fpo])
        0350b5cc 1020c2aa USER32!MessageBoxA+0x45 (FPO: [Non-Fpo])
        0350b604 1020cd3e MSVCR71D!__crtMessageBoxA+0x16a (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\crtmbox.c @ 119]
        0350c75c 1020ca2a MSVCR71D!CrtMessageWindow+0x2be (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\dbgrpt.c @ 617]
        0350f7d8 03666b3f MSVCR71D!_CrtDbgReport+0x41a (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\dbgrpt.c @ 516]
        0350f818 0361bad2 MFC71UD!AfxAssertFailedLine+0x2f (FPO: [Non-Fpo]) (CONV: stdcall) [f:\vs70builds\3077\vc\mfcatl\ship\atlmfc\src\mfc\afxasert.cpp @

28]
        0350f830 0368cc9e MFC71UD!AUX_DATA::UpdateSysMetrics+0x62 (FPO: [Non-Fpo]) (CONV: thiscall) [f:\vs70builds\3077

\vc\mfcatl\ship\atlmfc\src\mfc\auxdata.cpp @ 95]
        0350f840 0368cd5d MFC71UD!AUX_DATA::AUX_DATA+0x2e (FPO: [Non-Fpo]) (CONV: thiscall) [f:\vs70builds\3077\vc\mfcatl\ship\atlmfc\src\mfc\auxdata.cpp @

35]
        0350f848 10201d48 MFC71UD!$E5+0xd (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\mfcatl\ship\atlmfc\src\mfc\auxdata.cpp @ 22]
        0350f850 035da943 MSVCR71D!_initterm+0x18 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\crt0dat.c @ 600]
        0350f860 035daa5a MFC71UD!_CRT_INIT+0xa3 (FPO: [Non-Fpo]) (CONV: stdcall) [f:\vs70builds\3077\vc\crtbld\crt\src\crtdll.c @ 184]
        0350f8ac 7c9211a7 MFC71UD!_DllMainCRTStartup+0x9a (FPO: [Non-Fpo]) (CONV: stdcall) [f:\vs70builds\3077\vc\crtbld\crt\src\crtdll.c @ 266]
        0350f8cc 7c93cbab ntdll!LdrpCallInitRoutine+0x14
        0350f9d4 7c936178 ntdll!LdrpRunInitializeRoutines+0x344 (FPO: [Non-Fpo])
        0350fc80 7c9362da ntdll!LdrpLoadDll+0x3e5 (FPO: [Non-Fpo])
        0350ff28 7c801bb9 ntdll!LdrLoadDll+0x230 (FPO: [Non-Fpo])
        0350ff90 7c80ace4 KERNEL32!LoadLibraryExW+0x18e (FPO: [Non-Fpo])
        0350ffa4 7ff90010 KERNEL32!LoadLibraryW+0x11 (FPO: [Non-Fpo])
WARNING: Frame IP not in any known module. Following frames may be wrong.
        0350ffb4 7c80b50b 0x7ff90010
        0350ffec 00000000 KERNEL32!BaseThreadStart+0x37 (FPO: [Non-Fpo])

看到这一个线程的信息之后,原因终于找到了,是在对session 1的csrss进行注入之后,加载dll,初始化mfc动态链接库的时候导致断言失败,对话框通过LPC的方式重定向到

session 0的csrss进程去显示了。到这里还是有很多疑问,主要是两个问题:
1.为什么auxdata.cpp第94行HDC hDCScreen = GetDC(NULL);获取屏幕DC的时候会得到NULL句柄。
2.为什么在对session 0的csrss进程注入的时候没有出现这个问题。

写了如下的测试dll:
#include "stdafx.h"
#include <crtdbg.h>


#define ASSERT(expr, msg) \
 do { if (!(expr) && \
 (1 == _CrtDbgReport(_CRT_ASSERT, __FILE__, __LINE__, NULL, msg))) \
 _CrtDbgBreak(); } while (0)

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 if (DLL_PROCESS_ATTACH == ul_reason_for_call){
  _asm int 3    ;这里的断点,是为了跟踪调试GetDC
  ASSERT(NULL != GetDC(0), NULL);
 }
    return TRUE;
}

同时写一个简单的注入程序将上面的dll注入到csrss进程中。内核调试在int 3断点中断,nop掉int 3指令。单步跟踪GetDC(注意跟踪的时候对)同时结合windows nt的源代码,发

现之所以返回NULL,是因为csrss进程没有关联桌面,获取不到屏幕DC(具体参考nt源代码)。
同时发现session 0确实也拿不到屏幕DC,继续跟踪断言消息框显示流程。发现__crtMessageBoxA函数(VC有源代码)在uType参数加上了MB_SERVICE_NOTIFICATION标志,导致

MessageBoxWorker函数(win2k源代码)最终调用ServiceMessageBox,而不是SoftModalMessageBox。

kd> !process 8150b5c0 
PROCESS 8150b5c0  SessionId: 1  Cid: 0dc0    Peb: 7ffdd000  ParentCid: 023c
    DirBase: 02b403e0  ObjectTable: e11a0e48  HandleCount: 136.
    Image: csrss.exe
    VadRoot 816ca8d0 Vads 86 Clone 0 Private 199. Modified 2530. Locked 0.
    DeviceMap e1000110
    Token                             e1157930
    ElapsedTime                       01:41:39.406
    UserTime                          00:00:02.906
    KernelTime                        00:00:04.250
    QuotaPoolUsage[PagedPool]         127108
    QuotaPoolUsage[NonPagedPool]      3600
    Working Set Sizes (now,min,max)  (96, 50, 345) (384KB, 200KB, 1380KB)
    PeakWorkingSetSize                2097
    VirtualSize                       59 Mb
    PeakVirtualSize                   64 Mb
    PageFaultCount                    4342
    MemoryPriority                    BACKGROUND
    BasePriority                      13
    CommitCharge                      304

        //略去无关线程

        THREAD 8141c278  Cid 0dc0.01b0  Teb: 7ffd3000 Win32Thread: e1dd6938 WAIT: (WrLpcReply) UserMode Non-Alertable
            8141c46c  Semaphore Limit 0x1
        Waiting for reply to LPC MessageId 00003e93:
        Current LPC port e13cb988
        Not impersonating
        DeviceMap                 e1000110
        Owning Process            0       Image:         <Unknown>
        Attached Process          8150b5c0       Image:         csrss.exe
        Wait Start TickCount      23986          Ticks: 4438 (0:00:01:09.343)
        Context Switch Count      17                 LargeStack
        UserTime                  00:00:00.093
        KernelTime                00:00:00.031
        Win32 Start Address 0x02b60000
        Start Address KERNEL32!BaseThreadStartThunk (0x7c810669)
        Stack Init f72f6000 Current f72f5a94 Base f72f6000 Limit f72f3000 Call 0
        Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 0
        Kernel stack not resident.
        ChildEBP RetAddr 
        f72f5aac 80501366 nt!KiSwapContext+0x2e (FPO: [Uses EBP] [0,0,4])
        f72f5ab8 804fabd0 nt!KiSwapThread+0x46 (FPO: [0,0,0])
        f72f5ae0 80598d01 nt!KeWaitForSingleObject+0x1c2 (FPO: [5,5,4])
        f72f5b18 80598e4d nt!LpcpRequestWaitReplyPort+0x43d (FPO: [4,4,0])
        f72f5b30 8060a799 nt!LpcRequestWaitReplyPortEx+0x21 (FPO: [3,0,0])
        f72f5cd4 8060abf7 nt!ExpRaiseHardError+0x1bd (FPO: [Non-Fpo])
        f72f5d44 8053da48 nt!NtRaiseHardError+0x16b (FPO: [Non-Fpo])
        f72f5d44 7c92eb94 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f72f5d64)
        02c6b2d8 7c92e273 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        02c6b2dc 77d65d43 ntdll!NtRaiseHardError+0xc (FPO: [6,0,0])
        02c6b338 77d48ffe USER32!ServiceMessageBox+0x145 (FPO: [4,13,0])
        02c6b494 77d65fdf USER32!MessageBoxWorker+0x13e (FPO: [1,78,4])
        02c6b4ec 77d66084 USER32!MessageBoxTimeoutW+0x7a (FPO: [6,19,0])
        02c6b520 77d50598 USER32!MessageBoxTimeoutA+0x9c (FPO: [6,2,4])
        02c6b540 77d50550 USER32!MessageBoxExA+0x1b (FPO: [5,0,0])
        02c6b55c 1001811a USER32!MessageBoxA+0x45 (FPO: [4,0,0])
        02c6b594 10012c5e ApiHook!__crtMessageBoxA+0x16a (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\crtmbox.c @ 119]
        02c6c6ec 1001283a ApiHook!CrtMessageWindow+0x2be (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\dbgrpt.c @ 617]
        02c6f768 10011fa3 ApiHook!_CrtDbgReport+0x41a (FPO: [Non-Fpo]) (CONV: cdecl) [f:\vs70builds\3077\vc\crtbld\crt\src\dbgrpt.c @ 516]
        02c6f850 1001320b ApiHook!DllMain+0x53 (FPO: [Non-Fpo]) (CONV: stdcall) [e:\lzz\vc proj\apihook\apihook.cpp @ 20]
        02c6f898 7c9211a7 ApiHook!_DllMainCRTStartup+0xbb (FPO: [Non-Fpo]) (CONV: stdcall) [f:\vs70builds\3077\vc\crtbld\crt\src\dllcrt0.c @ 297]
        02c6f8b8 7c93cbab ntdll!LdrpCallInitRoutine+0x14
        02c6f9c0 7c936178 ntdll!LdrpRunInitializeRoutines+0x344 (FPO: [Non-Fpo])
        02c6fc6c 7c9362da ntdll!LdrpLoadDll+0x3e5 (FPO: [Non-Fpo])
        02c6ff14 7c801bb9 ntdll!LdrLoadDll+0x230 (FPO: [Non-Fpo])
        02c6ff7c 7c801d6e KERNEL32!LoadLibraryExW+0x18e (FPO: [Non-Fpo])
        02c6ff90 7c801da4 KERNEL32!LoadLibraryExA+0x1f (FPO: [3,0,0])
        02c6ffac 02b6000a KERNEL32!LoadLibraryA+0x94 (FPO: [1,0,0])
WARNING: Frame IP not in any known module. Following frames may be wrong.
        02c6ffec 00000000 0x2b6000a
内核函数ExpRaiseHardError根据当前进程的ExceptionPort发送这个消息框调用。这时候刚好csrss的ExceptionPort为NULL,系统使用默认的ExpDefaultErrorPort,但csrss

(session 0)是默认的ExpDefaultErrorPortProcess, 操作系统对这个进程的消息不进行LPC投递,直接返回. 这就是为什么第一个csrss被注入没有弹出断言消息框的原因。这之后

的第二个csrss进程的ExceptionPort也是NULL,LPC被发送到了ExpDefaultErrorPort,第一个csrss对该消息进行了处理显示了断言消息框。

进一步发现系统中只有system,smss,csrss进程没有ExceptionPort,其它的进程都有ExceptionPort。这个Port的名字就是"ApiPort",每一个session都有一个这样的Port,csrss

进程负责监听,而没有ExceptionPort的进程则通过ExpDefaultErrorPort发送,默认由session 0的csrss进程处理。


IP 地址: 已记录   报告
   2009-04-19, 15:45 下午
MJ0011 离线,最后访问时间: 2009/12/24 22:33:41 MJ0011

发帖数前10位
注册: 2008-04-24
发 贴: 112
Re: 从csrss弹出的ASSERT对话框谈起
Reply Quote
NtRaiseHardError 就是通过LPC给CSRSS的winsrv.dll里的UserHardError弹框的~

用这个还可以实现驱动级弹框~
IP 地址: 已记录   报告
   2009-04-19, 18:15 下午
compiler 离线,最后访问时间: 2011/8/11 15:19:46 compiler

发帖数前50位
注册: 2008-04-22
发 贴: 21
Re: 从csrss弹出的ASSERT对话框谈起
Reply Quote
ls果然牛
IP 地址: 已记录   报告
高端调试 » 软件调试 » Windows内核调试 » Re: 从csrss弹出的ASSERT对话框谈起

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