#include "stdafx.h"

#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网页超链接的形式,供程序员在堆栈中快速切换函数并且显示变量值,

 kM

 # 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)了

dt argv

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)命令就可以显示完整的字符串内容了。

du 000d1b9c 

000d1b9c  "E:\ProLab\WindbgFirst\Debug\MyAp"

000d1bdc  "p.exe"

0:000> du 

000d1be8  "226"

发现连续执行du,windbg会默认去取下一个地址的内容,呈现出来.

但是也有很多情况下,你可能并不知道指定地址里面保存的内容是什么,这个时候,建议你用dc(display
double-word values and ASCII characters)命令查看内存。

dc 000d1b90 

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命令来显示内存

最新文章

  1. Dapper.NET——轻量ORM
  2. js杂项
  3. Extjs,Git,插件....学习网址
  4. 关于最近折腾的ubuntu12.10
  5. Entity Framework一对多关系添加数据的两种方式
  6. 深入理解计算机系统家庭作业汇总 20135301&amp;&amp;20135328
  7. AudioManager音频管理器控制手机音频实例
  8. SQL Server :DBLINK创建及使用
  9. 简单的div元素拖拽到div
  10. 理解MySQL——架构与概念
  11. 在Ubuntu下构建Bullet以及执行Bullet的样例程序
  12. C#代码实现把网页文件保存为mht文件
  13. HDU 6112 今夕何夕
  14. Keepalived概述和安装(1)
  15. MS SQL 日志记录管理
  16. &quot;《算法导论》之‘线性表’&quot;:基于静态分配的数组的顺序表
  17. Cordova入门系列(三)Cordova插件调用
  18. qrcode.php
  19. css3 之border-radius 属性解析
  20. 在GridView控件内文本框实现TextChanged事件

热门文章

  1. fork执行一个进程
  2. 笔记44 Hibernate快速入门(一)
  3. 自定义实现系统max方法
  4. 29. StringBuilder
  5. 【历年真题】斐波那契数列logn做法
  6. bzoj1038题解
  7. NX二次开发-UFUN工程图表格注释写入文本内容UF_TABNOT_set_cell_text
  8. (转)JAVA国际化
  9. 牛客多校第九场 D Knapsack Cryptosystem 背包
  10. CSS3:CSS3 简介