WinDbg:如何从核心转储中获取显示在 Word 对话框中的消息?

WinDbg: How do I get the message displayed in a Word dialog from a core dump?

我正在使用 C# 应用程序中的 MS Word 执行一些 Office 自动化,我发现 Word 有时会挂起。我无法在开发人员环境中重现挂起,因此我希望我可以通过获取核心转储然后使用 WinDbg 对其进行分析来准确诊断 Word 挂起的原因。

如果我 运行 kb,我得到这个堆栈跟踪(我在警告后放弃了所有内容,因为它可能不相关):

ChildEBP RetAddr  Args to Child              
003bc94c 762ed846 00037b72 00000008 00000000 user32!NtUserWaitMessage+0x15
003bc988 762eda5c 00047b12 00037b72 00000008 user32!DialogBox2+0x222
003bc9b4 762ed98a 59870000 0089aa30 00037b72 user32!InternalDialogBox+0xe5
003bc9d4 762ed70e 59870000 0089aa30 00037b72 user32!DialogBoxIndirectParamAorW+0x37
003bc9f4 59acdf5e 59870000 0089aa30 00037b72 user32!DialogBoxIndirectParamW+0x1b
WARNING: Stack unwind information not available. Following frames may be wrong.

所以这似乎表明 Word 正在挂起,因为它正在显示一个对话框。 如何获取该对话框的内容?

如果我查看地址 0089aa30 处的内存,我会看到:

........................3....
.M.i.c.r.o.s.o.f.t. .W.o.r.d.
........T.a.h.o.m.a..........
....P#.!.*...........O.K.....
...........PW.!.*...........&
.H.e.l.p..................P..
.............................
....P+...r.......M.S.O.U.N.I.
S.T.A.T...W.o.r.d. .c.a.n.n.o
.t. .o.p.e.n. .t.h.e. .e.x.i.
s.t.i.n.g. .f.i.l.e..... .(.N
.o.r.m.a.l.)................@
..+.........M.S.O.U.N.I.S.T.A
.T...2.0.0.5.2.1.............

所以对我来说,这表示对话框中的消息是 "Word cannot open the existing file (Normal)"。

我走在正确的轨道上吗?我看的是正确的内存位吗?

有什么办法可以得到消息的确切内存地址吗? (我觉得我在猜测一点,因为上面的消息恰好在内存中靠近 DialogBoxIndirectParam 的参数。)我查看了 DialogBoxIndirectParam 的 MSDN 文档,希望找出确切位置在内存中,我应该期望看到对话框的消息,但并没有走得太远。


编辑:在看到 blabb(绝对令人难以置信)的回答后,我试图在 WinDbg 中为我的 MS Word 核心转储执行相同的步骤。这是输出:

0:000> ub 762ed98a 
user32!DialogBoxIndirectParamAorW+0x1f:
762ed972 83c801          or      eax,1
762ed975 50              push    eax
762ed976 ff7518          push    dword ptr [ebp+18h]
762ed979 ff7514          push    dword ptr [ebp+14h]
762ed97c ff7510          push    dword ptr [ebp+10h]
762ed97f ff750c          push    dword ptr [ebp+0Ch]
762ed982 ff7508          push    dword ptr [ebp+8]
762ed985 e809000000      call    user32!InternalDialogBox (762ed993)
0:000> .frame /r 2
02 003bc9b4 762ed98a user32!InternalDialogBox+0xe5
eax=00000000 ebx=00037b72 ecx=00000000 edx=00000000 esi=003bc97c edi=003bc918
eip=762eda5c esp=003bc990 ebp=003bc9b4 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
user32!InternalDialogBox+0xe5:
762eda5c 5f              pop     edi
0:000> dc /c 1 003bc990 l8
003bc990  00047b12  .{..
003bc994  00037b72  r{..
003bc998  00000008  ....
003bc99c  00000000  ....
003bc9a0  00000000  ....
003bc9a4  00037b72  r{..
003bc9a8  003bcb98  ..;.
003bc9ac  00000000  ....

我知道我正在查看错误的内存位(即我传递给 dc 的地址不正确),但我不知道为什么。我使用“.frame /r 2”来获取esp的地址,我做错了什么?

InternalDialogBox Api 有六个参数

C:\>cdb -c ".fnent user32!InternalDialogbox;q" cdb | grep Params
Params:    0n6 (0x18 bytes)

您可以尝试通过对堆栈 return 地址进行反向反汇编来解密此调用

0:000> kb 1
 # ChildEBP RetAddr  Args to Child              
00 0017fad8 778be0d5 77860000 001ec4f0 00000000 USER32!InternalDialogBox

0:000> ub @$ra
USER32!SoftModalMessageBox+0x66d:
778be0b8 e87c48fdff      call    USER32!MessageBeep (77892939)
778be0bd 56              push    esi
778be0be 53              push    ebx
778be0bf 6848d68b77      push    offset USER32!MB_DlgProc (778bd648)
778be0c4 ff75ac          push    dword ptr [ebp-54h]
778be0c7 ff75e4          push    dword ptr [ebp-1Ch]
778be0ca ff35d0908c77    push    dword ptr [USER32!hmodUser (778c90d0)]
778be0d0 e8a059fdff      call    USER32!InternalDialogBox (77893a75)

在故障转储中,您可以替换地址而不是注册,或者您可以 做 .frame /r {frame number} 来获取 esp

的地址
0:000> dc /c 1 @esp l8
0017fadc  778be0d5  ...w
0017fae0  77860000  ...w
0017fae4  001ec4f0  ....
0017fae8  00000000  ....
0017faec  778bd648  H..w
0017faf0  0017fcd8  ....
0017faf4  00000000  ....
0017faf8  00000001  ....

1) 第一个参数是hModUser 全局变量 2) 第四个参数是记录在案的 DialogProc 回调 3) 第三个和第六个参数为 NULL

