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 原文作者:博客园--曲高终和寡 **** ...
随机推荐
- 在windows server 2012中安装完oracle 11 client如何使用
1.首先要添加监听配置,这样才可以没有报错的连接上服务器,至于如何添加,请自行搜索. 2.打开SQL Plus连接oracle server端,这里因为是小白,看到命令行界面上来就需要输入用户名密码 ...
- Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志
其实,小哈在之前就出过一篇关于如何使用 AOP 切面统一打印请求日志的文章,那为什么还要再出一篇呢?没东西写了? 哈哈,当然不是!原因是当时的实现方案还是存在缺陷的,原因如下: 不够灵活,由于是以所有 ...
- Jvm之class文件的加载、初始化
编写的java文件在要真正运行时,会首先被编译成 “.class"结尾的二进制文件,然后被虚拟机加载.那么在虚拟机中一个class文件要成为java实例,需要经历好几个步骤: 一.class ...
- Download Kali Linux
https://www.kali.org/downloads/
- 引入CSS样式表(书写位置)
CSS可以写到那个位置? 是不是一定写到html文件里面呢? 内部样式表 内嵌式是将CSS代码集中写在HTML文档的head头部标签中,并且用style标签定义,其基本语法格式如下: <head ...
- Android中的APK,TASK,PROCESS,USERID之间的关系
开发Android已经有一段时间了,今天接触到底层的东西,所以对于进程,用户的id以及Android中的Task,Apk之间的关系,要做一个研究,下面就是研究结果: apk一般占一个dalvik,一个 ...
- bzoj1059题解
[解题思路] 因为只要验证可行性,所以考虑行和考虑列是等价的,故我们只考虑行的交换操作. 这样,拆一波点,把每一行拆成两个点,左边为原交换行,右边为目标交换行,原问题等价于能否对这个二分图进行完全匹配 ...
- 微信-小程序-开发文档-服务端-模板消息:templateMessage.deleteTemplate
ylbtech-微信-小程序-开发文档-服务端-模板消息:templateMessage.deleteTemplate 1.返回顶部 1. templateMessage.deleteTemplate ...
- Linux下同一目录内文件和目录为什么不能同名?
问题描述: 如果事先有叫‘A’的文件夹存在,则不允许建立叫‘A’的文件: 同理若先有叫‘b’的文件存在,一样不允许建立叫‘b’的文件夹. 原因很简单,因为Linux下一切都是文件,一个目录归根到底还是 ...
- 关于ctype.h头文件使用说明
ctype.h里的函数概况: 1.字符测试函数 (1)函数原型均为 int isXXX( int ch) (2)参数为int,任何参数均被转换为整形 (3)只能处理[0,127]之间的值 2.字符映射 ...