Windbg Step 2 分析程序堆栈实战

#include <tchar.h>
#ifdef _UNICODE
#define _ttol _wtol
#else
#define _ttol atol
#endif
void Usage()
{
#ifdef _UNICODE
wprintf(L"[Usage]: nativedebug.exe <digital numbers>\n");
#else
printf("[Usage]: nativedebug.exe <digital numbers>\n");
#endif
}
int _tmain(int argc, _TCHAR* argv[])
{
int result = 0;
if ( argc != 2 )
{
Usage();
return -1;
}
result = _ttol(argv[1]);
#ifdef _UNICODE
wprintf(L"%s * %s = %d\n", argv[1], argv[1], result * result);
wprintf(L"Press any key to exit ...\n");
_getwch();
#else
printf("%s * %s = %d\n", result * result);
printf("Press any key to exit ...\n");
_getch();
#endif
return 0;
}

编译,用Windbg分析。
1. 设置断点,打开源文件,直接在result = _ttol(argv[1]);按F9
或者设置_wtol和atol的断点:
因为代码中有:
#ifdef _UNICODE
# define _ttol _wtol
#else
# define _ttol atol
#endif
而宏是在编译期间就被编译器扩展,并不会被加到符号文件中去,因此如果你试图使用bp命令在_ttol入口设置断点的话,是会失败的。因此你可以使用类似下面的通配符来查找正确的函数名:
x MSVCR90D!*tol×
然后用bm *tol*给所有含有tol的函数都设置断点;
然后用bl查看断点列表,用bc 2-6 清除,用bd 2-6禁用 第二个到6个断点
2. lm查看loaded Modules
lm
start end module name
01330000 0134b000 MyApp C (private pdb symbols) E:\ProLab\WindbgFirst\Debug\MyApp.pdb
59bc0000 59ce4000 MSVCR90D (deferred)
75100000 75200000 kernel32 (deferred)
76750000 76796000 KERNELBASE (deferred)
77500000 77680000 ntdll (pdb symbols) c:\websymbols\wntdll.pdb\ACE318E6A2F44F23A6CC5628F10A7DDC2\wntdll.pdb
我们发现MSVCR90D的pdb并没有被加载,是因为程序还没运行到,
3. 按F11
没有跳到源代码!
运行:src.path C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\crt\src
4. lm
lm
start end module name
01330000 0134b000 MyApp C (private pdb symbols) E:\ProLab\WindbgFirst\Debug\MyApp.pdb
598d0000 599f4000 MSVCR90D (private pdb symbols) c:\websymbols\msvcr90d.i386.pdb\EBEA784C96244F1E8F8D35E0391C898D1\msvcr90d.i386.pdb
75100000 75200000 kernel32 (deferred)
76750000 76796000 KERNELBASE (deferred)
77500000 77680000 ntdll (pdb symbols) c:\websymbols\wntdll.pdb\ACE318E6A2F44F23A6CC5628F10A7DDC2\wntdll.pdb
5. 查看堆栈 k / kp / kP / kn
k比较简单,kp能看到各个函数的输入参数,kP比kp看起来更舒服,kn(callstack with index number)
在windbg中,在堆栈中切换到不同的函数,需要用到.frame命令(注意前面的点号)。

kn
# ChildEBP RetAddr
00 0021fa0c 01341464 MSVCR90D!_wtol [f:\dd\vctools\crt_bld\self_x86\crt\src\atox.c @ 55]
01 0021faf0 01341a88 MyApp!wmain+0x44 [e:\prolab\windbgfirst\windbgfirst\windbgfirst.cpp @ 29]
02 0021fb40 013418cf MyApp!__tmainCRTStartup+0x1a8 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 583]
03 0021fb48 75113677 MyApp!wmainCRTStartup+0xf [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 403]
04 0021fb54 77539d42 kernel32!BaseThreadInitThunk+0xe
05 0021fb94 77539d15 ntdll!__RtlUserThreadStart+0x70
06 0021fbac 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> .frame 01
01 0021faf0 01341a88 MyApp!wmain+0x44 [e:\prolab\windbgfirst\windbgfirst\windbgfirst.cpp @ 29]
0:000> dv
argc = 0n2
argv = 0x000d1b90
result = 0n0

6. dv(display variables)
切换了函数以后,下一步就是查看变量的值,使用dv命令来查看变量信息,这个命令相当于Visual Studio里面的局部变量(locals)窗口。
7. kM
.frame的方式比较复杂,因此windbg提供了一个快捷命令,kM(callstack
with markup)。这个命令提供了一个类似html网页超链接的形式,供程序员在堆栈中快速切换函数并且显示变量值,