第二个参数由 DLGTEMPLATE followed by DLGITEMTEMPLATE 结构的数组组成,请阅读文档了解此可变大小数组的格式

第五个参数是MSGBOXPARAMS结构

示例转储和解密可变大小数组的转储如下

0:000> db 1ec4f0 l f8 
001ec4f0  c5 01 c8 80 00 00 00 00-02 00 1a 01 9b 00 a7 00  ................
001ec500  3e 00 00 00 00 00 54 00-68 00 69 00 73 00 20 00  >.....T.h.i.s. .
001ec510  69 00 73 00 20 00 4d 00-79 00 20 00 43 00 61 00  i.s. .M.y. .C.a.
001ec520  70 00 74 00 69 00 6f 00-6e 00 20 00 46 00 6f 00  p.t.i.o.n. .F.o.
001ec530  72 00 20 00 32 00 30 00-31 00 35 00 20 00 43 00  r. .2.0.1.5. .C.
001ec540  6f 00 6d 00 6d 00 75 00-6e 00 69 00 74 00 79 00  o.m.m.u.n.i.t.y.
001ec550  20 00 76 00 73 00 00 00-ff 7f 00 00 01 00 03 50   .v.s..........P
001ec560  00 00 00 00 71 00 2a 00-32 00 0e 00 01 00 ff ff  ....q.*.2.......
001ec570  80 00 4f 00 4b 00 00 00-00 00 00 00 80 20 02 50  ..O.K........ .P
001ec580  00 00 00 00 07 00 0e 00-8c 00 09 00 ff ff ff ff  ................
001ec590  82 00 54 00 68 00 69 00-73 00 20 00 69 00 73 00  ..T.h.i.s. .i.s.
001ec5a0  20 00 6d 00 79 00 20 00-66 00 69 00 72 00 73 00   .m.y. .f.i.r.s.
001ec5b0  74 00 20 00 54 00 65 00-73 00 74 00 20 00 77 00  t. .T.e.s.t. .w.
001ec5c0  69 00 74 00 68 00 20 00-32 00 30 00 31 00 35 00  i.t.h. .2.0.1.5.
001ec5d0  20 00 63 00 6f 00 6d 00-6d 00 75 00 6e 00 69 00   .c.o.m.m.u.n.i.
001ec5e0  74 00 79 00 00 00 00 00                          t.y.....
0:000> dt ConsoleApplication1!DLGTEMPLATE 1ec4f0
   +0x000 style            : 0x80c801c5
   +0x004 dwExtendedStyle  : 0
   +0x008 cdit             : 2
   +0x00a x                : 0x11a
   +0x00c y                : 0x9b
   +0x00e cx               : 0xa7
   +0x010 cy               : 0x3e
0:000> du 1ec504
001ec504  ""
0:000> du 1ec506
001ec506  "This is My Caption For 2015 Comm"
001ec546  "unity vs"
0:000> dt ConsoleApplication1!DLGITEMTEMPLATE 1ec55c
   +0x000 style            : 0x50030001
   +0x004 dwExtendedStyle  : 0
   +0x008 x                : 0x71
   +0x00a y                : 0x2a
   +0x00c cx               : 0x32
   +0x00e cy               : 0xe
   +0x010 id               : 1
