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传递。

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

逆向--C函数和汇编的更多相关文章

  1. strlen函数的汇编实现分析

    [原创][老刘谈算法001]这位运算玩的真溜—strlen函数的汇编实现分析-『密码算法』-看雪安全论坛 https://bbs.pediy.com/thread-229243.htm

  2. 【黑客免杀攻防】读书笔记14 - 面向对象逆向-虚函数、MFC逆向

    虚函数存在是为了克服类型域解决方案的缺陷,以使程序员可以在基类里声明一些能够在各个派生类里重新定义的函数. 1 识别简单的虚函数 代码示例: #include "stdafx.h" ...

  3. Linux的.a、.so和.o文件 windows下obj,lib,dll,exe的关系 动态库内存管理 动态链接库搜索顺序 符号解析和绑定 strlen函数的汇编实现分析

    Linux的.a..so和.o文件 - chlele0105的专栏 - CSDN博客 https://blog.csdn.net/chlele0105/article/details/23691147 ...

  4. 【安卓逆向】ARM常见汇编指令总结

    跳转指令 B 无条件跳转 BL 带链接的无条件跳转 BX 带状态切换的无条件跳转 BLX 带链接和状态的无条件跳转 存储器与寄存器交互数据指令(核心) 存储器:主存和内存 寄存器中放的数据:可以是字符 ...

  5. iOS 逆向之ARM汇编

    最近对iOS逆向工程很感兴趣. 目前iOS逆向的书籍有: <Hacking and Securing IOS Applications>, <iOS Hacker's Handboo ...

  6. 从linux0.11中起动部分代码看汇编调用c语言函数

    上一篇分析了c语言的函数调用栈情况,知道了c语言的函数调用机制后,我们来看一下,linux0.11中起动部分的代码是如何从汇编跳入c语言函数的.在LINUX 0.11中的head.s文件中会看到如下一 ...

  7. 从汇编看c++成员函数指针(二)

    下面先看一段c++源码: #include <cstdio> using namespace std; class X { public: virtual int get1() { ; } ...

  8. 从汇编看c++中成员函数指针(一)

    下面先来看c++的源码: #include <cstdio> using namespace std; class X { public: int get1() { ; } virtual ...

  9. C语言与汇编的嵌入式编程:main中模拟函数的调用(两数交换)

    编写一个两数交换函数swap,具体代码如下: #include<stdio.h> void swap(int *p1,int *p2) { int temp; temp = *p1; *p ...

随机推荐

  1. thinkPHP5.0中使用header跳转没作用

    我在controller中的方法中这样写: header("Location:".$url); 但是一直没动静,不会跳转,最后还是官方文档解决了 https://www.kancl ...

  2. ubuntu18.04 复制或剪切某文件夹下的前x个文件到另一个文件夹下

    该代码可以将file_path_src文件夹中的前cnt个文件,剪切或复制到file_path_tar文件夹下,前提是file_path_src中的文件名可以排序.如VOC数据集提取某个类的图片和xm ...

  3. Mac的Terminal中无法使用mvim解决方案

    对于每个人来说,都会有特别喜欢的编辑器.对于很多热爱Unix/Linux的人来说,Vim/vi肯定是很熟悉的“编辑利器”了. 当然,对于Mac用户来说,肯定也不乏对Vim狂热的人.庆幸的是,Vim对M ...

  4. BOM--location对象、history对象

    location对象 location 是最有用的BOM 对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能. 事实上,location 对象是很特别的一个对象,因为它既是win ...

  5. img标签无法显示src中名字中带有中文的图片的问题

    img: <img src="/upload/${good.photo}" style="width: 120px;height: 120px;" alt ...

  6. 105、Java中String类之利用indexOf()方法判断子字符串是否存在

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  7. 最简单的mybatis增删改查样例

    最简单的mybatis增删改查样例 Book.java package com.bookstore.app; import java.io.Serializable; public class Boo ...

  8. PHP连数据库生成数据字典

    <?php /** * 生成mysql数据字典 */ header("Content-type:text/html;charset=utf-8"); // 配置数据库 $da ...

  9. MQTT 协议学习:000-有关概念入门

    背景 从本章开始,在没有特殊说明的情况下,文章中的MQTT版本均为 3.1.1. MQTT 协议是物联网中常见的协议之一,"轻量级物联网消息推送协议",MQTT同HTTP属于第七层 ...

  10. C++ 11 :override 关键字的使用

    override 关键字 作用:在成员函数声明或定义中, override 确保该函数为虚函数并覆写来自基类的虚函数. 位置:函数调用运算符之后,函数体或纯虚函数标识 "= 0" ...