# ChildEBP RetAddr
00 0021fa0c 01341464 MSVCR90D!_wtol+0x5
01 0021faf0 01341a88 MyApp!wmain+0x44
02 0021fb40 013418cf MyApp!__tmainCRTStartup+0x1a8
03 0021fb48 75113677 MyApp!wmainCRTStartup+0xf
04 0021fb54 77539d42 kernel32!BaseThreadInitThunk+0xe
05 0021fb94 77539d15 ntdll!__RtlUserThreadStart+0x70
06 0021fbac 00000000 ntdll!_RtlUserThreadStart+0x1b

8. dt
对于简单类型,例如整型、浮点型甚至是字符串,windbg可以直接显示出变量的值。但是对于一些复杂类型,例如数组,结构,类呀,那就需要借助另外一个命令dt(display
type)了
Local var @ 0x21fafc Type wchar_t**
0x000d1b90
unsigned short,在C和C++程序中,一般都意味着是wchar_t(宽字符)类型
**表示是一个包含宽字符字符串的数组
9. dd(display by double-word)
下一步就是继续查看argv数组里面的内容,根据前面的dv打印的结果,我们知道argc(也就是说明argv数组元素个数的参数)的值是2。在一台32位机(或者是在64位机器上调试一个32位的程序),使用dd命令参看argv的内存,以四字节的形式显示,如果是64位,使用dq(display
by quad-word)命令以8个字节的形式打印内存。
dd默认是显示32个dword,也就是128个字节的内存内容。

# 将argv传给dd命令的时候, windbg是先将argv转换成保存
# 数组指针的地址(就是0021fafc)—毕竟数组的指针也是需要地方保存的嘛。
# 而高亮显示的00081350才是保存argv数组内容的真实地址
dd argv
0021fafc 000d1b90 000d1c30 164b267e 00000000
0021fb0c 00000000 7efde000 00da7a64 00000000
0021fb1c 00000000 00220000 00000000 0021fb04
0021fb2c 00000069 0021fb84 01341087 175eb66e
0021fb3c 00000000 0021fb48 013418cf 0021fb54
0021fb4c 75113677 7efde000 0021fb94 77539d42
0021fb5c 7efde000 76a0918c 00000000 00000000
0021fb6c 7efde000 00000000 00000000 00000000

继续分析argv数组内容
既然我们已经知道argv数组的大小是2的话,你也可以将这个信息提供给dd命令,告诉它你只需要显示argv指针所指向的内存的两个元素就可以了
10. dd 000d1b90 L2
000d1b90 000d1b9c 000d1be8
11. 执行了这么多命令以后,我们终于可以看到argv[0]和argv[1]的值了,不容易呀!既然已经知道是unicode字符串,使用du(display
unicode)命令就可以显示完整的字符串内容了。
000d1b9c "E:\ProLab\WindbgFirst\Debug\MyAp"
000d1bdc "p.exe"
0:000> du
000d1be8 "226"
发现连续执行du,windbg会默认去取下一个地址的内容,呈现出来.
但是也有很多情况下,你可能并不知道指定地址里面保存的内容是什么,这个时候,建议你用dc(display
double-word values and ASCII characters)命令查看内存。

000d1b90 000d1b9c 000d1be8 00000000 003a0045 ............E.:.
000d1ba0 0050005c 006f0072 0061004c 005c0062 \.P.r.o.L.a.b.\.
000d1bb0 00690057 0064006e 00670062 00690046 W.i.n.d.b.g.F.i.
000d1bc0 00730072 005c0074 00650044 00750062 r.s.t.\.D.e.b.u.
000d1bd0 005c0067 0079004d 00700041 002e0070 g.\.M.y.A.p.p...
000d1be0 00780065 00000065 00320032 00000036 e.x.e...2.2.6...
000d1bf0 fdfdfdfd abababab abababab feeefeee ................
000d1c00 00000000 00000000 31dcc3ca 1800157c ...........1|...