0:000> $$ 80 is a predfined button and the text is OK
0:000> dt ConsoleApplication1!DLGITEMTEMPLATE 1ec57c
   +0x000 style            : 0x50022080
   +0x004 dwExtendedStyle  : 0
   +0x008 x                : 7
   +0x00a y                : 0xe
   +0x00c cx               : 0x8c
   +0x00e cy               : 9
   +0x010 id               : 0xffff
0:000> $$ 82 is a predfined static text and the text is 
0:000> du 1ec592
001ec592  "This is my first Test with 2015 "
001ec5d2  "community"

这是一个 MSGBOXPARAMSW 转储

0:000> dt ConsoleApplication1!MSGBOXPARAMSW 0017fcd8 
   +0x000 cbSize           : 0x28
   +0x004 hwndOwner        : (null) 
   +0x008 hInstance        : (null) 
   +0x00c lpszText         : 0x01172150  "This is my first Test with 2015 community"
   +0x010 lpszCaption      : 0x011720f8  "This is My Caption For 2015 Community vs"
   +0x014 dwStyle          : 0
   +0x018 lpszIcon         : (null) 
   +0x01c dwContextHelpId  : 0
   +0x020 lpfnMsgBoxCallback : (null) 
   +0x024 dwLanguageId     : 0

编辑

从任务管理器创建了转储并加载了它

0:000> .shell -ci "version" grep DMP
Full memory user mini dump: C:\Users\HP\Desktop\cons.DMP
command line: 'windbg  -z cons.DMP'  Debugger Process 0x17CC 
.shell: Process exited

只是为了确保重置上下文记录

0:000> .cxr
Resetting default scope

转储堆栈跟踪 9感兴趣的框架不在顶部)

0:000> kb 5
 # ChildEBP RetAddr  Args to Child              
00 0028f6fc 778766c9 7789382a 00000000 00000000 ntdll!KiFastSystemCallRet
01 0028f700 7789382a 00000000 00000000 00000000 user32!NtUserWaitMessage+0xc
02 0028f734 77893b27 00aa0350 00000000 00000000 user32!DialogBox2+0x207
03 0028f758 778be0d5 77860000 002f63f0 00000000 user32!InternalDialogBox+0xcb
04 0028f7fc 778be659 00000000 69d52104 69d52108 user32!SoftModalMessageBox+0x68a

覆盖感兴趣的帧编号的本地上下文

0:000> .frame /c /r 04
04 0028f7fc 778be659 user32!SoftModalMessageBox+0x68a
eax=00000001 ebx=0028f958 ecx=0028f458 edx=77ad70f4 esi=005fab18 edi=00000001
eip=778be0d5 esp=0028f760 ebp=0028f7fc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
user32!SoftModalMessageBox+0x68a:
778be0d5 8945e8          mov     dword ptr [ebp-18h],eax ss:0023:0028f7e4=00000000

checking esp you can use esp as it is instead of groping for address

