当前位置:软件学习 > 其它软件 >>

带你阅读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
补充:软件开发 , 其他 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,