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

时间:2017-03-08 03:51:01

标签: ms-word office-interop windbg

我正在使用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无法打开现有文件(正常)"。

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

有没有办法获得邮件的确切内存地址? (我觉得我有点猜测,因为上面的消息恰好在内存中接近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  ....

我知道我正在查看错误的记忆位(即我传递给直流的地址不正确),但我不知道为什么。我使用" .frame / r 2"要获取esp的地址,我做错了什么?

1 个答案:

答案 0 :(得分:6)

InternalDialogBox Api采取六个参数

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

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

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)第3和第6个参数为NULL

第二个参数由DLGTEMPLATE数组后跟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

修改

从taskmanager创建转储并加载

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

dumping stacktrace 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第二个arg

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或者黑客加载你编译成地址空间的二进制文件,或者将msGTEMPLATE结构添加到ms的官方pdb for user32(我以为我有一篇帖子解释这个但是我似乎无法如果我找到它或者网站搜索谷歌如何将typeinfo添加到网站中的pdb,我会发现链接错误:woodmann.com

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

可以搜索我们需要的某些typeinfo

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  

将modulename字符串嵌入已分配内存中的某个地址

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  ................

汇编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

重置后退

0:000> r eip = 77b305a6

我们研究了我们拥有的typeinfo和宾果

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