0:000> dc /c 1 @esp l 8
0028f760  77860000  ...w
0028f764  002f63f0  .c/.
0028f768  00000000  ....
0028f76c  778bd648  H..w
0028f770  0028f958  X.(.
0028f774  00000000  ....
0028f778  00000001  ....
0028f77c  0028f958  X.(.

正在转储 DLGTEMPLATE 第二个参数

0:000> db 2f63f0 lf8
002f63f0  c5 01 c8 80 00 00 00 00-02 00 1a 01 9b 00 a7 00  ................
002f6400  3e 00 00 00 00 00 54 00-68 00 69 00 73 00 20 00  >.....T.h.i.s. .
002f6410  69 00 73 00 20 00 4d 00-79 00 20 00 43 00 61 00  i.s. .M.y. .C.a.
002f6420  70 00 74 00 69 00 6f 00-6e 00 20 00 46 00 6f 00  p.t.i.o.n. .F.o.
002f6430  72 00 20 00 32 00 30 00-31 00 35 00 20 00 43 00  r. .2.0.1.5. .C.
002f6440  6f 00 6d 00 6d 00 75 00-6e 00 69 00 74 00 79 00  o.m.m.u.n.i.t.y.
002f6450  20 00 76 00 73 00 00 00-ff 7f 00 00 01 00 03 50   .v.s..........P
002f6460  00 00 00 00 71 00 2a 00-32 00 0e 00 01 00 ff ff  ....q.*.2.......
002f6470  80 00 4f 00 4b 00 00 00-00 00 00 00 80 20 02 50  ..O.K........ .P
002f6480  00 00 00 00 07 00 0e 00-8c 00 09 00 ff ff ff ff  ................
002f6490  82 00 54 00 68 00 69 00-73 00 20 00 69 00 73 00  ..T.h.i.s. .i.s.
002f64a0  20 00 6d 00 79 00 20 00-66 00 69 00 72 00 73 00   .m.y. .f.i.r.s.
002f64b0  74 00 20 00 54 00 65 00-73 00 74 00 20 00 77 00  t. .T.e.s.t. .w.
002f64c0  69 00 74 00 68 00 20 00-32 00 30 00 31 00 35 00  i.t.h. .2.0.1.5.
002f64d0  20 00 63 00 6f 00 6d 00-6d 00 75 00 6e 00 69 00   .c.o.m.m.u.n.i.
002f64e0  74 00 79 00 00 00 00 00                          t.y.....

typeinfo(您需要适当的私有 pdb 或 hack 加载您编译到地址 space 的二进制文件或将 DLGTEMPLATE 结构添加到来自 ms 的 user32 的官方 pdb(我以为我有一个 post 在 se 中对此进行解释,但我似乎找不到)生病 link 稍后如果我找到它或站点搜索 google 如何在 site:woodmann.com [=30= 中将类型信息添加到 pdb ]

0:000> dt cons!DLGTEMPLATE poi(@esp+4)
   +0x000 style            : 0x80c801c5
   +0x004 dwExtendedStyle  : 0
   +0x008 cdit             : 2
   +0x00a x                : 0n282
   +0x00c y                : 0n155
   +0x00e cx               : 0n167
   +0x010 cy               : 0n62

0:000> du poi(@esp+4)+16
002f6406  "This is My Caption For 2015 Comm"
002f6446  "unity vs"

编辑 2 这是转储模式下的实时会话,您需要修改 pdb,因为您不能使用执行命令

我们正在进行实时 dbg 会话,我们可以使用在 dmp 模式下不可用的步进命令

0:000> .tlist -c -v 
 0n3324 Msgbox.exe
       Session: 1  User: HP-PC\HP  Command Line: Msgbox.exe

让我们搜索一些我们需要的类型信息

0:000> dt *!*DLGTEMPLATE*
0:000> $$ no the thype info is not available
0:000> $$ we know ole32.dll has it 
0:000> $$ so lets hack load it

分配一些内存

0:000> .dvalloc 1000
Allocated 1000 bytes starting at 00020000
save the current eip

0:000> ? @eip
Evaluate expression: 2008221094 = 77b305a6  

将模块名称字符串嵌入分配内存中的某个地址

0:000> ea 20100 "ole32.dll"
0:000> db 20100 l20
00020100  6f 6c 65 33 32 2e 64 6c-6c 00 00 00 00 00 00 00  ole32.dll.......
00020110  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

Assemble 内联 LoadLibraryA 调用

0:000> a 20000
00020000 push 20100
push 20100
00020005 call kernel32!LoadLibraryA
call kernel32!LoadLibraryA
0002000a 

将eip改成绕道地址

0:000> r eip = 20000

single step to load a dll into the address space 


0:000> p
eax=00000000 ebx=00000000 ecx=0026f80c edx=77ad70f4 esi=fffffffe edi=00000000
eip=00020005 esp=0026f824 ebp=0026f854 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
00020005 e852395877      call    kernel32!LoadLibraryA (775a395c)
0:000> p
ModLoad: 77930000 77a8c000   C:\Windows\system32\ole32.dll
ModLoad: 75ee0000 75f81000   C:\Windows\system32\RPCRT4.dll
ModLoad: 77530000 7754f000   C:\Windows\system32\IMM32.DLL
ModLoad: 76030000 760fc000   C:\Windows\system32\MSCTF.dll
eax=77930000 ebx=00000000 ecx=77ae6570 edx=002b0174 esi=fffffffe edi=00000000
eip=0002000a esp=0026f828 ebp=0026f854 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
0002000a 0000            add     byte ptr [eax],al          ds:0023:77930000=4d

重置eip回来

0:000> r eip = 77b305a6

我们研究了我们拥有的类型信息和宾果游戏

0:000> dt *!*DLGTEMPLATE*
          ole32!LPDLGTEMPLATEA
          ole32!LPDLGTEMPLATE
          ole32!LPDLGTEMPLATEW
          ole32!LPCDLGTEMPLATE
          ole32!LPCDLGTEMPLATEA
          ole32!LPCDLGTEMPLATEW
          ole32!DLGTEMPLATE
          ole32!DLGTEMPLATE