zoukankan      html  css  js  c++  java
  • 逆向--C函数和汇编

    C函数和汇编

    C代码

    (编译工具gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609平台ubuntu i386 32位)

    int bar(int c , int d){
        int e = c +d;
        return e;
    }
    
    int foo (int a , int b){
        return bar(a,b);
    }
    
    int main (void){
        foo(2,3);
        return 0;
    }
    

    gcc -S -masm=intel function_asm.c 生成一个intel风格的汇编代码文件

            .file   "function_asm.c"
            .intel_syntax noprefix
            .text
            .globl  bar
            .type   bar, @function
    bar:
    .LFB0:
            .cfi_startproc
            push    ebp
            .cfi_def_cfa_offset 8
            .cfi_offset 5, -8
            mov     ebp, esp
            .cfi_def_cfa_register 5
            sub     esp, 16
            mov     edx, DWORD PTR [ebp+8]
            mov     eax, DWORD PTR [ebp+12]
            add     eax, edx
            mov     DWORD PTR [ebp-4], eax
            mov     eax, DWORD PTR [ebp-4]
            leave
            .cfi_restore 5
            .cfi_def_cfa 4, 4
            ret
            .cfi_endproc
    .LFE0:
            .size   bar, .-bar
            .globl  foo
            .type   foo, @function
    foo:
    .LFB1:
            .cfi_startproc
            push    ebp
            .cfi_def_cfa_offset 8
            .cfi_offset 5, -8
            mov     ebp, esp
            .cfi_def_cfa_register 5
            push    DWORD PTR [ebp+12]
            push    DWORD PTR [ebp+8]
            call    bar
            add     esp, 8
            leave
            .cfi_restore 5
            .cfi_def_cfa 4, 4
            ret
            .cfi_endproc
    .LFE1:
            .size   foo, .-foo
            .globl  main
            .type   main, @function
    main:
    .LFB2:
            .cfi_startproc
            push    ebp
            .cfi_def_cfa_offset 8
            .cfi_offset 5, -8
            mov     ebp, esp
            .cfi_def_cfa_register 5
            push    3
            push    2
            call    foo
            add     esp, 8
            mov     eax, 0
            leave
            .cfi_restore 5
            .cfi_def_cfa 4, 4
            ret
            .cfi_endproc
    .LFE2:
            .size   main, .-main
            .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609"
            .section        .note.GNU-stack,"",@progbits
    
    

    objdump -M intel -S -d a.out 将生成的二进制文件用intel格式反汇编,我们关心的如下:

    080483db <bar>:
     80483db:       55                      push   ebp
     80483dc:       89 e5                   mov    ebp,esp
     80483de:       83 ec 10                sub    esp,0x10
     80483e1:       8b 55 08                mov    edx,DWORD PTR [ebp+0x8]
     80483e4:       8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
     80483e7:       01 d0                   add    eax,edx
     80483e9:       89 45 fc                mov    DWORD PTR [ebp-0x4],eax
     80483ec:       8b 45 fc                mov    eax,DWORD PTR [ebp-0x4]
     80483ef:       c9                      leave
     80483f0:       c3                      ret
    
    080483f1 <foo>:
     80483f1:       55                      push   ebp
     80483f2:       89 e5                   mov    ebp,esp
     80483f4:       ff 75 0c                push   DWORD PTR [ebp+0xc]
     80483f7:       ff 75 08                push   DWORD PTR [ebp+0x8]
     80483fa:       e8 dc ff ff ff          call   80483db <bar>
     80483ff:       83 c4 08                add    esp,0x8
     8048402:       c9                      leave
     8048403:       c3                      ret
    
    08048404 <main>:
     8048404:       55                      push   ebp
     8048405:       89 e5                   mov    ebp,esp
     8048407:       6a 03                   push   0x3
     8048409:       6a 02                   push   0x2
     804840b:       e8 e1 ff ff ff          call   80483f1 <foo>
     8048410:       83 c4 08                add    esp,0x8
     8048413:       b8 00 00 00 00          mov    eax,0x0
     8048418:       c9                      leave
     8048419:       c3                      ret
     804841a:       66 90                   xchg   ax,ax
     804841c:       66 90                   xchg   ax,ax
     804841e:       66 90                   xchg   ax,ax
    

    函数有几个关键点调用函数、参数传递、返回值、调用后会返回计息执行下面的指令

    其中参数和返回地址都是通过栈来实现的。平衡栈的动作根据不同的调用约定来实现的。C编译器符合

    参数从右到左入栈

    int main (void){
        foo(2,3);
        return 0;
    }
    main函数调用foo函数(2,3)作为参数被传递
    8048407:       6a 03                   push   0x3
    8048409:       6a 02                   push   0x2
    804840b:       e8 e1 ff ff ff          call   80483f1 <foo>
    8048410:       83 c4 08                add    esp,0x8
    先将3入栈,再将2入栈
    call foo 函数(跳转到80483f1 <foo>执行)
    call指令
    call首先将它的下一条指令入栈(也就是8048410地址)将它调用的函数地址(foo函数地址复制到EIP寄存器当中)
    下条指令CPU会执行EIP中地址,现在进入foo函数当中
    080483f1 <foo>:
     80483f1:       55                      push   ebp
     80483f2:       89 e5                   mov    ebp,esp
     80483f4:       ff 75 0c                push   DWORD PTR [ebp+0xc]
     80483f7:       ff 75 08                push   DWORD PTR [ebp+0x8]
     80483fa:       e8 dc ff ff ff          call   80483db <bar>
     80483ff:       83 c4 08                add    esp,0x8
     8048402:       c9                      leave
     8048403:       c3                      ret
     foo调用了bar进入bar
     int bar(int c , int d){
        int e = c +d;
        return e;
    }
    
    int foo (int a , int b){
        return bar(a,b);
    }
    ================================================================================
     080483db <bar>:
     80483db:       55                      push   ebp
     80483dc:       89 e5                   mov    ebp,esp
     80483de:       83 ec 10                sub    esp,0x10
     80483e1:       8b 55 08                mov    edx,DWORD PTR [ebp+0x8]
     80483e4:       8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
     80483e7:       01 d0                   add    eax,edx
     80483e9:       89 45 fc                mov    DWORD PTR [ebp-0x4],eax
     80483ec:       8b 45 fc                mov    eax,DWORD PTR [ebp-0x4]
     80483ef:       c9                      leave
     80483f0:       c3                      ret
     其中
     80483f1:       55                      push   ebp;保存ebp现场
     80483f2:       89 e5                   mov    ebp,esp;将esp的值赋给ebp现在是参数、参数、返回地址、ebp现场。
     ebp是用来取调用者传过来的参数的也可以用来引用局部变量(在栈上分配)。为啥呢?因为esp总是指向栈顶,刚进入被调用函数的时候将esp赋值给ebp这个时候好找前面压过栈的参数。编译器好实现。
     EBP:高级语言通过 EBP 来引用堆栈中的函数参数和局部变量。除了高级编程,它不用于一般算术运算和数据传输。
     取参数
     80483e1:       8b 55 08                mov    edx,DWORD PTR [ebp+0x8]
     80483e4:       8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]
     所有函数都是通过eax来返回值的
     80483ec:       8b 45 fc                mov    eax,DWORD PTR [ebp-0x4]
     leave是下面函数开始的时候的逆操作重新将ebp赋值给esp,然后pop ebp;ebp又恢复到维护foo函数的了,前面的数据还在栈上但是我已经不维护了,没有意义了。
     80483db:       55                      push   ebp
     80483dc:       89 e5                   mov    ebp,esp
     ret指令是call指令的逆操作,pop现在的esp的保存的数据给EIP(也就是foo函数调用bar函数前call保存的地址),然后esp值-4
     其中EBP总是指向当前栈帧的栈底、返回值通过EAX传递。
    

    在逆向中将重点放在函数的识别和参数的传递上是节省体力的方法,函数是一个程序模块,程序就是由这样一个模块一个模块组成的。

  • 相关阅读:
    sitemap.xml生成方法(asp和php)(转)
    浏览器缓存机制(转)
    JavaScript在IE浏览器和Firefox浏览器中的差异总结(转)
    JavaScript的数组及其操作
    Google Maps和GIS开发资源收集
    js 字符串转换成数字(转)
    关于构造函数
    C#类型转化
    .net framework
    C#变量
  • 原文地址:https://www.cnblogs.com/wan-xiang/p/11733318.html
Copyright © 2011-2022 走看看