转载+整理 http://www.cnblogs.com/killmyday
编译,用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命令(注意前面的点号)。
6. dv(display variables)
切换了函数以后,下一步就是查看变量的值,使用dv命令来查看变量信息,这个命令相当于Visual Studio里面的局部变量(locals)窗口。
7. kM
.frame的方式比较复杂,因此windbg提供了一个快捷命令,kM(callstack with markup)。这个命令提供了一个类似html网页超链接的形式,供程序员在堆栈中快速切换函数并且显示变量值,
8. dt
对于简单类型,例如整型、浮点型甚至是字符串,windbg可以直接显示出变量的值。但是对于一些复杂类型,例如数组,结构,类呀,那就需要借助另外一个命令dt(display type)了
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继续分析argv数组内容
既然我们已经知道argv数组的大小是2的话,你也可以将这个信息提供给dd命令,告诉它你只需要显示argv指针所指向的内存的两个元素就可以了
10. dd 000d1b90 L2
000d1b90 000d1b9c 000d1be8
11. 执行了这么多命令以后,我们终于可以看到argv[0]和argv[1]的值了,不容易呀!既然已经知道是unicode字符串,使用du(display unicode)命令就可以显示完整的字符串内容了。
发现连续执行du,windbg会默认去取下一个地址的内容,呈现出来.
但是也有很多情况下,你可能并不知道指定地址里面保存的内容是什么,这个时候,建议你用dc(display double-word values and ASCII characters)命令查看内存。
如果你调试的是一个非unicode程序,即是一个只理解ASCII字符集的程序(也就是所有字符串的类型都是char),那么在查看字符串的时候,使用da(display ascii)而不是du命令来显示内存