这里使用一个debug程序:
.cxr
设备上下文的常用含义是一组寄存器,表示处理器在某个特定时刻的状态,因此也称为寄存器上下文,当生成异常时,寄存器上下文可以通过异常分发器的保码保存到栈上,并且在引发异常时可以用来恢复寄存器的值。
如何找到这个上下文?最简单的方式是从异常分发过程中使用的各种函数的参数中获取上下文,或者通过栈中搜索上下文,无论通过何种方式找到寄存器上下文,都可以通过.cxr <context address>来将其设置为当前的上下文
KiUserExceptionDispatcher( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )
第二个参数就是上下文件地址了
0:005> dt CONTEXT
02sample!CONTEXT
+0x000 ContextFlags : Uint4B
+0x004 Dr0 : Uint4B
+0x008 Dr1 : Uint4B
+0x00c Dr2 : Uint4B
+0x010 Dr3 : Uint4B
+0x014 Dr6 : Uint4B
第一个参数ContextFlags的取值是定义的长量,一盘为0x0001003f,表示常量CONTEXT_ALL,所以我们在栈中进行搜索某个内存块的含义时,这个标志是非常有用的,我们可以通过这个标志来找到上下文,并将其设置为当前线程的上下文,从而了解在异常发生之前处理器的状态是什么
0:000> *在地址空间的前256M中搜索完整的上下文
0:000> s -d 0 L10000000/4 0001003f
0009fd24 0001003f 00000000 00000000 00000000 ?...............
001c3b08 0001003f 0001004d 00000000 00000400 ?...M...........
005efd24 0001003f 00000000 00000000 00000000 ?...............
007efd24 0001003f 00000000 00000000 00000000 ?...............
0:000> *将找到的上下文设置到这个地址上
0:000> .cxr 0009fd24
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000
eip=7746e8ac esp=000dfd34 ebp=000dfe50 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ntdll!NtDeviceIoControlFile+0xc:
7746e8ac c22800 ret 28h
0:000> k
*** Stack trace for last set context - .thread/.cxr resets it
# ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
00 000dfe50 74a3d108 ntdll!NtDeviceIoControlFile+0xc
01 000dfe78 74aa16b4 KERNELBASE!GetConsoleOutputCP+0x58
02 000dfea8 765fa582 KERNELBASE!SetConsoleMode+0x24
03 000dfee4 765fa4a8 msvcrt!getwch+0x112
04 000dff18 01001d63 msvcrt!getwch+0x38
05 000dff30 01001c7b 02sample!AppInfo::Loop+0xb3 [c:\awd\common\menu.h @ 47]
06 000dff3c 01002038 02sample!wmain+0x1b [c:\awd\chapter2\sample.cpp @ 228]
07 000dff80 73fd8674 02sample!__wmainCRTStartup+0x102 [d:\vistartm\base\crts\crtw32\dllstuff\crtexe.c @ 711]
08 000dff94 77464b47 KERNEL32!BaseThreadInitThunk+0x24
09 000dffdc 77464b17 ntdll!RtlGetAppContainerNamedObjectPath+0x137
0a 000dffec 00000000 ntdll!RtlGetAppContainerNamedObjectPath+0x107
0:000> *恢复到默认的上下文
0:000> .cxr
Resetting default scope
0:000> k
# ChildEBP RetAddr
00 000dff18 01001d63 02sample!RaiseAV+0x10 [c:\awd\chapter2\sample.cpp @ 55]
01 000dff30 01001c7b 02sample!AppInfo::Loop+0xb3 [c:\awd\common\menu.h @ 47]
02 000dff3c 01002038 02sample!wmain+0x1b [c:\awd\chapter2\sample.cpp @ 228]
03 000dff80 73fd8674 02sample!__wmainCRTStartup+0x102 [d:\vistartm\base\crts\crtw32\dllstuff\crtexe.c @ 711]
WARNING: Stack unwind information not available. Following frames may be wrong.
04 000dff94 77464b47 KERNEL32!BaseThreadInitThunk+0x24
05 000dffdc 77464b17 ntdll!RtlGetAppContainerNamedObjectPath+0x137
06 000dffec 00000000 ntdll!RtlGetAppContainerNamedObjectPath+0x107
.frame
.frame命令指定使用哪个局部上下文(作用域)来解析局部变量,或者显示当前的局部上下文
所谓局部上下文,是指局部变量所基于的语境,局部变量是指定义在函数内部的变量,这些变量的含义与当前的执行位置密切相关,在调试时,调试器默认显示的是当前函数(程序指针)所对应的局部上下文,因为当前函数和局部变量都是与栈帧密切相关的,所以windbg通常使用栈帧号来表示局变上下文
帧序号(frame number)是堆栈帧在堆栈回溯中的位置。可以使用k (Display Stack Backtrace)命令或者Calls 窗口查看堆栈回溯。第一行 (当前帧) 的帧序号是0。后面的行分别是1、2、3等等。
0:000> kn
# ChildEBP RetAddr
00 0012f78c 7c92daea ntdll!KiFastSystemCallRet
01 0012f790 7c932298 ntdll!ZwRequestWaitReplyPort+0xc
02 0012f7b0 7c872a51 ntdll!CsrClientCallServer+0x8c
03 0012f8ac 7c872b98 kernel32!ReadConsoleInternal+0x1be
04 0012f934 7c8018b7 kernel32!ReadConsoleA+0x3b
05 0012f98c 102c207c kernel32!ReadFile+0x64
06 0012fa20 102c19c9 MSVCR90D!_read_nolock+0x62c [f:\dd\vctools\crt_bld\self_x86\crt\src\read.c @ 233]
07 0012fa70 10253e43 MSVCR90D!_read+0x219 [f:\dd\vctools\crt_bld\self_x86\crt\src\read.c @ 93]
08 0012fa98 102523e8 MSVCR90D!_filbuf+0x113 [f:\dd\vctools\crt_bld\self_x86\crt\src\_filbuf.c @ 136]
09 0012faf0 10252440 MSVCR90D!getc+0x208 [f:\dd\vctools\crt_bld\self_x86\crt\src\fgetc.c @ 76]
0a 0012fafc 1025245a MSVCR90D!_fgetchar+0x10 [f:\dd\vctools\crt_bld\self_x86\crt\src\fgetchar.c @ 37]
0b 0012fb04 0041160b MSVCR90D!getchar+0xa [f:\dd\vctools\crt_bld\self_x86\crt\src\fgetchar.c @ 47]
0c 0012fbe4 004114b2 test2!MyCls::hold+0x2b [d:\project1\test2\test2\test2.cpp @ 28]
0d 0012fcec 0041167a test2!foo1+0xa2 [d:\project1\test2\test2\test2.cpp @ 39]
0e 0012fdc0 004116ea test2!foo2+0x3a [d:\project1\test2\test2\test2.cpp @ 45]
0f 0012fe94 00411743 test2!foo3+0x3a [d:\project1\test2\test2\test2.cpp @ 51]
10 0012ff68 00411ce8 test2!main+0x23 [d:\project1\test2\test2\test2.cpp @ 56]
11 0012ffb8 00411b2f test2!__tmainCRTStartup+0x1a8 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 586]
12 0012ffc0 7c817077 test2!mainCRTStartup+0xf [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 403]
13 0012fff0 00000000 kernel32!BaseProcessStart+0x23
0:000> .frame d
0d 0012fcec 0041167a test2!foo1+0xa2 [d:\project1\test2\test2\test2.cpp @ 39]
0:000> x
0012fce4 pcls = 0x00392a28
0012fcd8 rawptr = 0x00392a28
.frame 帧号,可以把局部上下文切换到指定的栈帧
之后跟x,可以显示当前这个函数里面的局部变量
对应d帧的代码:
void foo1()
{
MyCls *pcls=new MyCls();
void *rawptr=pcls;
pcls->set("abcd");
pcls->output();
pcls->hold();
};
x显示的是pcls和rawptr
dt
dt命令显示局部变量、全局变量或数据类型的信息。它也可以仅显示数据类型。即结构和联合(union)的信息
dt最方便处是查找结构体,查找结构体一定要使用dt,不要使用x
0:000:x86> dt *!*IMAGE_DOS*
test1!IMAGE_DOS_HEADER
test1!PIMAGE_DOS_HEADER
test1!_IMAGE_DOS_HEADER
ntdll!_IMAGE_DOS_HEADER
ntdll32!_IMAGE_DOS_HEADER
MSVCR90D!IMAGE_DOS_HEADER
MSVCR90D!PIMAGE_DOS_HEADER
MSVCR90D!_IMAGE_DOS_HEADER
dt -b this可以打印this指针,只在类中起作用
0:000:x86> dt -b this
Local var @ 0x1cfd00 Type CLook*
0x00683488
+0x000 m_i : 0n1524615000
+0x004 m_j : 37 'Unknown format character
如果只想显示某个字段,可以用-ny 加上搜索选项,如:
0:000> dt -v ntdll!_PEB -ny BeingDebugged @$peb
struct _PEB, 91 elements, 0x248 bytes
+0x002 BeingDebugged : 0x1 ''
-v是详细输出。这会输出结构的总大小和字段数量这样的附加信息
也可以直接这样看大小:
0:000:x86> ?? sizeof(IMAGE_DOS_HEADER)
unsigned int 0x40
也可以用-y 来连接通配符,如:
0:000> dt -v ntdll!_PEB -y B* @$peb
struct _PEB, 91 elements, 0x248 bytes
+0x002 BeingDebugged : 0x1 ''
+0x003 BitField : 0x8 ''
0:000> dt pcls
Local var @ 0x12fce4 Type MyCls*
0x00392a28
+0x000 str : 0x00415800 "abcd"
+0x004 inobj : innner
0:000> dt rawptr
Local var @ 0x12fcd8 Type void*
0x00392a28
0:000> dt -b-r pcls
Local var @ 0x12fce4 Type MyCls*
0x00392a28
+0x000 str : 0x00415800 "abcd"
+0x004 inobj : innner
+0x000 arr : "abcd"
[00] 97 'a'
[01] 98 'b'
[02] 99 'c'
[03] 100 'd'
[04] 0 ''
[05] 0 ''
[06] 0 ''
[07] 0 ''
[08] 0 ''
[09] 0 ''