Windbg 调试VC程序
windbg中的调试指令有三种: http://www.360doc.com/content/16/1110/14/30953065_605412205.shtml
1. 基本命令: 调试器自带,提供最基本的调试功能,不区分大小写。 例如 bp ,g ,dt ,dv ,k,s等
2. 元命令:调试器自带,以“.”开头. 提供基本命令没有提供的功能。例如 .reload .sympath等
3. 扩展命令:外部加入的命令,以“!”开头。用于扩展某一方面的调试功能,其实现在动态加载的模块中。例如:!analyze
使用;分隔符,可以在一行输入多个命令。使用 ctrl + break 可以终止一个命令。当输入框显示为busy时,即使输入框可以输入命令,输入的命令也不会立刻执行。
一. windbg 启动调试的办法
分为两种:
1. 命令行方式启动:(又分为打开和附加两种方式)
windbg - i // 将windbg设置为默认调试器
windbg “notepad” arguments //使用windbg 启动notepad调试,设置启动参数
windbg -p 4200 //使用windbg 附加到一个正在运行的PID = 4200的进程
windbg -pn "notepad" //使用windbg附加到一个正在运行的名字为"notepad"的进程
2. 图形界面方式:直接运行windbg.exe
二. 常用的元命令
1. .restart //重启并调试
2 .kill //强制结束当前调试
3. .help //打印出所有元命令
4. .hh //打开windbg chm帮助文档
三. 常用基本命令
1. 搜索命令
s -a 0012ff40 L0x20 "Hello" //搜索ansi字符串“hello”, 从0012ff40地址开始, 长度是 0x20的范围。即搜索范围是 0012ff40~ 0012ff60.
2. 断点命令
bp 0040108c //直接在地址下断
bp test1!Max ; bp Max //直接在函数名上下断
bp 'test1.cpp:30' //在test1.cpp第30行下断
bp CObject::CObject //在CObject构造函数上下断
bp kernel32!CreateFileA //在kernel32.dll模块CreateFileA函数头位置下断
bp TestCommand!CObject::add //在TestCommand.dll模块的CObject类函数add头部下断。
bp `ConsoleTest.cpp:40` ".if (poi(pVar)>5) {};{g}"
// ".if (Condition) {Optional Commands}; {g}" 条件断点 pVar指针指向的值>5,执行空语句(;),断住 否则继续执行
bu test1!Max ;bu Max //在函数的开头下断
bm add_* // 匹配add_开头的函数,并在这些函数起始处都打上断点
ba w4 0x0483dfe0// 当对0483dfe0地址写操作时停下,前面要带上0x,否则会报错。
//ba [r|w|e] [Size] Addr [r=read/write, w=write, e=execute], Size=[1|2|4 bytes]
//这个指令比较强大,可以下内存访问,写入以及执行断点。 内存大小Size :单字节, 双字节,4字节,8字节。
3. 断点管理
bl // 列出所有断点 breakpoint list
bc * // 清除所有断点 breakpoint clear
bc 1 // 清除1号断点
bc 1 2 5 // 清除1号、2号、5号断点
be * // 启用所有断点 breakpoint enable
be 1 // 启用1号断点
be 1 2 5 // 启用1号、2号、5号断点
bd * // 禁用所有断点 breakpoint disable
bd 1 // 禁用1号断点
bd 1 2 5 // 禁用1号、2号、5号断点
4. 断点执行
g // Go(F5)
gu // 执行到当前函数完成时停下【Go Up】
p // 单步执行(F10) 【Step】
pc // 执行到下一个函数调用处停下【Step to Next Call】
pa 7c801b0b // 执行到7c801b0b地址处停下 【Step to Adress】
t // Step into(F11) 【Trace】
tc // 执行到下一个进入点处停下 【Trace to Next Call】
ta 7c801b12 // 执行到7c801b12地址处停下 【Trace to Adress】
5. 进程相关
| // 列出调试进程
|* // 列出调试进程
6. 线程相关
~ // 列出线程
~* // 所有线程
~* k // 所有线程堆栈信息
~* r // 所有线程寄存器信息
~. // 查看当前线程
~0s // 查看主线程
~# // 查看导致当前事件或异常的线程
7. 模块相关
lm //列出进程加载模块
8. 查看变量
dt i_c //查看变量地址, 类型, 值
dt ntdll!* // 显示ntdll里的所有类型信息
dt *!*IMAGE_DOS* // 显示所有模块中含有IMAGE_DOS字符的类型信息
dt myApp!g_app // 表示显示myApp进程里全局变量g_app的内存布局
dt WindbgTest!CTest // 查看模块WindbgTest的CTest的内存布局
dt WindbgTest!CTest 0x0041f8d4 // 将0x0041f8d4地址处内容按照模块WindbgTest的CTest的内存布局来解析
dt this // 查看this指针的类型及成员变量
dt -v _PEB @$PEB // 使用详细模式查看PEB(process's environment block)内存结构
dt tagMSG 0x0336e54c // 类型要使用tagMSG,不能使用typedef产生出的MSG
typedef struct tagMSG{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
dv // 显示当前函数内所有局部变量,函数参数的值
dv nCount // 查看局部变量nCount的值
x //显示当前函数内所有局部变量 ,函数参数的值, 包括变量地址、
x nCount // 查看局部变量nCount的值 和地址
9. 查看堆栈
k // 显示当前调用堆栈
kn // 带栈编号显示当前调用堆栈
kb // 打印出前3个函数参数的当前调用堆栈
kb 5 // 只显示最上的5层调用堆栈
kv // 在kb的基础上增加了函数调用约定等信息
kp // 显示每一层函数调用的完整参数,包括参数类型、名字、取值(必须是完整符号的情况下,private symbols);注意:若程序被优化,这些值不一定对
kd // 打印堆栈的地址
dds //显示栈帧
10. 显示反汇编
u //显示当前eip位置往后的8条指令
uf CTest::add // 反汇编CTest类的add函数
uf /c main // 反汇编main函数,通过/c可以查看main函数中的函数调用(call)都有哪些
ub 000c135d L20 // 查看地址为000c135d指令前的20条指令内容
11. 显示寄存器
r // 显示所有寄存器信息及发生core所在的指令
r eax, edx // 显示eax,edx寄存器信息
r eax=5, edx=6 // 对寄存器eax赋值为5,edx赋值为6
12. 显示内存
!address // 查看进程的所有内存页属性
!address 7ffd8000 // 查看7ffd8000地址处内存页属性
dd /c 5 7c801e02 // 从7c801e02内存处开始以dword为单位显示内存(宽度为:5)
dd /c 5 7c801e02 L8 // 从7c801e02内存处开始以dword为单位显示内存(宽度为:5)【显示8个dword】
da /c 100 7c80ff03 // 从7c80ff03内存处开始显示Ascii字符串(宽度为:100)
du /c 100 7c8022f5 // 从7c8022f5内存处开始显示Unicode字符串(宽度为:100)
s -w 522e0000 L0x100 0x1212 0x2212 0x1234 // 表示在起始地址522e0000之后的0x100个单位内搜索0x1212 0x2212 0x1234系列的起始地址
s -u 522e0000 527d1000 "web" //表示在522e0000 和527d1000之间搜索Unicode 字符串”web”
ea 0x445634 "abc" // 表示在0x445634地址写入Ascii字符串abc, 不包含结束符0
eza 0x445634 "abc" // 表示在0x445634地址写入Ascii字符串abc, 包含结束符0
eu 0x445634 "abc" // 表示在0x445634地址写入Unicode字符串abc, 不包含结束符0
ezu 0x445634 "abc" // 表示在0x445634地址写入Unicode字符串abc, 包含结束符0
ed nCounter 80 // 将变量nCounter的值修改为80(注:80为10进制还是16进制,还是其他,取决于当前进制)
.writemem D:\Test\0041a5e4.bin 0041a5e4 L0x1000 // 将内存地址处0x0041a5e4后面0x1000长度的内容拷贝存储到D:\Test\0041a5e4.bin中
13 查看堆
!heap -s // 显示进程堆的个数(每一项是一个堆,也就是_HEAP结构指针,对应的API是HeapCreate)
dt _HEAP 00140000 // 选取一个堆的地址,打印该堆的内存结构
!heap -a 00140000 // 选取一个堆的地址,打印该堆的信息,比上面打印内存命令更详细直观
14. 虚拟内存
!vadump // 查看虚拟内存布局
15. 查看句柄
!handle // 查看所有句柄的ID