如果你调试的是一个非unicode程序,即是一个只理解ASCII字符集的程序(也就是所有字符串的类型都是char),那么在查看字符串的时候,使用da(display
ascii)而不是du命令来显示内存
Windbg Step 2 分析程序堆栈实战的更多相关文章
- 调试技巧 —— 如何利用windbg + dump + map分析程序异常
调试技巧 —— 如何利用windbg + dump + map分析程序异常 逗比汪星人2011-09-04上传 调试技巧 —— 如何利用windbg + dump + map分析程序异常 http ...
- 微信小程序教学第二章:小程序中级实战教程之预备篇 - 项目结构设计 |基于最新版1.0开发者工具
iKcamp官网:http://www.ikcamp.com 访问官网更快阅读全部免费分享课程:<iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享>. ...
- 通过官方API结合源码,如何分析程序流程
通过官方API结合源码,如何分析程序流程通过官方API找到我们关注的API的某个方法,然后把整个流程执行起来,然后在idea中,把我们关注的方法打上断点,然后通过Step Out,从内向外一层一层分析 ...
- JVM:如何分析线程堆栈
英文原文:JVM: How to analyze Thread Dump 在这篇文章里我将教会你如何分析JVM的线程堆栈以及如何从堆栈信息中找出问题的根因.在我看来线程堆栈分析技术是Java EE产品 ...
- python爬取微信小程序(实战篇)
python爬取微信小程序(实战篇) 本文链接:https://blog.csdn.net/HeyShHeyou/article/details/90452656 展开 一.背景介绍 近期有需求需要抓 ...
- 应用程序框架实战二十二 : DDD分层架构之仓储(层超类型基础篇)
前一篇介绍了仓储的基本概念,并谈了我对仓储的一些认识,本文将实现仓储的基本功能. 仓储代表聚合在内存中的集合,所以仓储的接口需要模拟得像一个集合.仓储中有很多操作都是可以通用的,可以把这部分操作抽取到 ...
- 应用程序框架实战十五:DDD分层架构之领域实体(验证篇)
在应用程序框架实战十四:DDD分层架构之领域实体(基础篇)一文中,我介绍了领域实体的基础,包括标识.相等性比较.输出实体状态等.本文将介绍领域实体的一个核心内容——验证,它是应用程序健壮性的基石.为了 ...
- google perftools分析程序性能
Google perftools 1.功能简介 它的主要功能就是通过采样的方式,给程序中cpu的使用情况进行“画像”,通过它所输出的结果,我们可以对程序中各个函数(得到函数之间的调用关系)耗时情况一目 ...
- [大数据从入门到放弃系列教程]第一个spark分析程序
[大数据从入门到放弃系列教程]第一个spark分析程序 原文链接:http://www.cnblogs.com/blog5277/p/8580007.html 原文作者:博客园--曲高终和寡 **** ...
随机推荐
- 关于虚拟机中linux系统时间的问题
由于考试需求,我在vm上放置了考试用的linux环境,在进行操作的时候需要回调时间才能进行一些操作.但是每次重启之后,时间总是会和物理服务器的时间进行同步,让我非常的苦恼. 终于有一天我想清楚了如何表 ...
- Zabbix-1.8.14 安装
CentOS 6.9Apache 2.2PHP 5.3.3MySQL 5.1.73 1.下载安装zabbix软件源 在http://repo.zabbix.com/zabbix/1.8/rhel/6/ ...
- ubuntu查看时间同步服务器的匹配源
当服务器时间与设定好的同步时间源的时间有差异的时候,一般都需要先查看本机的时间同步服务功能是否在正常的运转,以及同步的时间源是哪里,在这里为大家提供一个检查时间用的命令. ubuntu版本 servi ...
- Tools: geos 使用指南
1. 下载geos 2. 进入VS开发人员命令提示3.依次执行如下命令 >VCVARS32.BAT>cd D:\DevTool\geos-3.7.0>atuogen.bat>n ...
- [转]sourceforge文件下载过慢
sourceforge文件下载过慢,可以用下面网址镜像下载, 通过 下载Sourceforge等国内无法下载站点文件的另一种方法博文,好像主站点是 https://www.mirrorservice. ...
- 50. Set接口和Set的实现类HashSet
集合分类:-------------------| Collection 单列集合的根接口 ---------------| List 如果实现了List接口的集合类,具备的特点是:有序,可重复- ...
- SOLID设计原则
SOLID设计原则 Single Responsibility Principle单一职责原则 单一职责原则(SRP)表明一个类有且只有一个职责. 一个类就像容器一样,它能添加任意数量的属性.方法等. ...
- 删除重复数据并保留id最小的一条记录
delete from test where id not in ( select a.id from (select min(id) as id from test group by form_i ...
- js特效玫瑰花
<script> var b = document.body; var c = document.getElementsByTagName('canvas')[0]; var a = c. ...
- C/C++ warning C4251: class ... 需要有 dll 接口由 class“..” 的客户端使用
{ 在DLL编程中, 如果调用模版类, 则可能出现类似以下的错误: 1>xclock.h(29): warning C4251: “XClock::m_FileName”: class“std: ...