带你阅读VC生成的经典反汇编代码,提高反汇编阅读能力
没事在百度逛了下,看见有这样的方法提高反汇编能力!刚写的关于如何提高反汇编代码阅读能力的帖子,顺便把一些call啊,堆栈平衡啊,局部变量访问啊这些东西结合实例说了一下
把自己写好的“hello world”程序源码加载到VC中,给main函数下个断点(F9下断点)
然后按F5运行至断点,VC把程序断下来的时候在断点代码处 右键菜单go to disassembly就可以看汇编代码了!
而且还是一行一行,源码对照反汇编解释给你看的。。
写一个小程序
#include <stdio.h>
void main(int argc[],char *argv[])
{
int a,b;
a=1;
b=2;
a=a+b;
}
然后按照我刚才说的方法看汇编代码。。
用VC看汇编代码的好处就是能对照着看,坏处就是,如果你想看指定内存地址或者寄存器的数据的话,得自己在监视窗口中添加,很麻烦,调试程序时通常要眼观八方,注意数据寄存器,内存地址,和堆栈发生的变化,所以明显VC翻译汇编代码的功能着实有点好处,但比起OD来还是有点麻烦,那还是用回OD吧,程序载入时先执行的其实不是main函数,而是编译器生成的一些初始化代码,这些代码暂且不讨论吧,直接来到main函数吧,在OD中怎么到达main函数呢,在这里介绍一个技巧:
将程序改写成如下:
#include <stdio.h>
void main(int argc[],char *argv[])
{
char *a="1234567";
printf("%s",a);
然后将程序载入OD,右键-查看-所有参考文本串,在弹出的窗口中招字符串“12345”,然后双击这个字符串,OD就会把你带到main函数的附近了,到了main函数附近之后,就找push ebp吧(程序的经典开头代码)
下面把完整代码贴一遍(注意蓝色为main函数中代码 红色部分为一个校验堆栈平衡的一个函数。)
00401010 > 55 push ebp ; 保存原来的ebp
00401011 8BEC mov ebp,esp ; 使得ebp=esp
00401013 83EC 44 sub esp,44 ; 预留44h个字节的空间
上面一句的详细解释:上面预留的44h个字节空间即68个字节的空间,即预留17个变量的空间(每个变量4个字节),其中我们的程序定义了一个变量--即指向常量字符串的指针a
00401016 53 push ebx
00401017 56 push esi
00401018 57 push edi
;上面三句是因为后面要用到这三个寄存器 所以为了程序执行完后不改变寄存器值 而保存他们,程序执行完后恢复
00401019 8D7D BC lea edi,dword ptr ss:[ebp-44];将edi设置为栈中一块连续区域的首地址
0040101C B9 11000000 mov ecx,11 ; 11h=17,为什么要给ecx赋予17呢,我们往下看
00401021 B8 CCCCCCCC mov eax,CCCCCCCC ;为什么要给eax赋予8个c呢,我们往下看
00401026 F3:AB rep stos dword ptr es:[edi]
现在开始解释上面三句,我先讲第三句吧,第三句的功能就是:将eax寄存器的值复制给由es:[edi]指向的内存区域,复制多少次呢?
ecx次!就是17次,就是将17个eax放到以es:[edi]为首地址的内存区域中,这样做没别的意思,就是初始化变量而已。
00401028 C745 FC 1C00420>mov dword ptr ss:[ebp-4],CPPlearn.>; 把字符串常量的指针给ss:[ebp-4]也就是我们定义的指针变量a
0040102F 8B45 FC mov eax,dword ptr ss:[ebp-4] ; 再将指a赋值给eax
00401032 50 push eax
00401033 68 B0074200 push CPPlearn.004207B0 ; ASCII "%s"
00401038 E8 53000000 call CPPlearn.printf
0040103D 83C4 08 add esp,8 ; 压栈调用函数,然后由主程序恢复堆栈平衡 压栈调用函数,你懂的!
00401040 5F pop edi
00401041 5E pop esi
00401042 5B pop ebx ; 犯罪现场重现
00401043 83C4 44 add esp,44 ; 释放掉占44h字节大小的在main中的所有变量
00401046 3BEC cmp ebp,esp,在这里如果因为一些意外而使得恢复之后的esp不等于原来的esp(原来的esp保存在ebp)的话,将会出现一些问题,继续往下看
00401048 E8 C3000000 call CPPlearn._chkesp
{
00401110 > /75 01 jnz short CPPlearn.00401113 ; 当ebp与esp相等时,属于正常情况,所以就不跳转了直接 返回主程序,其实我觉得这个判断应该由主程序来做,那就不用进call了,进call要浪费点时间。这里为了跟踪代码,我故意将Z标志位改成0(即比较结果不为0)
所以他的jnz就能实现跳转了。(跳到下面的401112去了)
00401112 |C3 retn
00401113 \55 push ebp ; 又一个子程序,犯罪现场保存恢复这些垃圾话我就不说了
00401114 8BEC mov ebp,esp
00401116 83EC 00 sub esp,0
00401119 50 push eax
0040111A 52 push edx
0040111B 53 push ebx
0040111C 56 push esi
0040111D 57 push edi
0040111E 68 54004200 push CPPlearn.00420054 &nbs
补充:软件开发 , 其他 ,