zoukankan      html  css  js  c++  java
  • 反汇编一个c程序

    方式一:使用gcc

    gcc编译有四步走,预编译,编译,汇编,连接

    使用-S编译选项

    [c-sharp] view plaincopy
    1. gcc  -S  test.c  

     

    会在当前目录下生成test.s的文件,该文件即是相应的汇编程序


    方式二:使用gdb

    首先编译时要是用-g编译选项

    [c-sharp] view plaincopy
    1. gcc -g ./test.c  -o ./test  

     

    接着运行gdb

    [c-sharp] view plaincopy
    1. gdb ./test--(可执行文件)  

     

    在gdb中使用 disassemble + frame(帧),即可查看相应代码段的汇编代码

    frame通常为一个函数名。

     

    方式三:使用objdump

    命令为

    [c-sharp] view plaincopy
    1. objdump -d test.o--(目标文件)  

     

    或者  

     

    [c-sharp] view plaincopy
    1. objdump -d  test--(可执行文件)  

     

    一个反汇编代码解释:

    (本例使用的GCC的汇编格式,这种格式叫做GAS(GNU ASsembler ,GNU汇编器) )

    c语言代码如下:

    ------test.c-------

    1. #include <stdio.h>  
    2. #include <unistd.h>  
    3. int static_var = 5;  
    4. int   
    5. fun_ret_int(int a, int b, register int c)  
    6. {  
    7. int d=1;  
    8. return a+b+c+d;  
    9. }  
    10. void fun()  
    11. {  
    12. int i1, i2, i3, i4,i5, i6,i7,i8,i9,i10;  
    13. i1=1;i2=3;i3=5; i4=7;i5=9; i6=11;i7=13;i8=15;i9=17;i10=19;  
    14. int i;  
    15. for(i=11; i< 20;++i);  
    16. i2 = fun_ret_int(1, 2, i1);  
    17. }  
    18. int main(int argc ,char *argv[])  
    19. {  
    20. int i =1;   
    21. int b =2;  
    22. argc = 3;  
    23. char **a=argv;  
    24. fun();  
    25. return 0;  
    26. }  

     

    现在编译:

    gcc  test.c -o test

    反汇编 :

    objdump -d test

    我截取部分代码如下:

    1. 08048394 <fun_ret_int>:  
    2.  8048394:   55                   push   %ebp  
    3.  8048395:   89 e5                   mov    %esp,%ebp  
    4.  8048397:   83 ec 10             sub    $0x10,%esp  
    5.  804839a:   8b 4d 10             mov    0x10(%ebp),%ecx  
    6.  804839d:   c7 45 fc 01 00 00 00 movl   $0x1,-0x4(%ebp)  
    7.  80483a4:   8b 45 0c             mov    0xc(%ebp),%eax  
    8.  80483a7:   8b 55 08             mov    0x8(%ebp),%edx  
    9.  80483aa:   8d 04 02             lea    (%edx,%eax,1),%eax  
    10.  80483ad:   01 c8                   add    %ecx,%eax  
    11.  80483af:   03 45 fc             add    -0x4(%ebp),%eax  
    12.  80483b2:   c9                   leave    
    13.  80483b3:   c3                   ret      
    14. 080483b4 <fun>:  
    15.  80483b4:   55                   push   %ebp  
    16.  80483b5:   89 e5                   mov    %esp,%ebp  
    17.  80483b7:   83 ec 3c             sub    $0x3c,%esp  
    18.  80483ba:   c7 45 fc 01 00 00 00 movl   $0x1,-0x4(%ebp)  
    19.  80483c1:   c7 45 f8 03 00 00 00 movl   $0x3,-0x8(%ebp)  
    20.  80483c8:   c7 45 f4 05 00 00 00 movl   $0x5,-0xc(%ebp)  
    21.  80483cf:   c7 45 f0 07 00 00 00 movl   $0x7,-0x10(%ebp)  
    22.  80483d6:   c7 45 ec 09 00 00 00 movl   $0x9,-0x14(%ebp)  
    23.  80483dd:   c7 45 e8 0b 00 00 00 movl   $0xb,-0x18(%ebp)  
    24.  80483e4:   c7 45 e4 0d 00 00 00 movl   $0xd,-0x1c(%ebp)  
    25.  80483eb:   c7 45 e0 0f 00 00 00 movl   $0xf,-0x20(%ebp)  
    26.  80483f2:   c7 45 dc 11 00 00 00 movl   $0x11,-0x24(%ebp)  
    27.  80483f9:   c7 45 d8 13 00 00 00 movl   $0x13,-0x28(%ebp)  
    28.  8048400:   c7 45 d4 01 00 00 00 movl   $0x1,-0x2c(%ebp)  
    29.  8048407:   c7 45 d0 0b 00 00 00 movl   $0xb,-0x30(%ebp)  
    30.  804840e:   eb 04                   jmp    8048414 <fun+0x60>  
    31.  8048410:   83 45 d0 01             addl   $0x1,-0x30(%ebp)  
    32.  8048414:   83 7d d0 13             cmpl   $0x13,-0x30(%ebp)  
    33.  8048418:   7e f6                   jle    8048410 <fun+0x5c>  
    34.  804841a:   8b 45 fc             mov    -0x4(%ebp),%eax  
    35.  804841d:   89 44 24 08             mov    %eax,0x8(%esp)  
    36.  8048421:   c7 44 24 04 02 00 00 movl   $0x2,0x4(%esp)  
    37.  8048428:   00   
    38.  8048429:   c7 04 24 01 00 00 00 movl   $0x1,(%esp)  
    39.  8048430:   e8 5f ff ff ff       call   8048394 <fun_ret_int>  
    40.  8048435:   89 45 f8             mov    %eax,-0x8(%ebp)  
    41.  8048438:   c9                   leave    
    42.  8048439:   c3                   ret      
    43. 0804843a <main>:  
    44.  804843a:   55                   push   %ebp  
    45.  804843b:   89 e5                   mov    %esp,%ebp  
    46.  804843d:   83 ec 10             sub    $0x10,%esp  
    47.  8048440:   c7 45 fc 01 00 00 00 movl   $0x1,-0x4(%ebp)  
    48.  8048447:   c7 45 f8 02 00 00 00 movl   $0x2,-0x8(%ebp)  
    49.  804844e:   c7 45 08 03 00 00 00 movl   $0x3,0x8(%ebp)  
    50.  8048455:   8b 45 0c             mov    0xc(%ebp),%eax  
    51.  8048458:   89 45 f4             mov    %eax,-0xc(%ebp)  
    52.  804845b:   e8 54 ff ff ff       call   80483b4 <fun>  
    53.  8048460:   b8 00 00 00 00       mov    $0x0,%eax  
    54.  8048465:   c9                   leave    
    55.  8048466:   c3                   ret      
    56.  8048467:   90                   nop  
    57.  8048468:   90                   nop  
    58.  8048469:   90                   nop  
    59.  804846a:   90                   nop  
    60.  804846b:   90                   nop  
    61.  804846c:   90                   nop  
    62.  804846d:   90                   nop  
    63.  804846e:   90                   nop  
    64.  804846f:   90                   nop  

     

    现在尝试对其中的一些语句进行分析:

    在每个函数的开始部分都是:

    [c-sharp] view plaincopy
    1. push   %ebp  
    2. mov    %esp,%ebp  
    3. sub    $***,%esp  

     

    %ebp---是帧寄存器,在函数中就是函数的基址寄存器,指向一个函数的栈底(帧底)。

    %esp---是栈寄存器,相当于是整个程序的基址寄存器,始终指向栈顶。

    push---入栈操作。

    mov ---移动

    sub ---减法

    第一句话 push   %ebp 的意思是%ebp入栈,此时的%ebp保存的是上一个函数的帧起始地址,也即调用该函数的地址。

    把%ebp压栈,保存起来,以便返回。

    第二句  mov    %esp,%ebp 的意思是  把%esp赋值给%ebp,%esp保存的是当前程序的栈顶,也即该函数所占用内存的起始地址。

    把%esp赋值给%ebp,也就把%ebp设置成了当前函数的帧起始地址。

    第三句话sub    $***,%esp,并不会在每个程序中都会出现。可以尝试一下,如果一个函数没有任何局部变量,那么反汇编这句话也就

    不会出来。这句话的意思是,把%esp减去一个数。我们知道栈空间是由高到底发展的,所以%esp++,相当于%esp=%esp-1。因为调用了 新函数,而且该函数有局部变量,那么栈空间就变大了,所以要扩展栈空间,也即是修改%esp,让其指向更低的地址。而让%esp减去多少呢?这要看函数占 用多少空间,于其中的局部变量有关,以及他将调用的函数参数有关。其并不计算其参数所占的空间,其参数所占的空间要算在调用它的函数中。

    下面来看看参数的压栈顺序;

    函数fun中语句:

    1. i2 = fun_ret_int(1, 2, i1);  

     

    所对应的汇编如下:

    [c-sharp] view plaincopy
    1. 804841a:    8b 45 fc             mov    -0x4(%ebp),%eax    
    2. 804841d:    89 44 24 08             mov    %eax,0x8(%esp)  
    3. 8048421:    c7 44 24 04 02 00 00 movl   $0x2,0x4(%esp)  
    4. 8048428:    00   
    5. 8048429:    c7 04 24 01 00 00 00 movl   $0x1,(%esp)  
    6. 8048430:    e8 5f ff ff ff       call   8048394 <fun_ret_int>  

     

    从这个汇编中可以看出函数参数的入栈顺序是自左往右的。

    mov    -0x4(%ebp),%eax  是把i1 放到%eax 寄存器中

    mov    %eax,0x8(%esp)   是把%eax压栈,所以这句话是把i1放在距离%esp为8byte的地方,即8~12byte存放的是一个i1(int)

    movl   $0x2,0x4(%esp)   距%esp 4~8byte存放的是2(int)

    movl   $0x1,(%esp)      距%esp 0~4byte存放的是1(int)

    因为栈是由高到低的,且%esp始终指向栈顶。所以看出入栈顺序是i1,2,1。正好与c文件中fun函数的参数顺序相反。

    自右向左压栈有什么好处呢?第一,由于栈是FILO,所以反方向入栈,那么第一个参数也就距离%esp越近。每次取参数时也就很方便,不用把所有参数占用的空间都计算出来,然后在取。第二,当传递的参数过多时,每次都从栈顶计算,取适当位置的参数,其他便可忽略。

    via:http://blog.csdn.net/plo154100/article/details/6409778

  • 相关阅读:
    CSRF 攻击
    PHP中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用
    PHP PDO函数库详解
    STK基础
    opnet统计结果的采集模式——capture mode
    一个博客园代码高亮的方案
    博客园TinyMCE编辑器中插入的代码块使用HTML编辑器再编辑
    local statistics和global statistics的区别
    opnet的函数中FIN、FRET和FOUT
    福昕阅读器默认打开pdf文件视图大小
  • 原文地址:https://www.cnblogs.com/cloud2rain/p/3058611.html
Copyright © 2011-2022 走看看