[教程]逆向反汇编第四课

来源:互联网 发布:爱不释手软件下载 编辑:程序博客网 时间:2024/05/06 05:21

在各个语言中有数据结构这个东东,它是计算机存储 组织数据的方式.逆向分析时,确定了数据结构后,算法就容易得到了.有时候事情当然也会反着来,根据特定的算法来判断数据结构.
       先看局部变量的
      局部变量十亿个函数内部定义的变量,只有在函数内才能使用,如计数器,临时变量等.使用局部变量带来的好处,使程序模块化封装变的可能.从汇编语言角度看,局部变量就是在堆栈中进行分配,函数执行完毕后释放这些堆栈,或者直接把局部变量放在寄存器中,我在视频中也告诉各位把寄存器可以理解为变量.
       第一种方法是用堆栈存放局部变量
       局部变量在程序中用"sub esp,8"语句为局部变量分配空间,用[ebp-xxxx]寻址调用这些变量,而参数调用相对于ebp偏移量是正的,即[ebp+xxxx],因此在逆向时比较容易区分开.编译器在优化模式时,则通过esp寄存器直接对局部变量与参数寻址了.当函数退出时,用'add esp,8'平衡堆栈,以释放局部变量所占据的内存.有些编译器,如Delphi通过给esp加一个负值来进行内存分配.另外,编译器可能会用"push reg"指令来取代"sub esp,4"指令,以节省几个字节.局部变量分配堆栈一般有三种形式:
1.
sub esp,n
.....
add esp,n
2.
add esp,-n
....
sub esp,-n
3.
push reg
.....
pop reg
看看第三种形式的实例"push reg"指令来取代"sub  esp,4"指令的.
先看C的代码:

 

view plaincopy to clipboardprint?
  1. int add(int x,int y)   
  2. int main(void)   
  3. {   
  4.     int a=5,b=6; //声明局部变量   
  5.    add (a,b);   
  6.     return 0;    
  7. }   
  8. int add(int x,int y)   
  9. {   
  10.     int z; //声明局部变量   
  11.    z=x+y;   
  12.     return (z);   
  13. }  

 

将他编译后反汇编.

 

view plaincopy to clipboardprint?
  1. 00401000  /$  55            push    ebp   
  2. 00401001  |.  8BEC          mov     ebp, esp   
  3. 00401003  |.  83EC 08       sub     esp, 8                           ;  为局部变量分配内存   
  4. 00401006  |.  C745 FC 05000>mov     dword ptr ss:[ebp-4], 5          ;  参数1放到局部变量[ebp-4]中   
  5. 0040100D  |.  C745 F8 06000>mov     dword ptr ss:[ebp-8], 6          ;  参数2放到局部变量[ebp-8]中   
  6. 00401014  |.  8B45 F8       mov     eax, dword ptr ss:[ebp-8]   
  7. 00401017  |.  50            push    eax   
  8. 00401018  |.  8B4D FC       mov     ecx, dword ptr ss:[ebp-4]   
  9. 0040101B  |.  51            push    ecx   
  10. 0040101C  |.  E8 09000000   call    local.0040102A   
  11. 00401021  |.  83C4 08       add     esp, 8   
  12. 00401024  |.  33C0          xor     eax, eax   
  13. 00401026  |.  8BE5          mov     esp, ebp   
  14. 00401028  |.  5D            pop     ebp   
  15. 00401029  /.  C3            retn  

 

;函数add (int x,int y)反汇编代码如下:

 

view plaincopy to clipboardprint?
  1. 0040102A  /$  55            push    ebp   
  2. 0040102B  |.  8BEC          mov     ebp, esp   
  3. 0040102D  |.  51            push    ecx                              ;  为局部变量分配内存   
  4. 0040102E  |.  8B45 08       mov     eax, dword ptr ss:[ebp+8]        ;  取参数1   
  5. 00401031  |.  0345 0C       add     eax, dword ptr ss:[ebp+C]        ;  参数1+参数2   
  6. 00401034  |.  8945 FC       mov     dword ptr ss:[ebp-4], eax        ;  将相加的结果放到局部变量[ebp-04]中   
  7. 00401037  |.  8B45 FC       mov     eax, dword ptr ss:[ebp-4]        ;  将返回结果放到eax中   
  8. 0040103A  |.  8BE5          mov     esp, ebp   
  9. 0040103C  |.  5D            pop     ebp   
  10. 0040103D  /.  C3            retn  

 

在函数add()里不存在"sub esp,n"这样的指令,程序是通过一句"push ecx"指令来开辟一块堆栈空间的,然后用[ebp-04]来访问这块空间
    局部变量的起始值是随即的,是其他函数执行完后留在堆栈中的垃圾数据,因此需要对其初始化.初始化局部变量有两种方法:一种是通过mov 指令为变量赋值,如"mov [ebp-04],5";另一种是使用Push 指令直接将值压入堆栈,如push 15.
      第二种是利用寄存器
    除了堆栈占用了2个寄存器外,编译器会利用剩下的6个通用寄存器尽可能有效地存放局部变量,这样可以产生最小的代码,提高效率.如果寄存器不够用,编译器将会将变量放到堆栈中.逆向分析时要注意局部变量的生存周期比较短,必须及时确定当前寄存器的变量是那个变量.