分析单任务计算机操作之反汇编C程序

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

-中科大_243_石润成

本文旨在借助分析一段c语言程序反汇编代码来描述单任务计算机是如何工作的,不考虑中断等复杂操作。如有错误,希望读者能够反馈给我,不胜感激!         

1.预备阶段

本文以example.c为例,代码如下:

#include<stdio.h>
int g(int x)
{
    return x+3;
}
int f(int x)
{
    return g(x);
}
int main(void)
{
    return f(8)+1;
}

实验环境:Ubuntu10.04

工具:gccgdbmakefile

(1)编写makefile

                    

(2)make后生成预编译文件(*.cpp)、汇编文件(*.s)、目标文件(*.o)、执行文件elf文件

           

(3)example.s法看到实际的代码运行地址,本人使用gdbdisas反汇编查看.

命令: 

           # gdb example

           # disas main

           # disas f

           # disas g

main反汇编:

           

f函数反汇编:

           

g函数反汇编:

           

2.分析汇编代码

    从main入口函数开始执行,但切记在main函数并不是整个程序第一个执行的函数(详情请看点击打开链接)。

  从main函数反汇编可以看到,eip指向main函数地址0x080483d2

[以下整个内存地址由高到低展开]

#1     push %ebp                        //%ebp入栈,该ebp是调用main函数的基栈地址

         mov %esp,%ebp              //%ebp = %esp,ebp指向新函数的基栈地址,此时与esp一样指向栈底,用来保护整个函数的栈变量

                              

#2     sub $0x4,%esp                //esp = esp - 4,分配4个字节,由高地址向低地址分配

                              

#3    movl #0x8,(%esp)            //8存入esp所指的内存空间,即入栈,一般对于本函数来说就是个局部变量保存

                              

#4    call 0x80483bf <f>    等价于   push %eip                    

                                                       mov $0x80483bf,%eip 

    本机测试此时%eip为 0x080483e4,将其设为%eip_m表示当main调用f函数结束时返回main函数的下一个指(add $0x1,%eax)地址

                              

#5    push %ebp                         //同上所述,入栈保存main函数的基栈地址,此处设为exp_m

        mov %esp,%ebp               //同时ebp指向esp,ebp指向新的调用函数基栈地址,在此ebp和esp又开始维护新的函数栈空

                             

#6    sub $0x4,%esp                 //%esp = %esp - 4 [意味着申请了四个字节的空间]

                               

#7   /* %eax = %ebp + 8内存地址的值(8) */ 

       mov 0x8(%ebp),%eax     

       /* %eax入栈,即将8入栈,这里可以看到实参8传了过来,但是传给的函数f并没有直接使用原实参的8而是重新分配了一个空间保存,即所副本,函数参数传递为值传递。*/      

        mov %eax,(%esp)           


               

#8    call 0x80483b4 <g>  等价于  push %eip   

                                                      mov   $0x80483bf,%eip 

     本机测试此时%eip为 0x080483d0,将其设为%eip_f表示当f函数调用g函数结束时返回f函数的下一个指令(leave)地址

                             

#9     push %ebp                              //f函数的基栈地址入栈,此处用%ebp_f表示

      mov %esp,%ebp                     //ebp指向新的基栈地址%esp

                                       

#10   mov 0x8(%ebp),%eax            //%eax = ebp + 8 内存地址的值(即8)

         add $0x3,%eax                      //%eax = %eax +3 = 11

#11   pop %ebp                             // %ebp = %esp,esp = esp-4

        注意在pop之前,esp指向的是ebp_f即f函数的基栈地址,pop之后,ebp指向f函数的基栈地址。

                                      

#12    ret   等价于 pop %eip

         注意未ret之前,esp指向的是返回f函数的下一个指令的地址,即上述说的leave地址,ret后,eip将指向leave地址0x080483d0,此时程序会跳转到该处执行。

     此处,所申请的栈空间并没有释放掉,还有个8。

                                      

#13    leave 等价于 mov %ebp,%esp       //可以看到其实是在返回函数f将g函数的栈空间释放的

                               pop %ebp                  //ebp又恢复main函数的基站地址

                            

#14    ret   等价于 pop %eip         //eip指向返回main函数的下一个指令(add $0x1,%eax)地址eip:0x080483e4,并开始从此处执行


                                        

#15    leave  等价于 mov %ebp,%esp             // esp指向main函数的基地址

                                 pop %ebp                       //这里ebp将指向%ebp_x(调用main函数的基站地址)

                                 

                                          

3.总结

       这里简单总结一下,C语言是以函数为基本单元的,从本次实验分析来看,整个程序也是从一个函数进入到另一个函数的顺序调用,然后顺序返回,比如本次实验程序的main函数调用f函数,f函数调用g函数,g函数再反馈结果给f,f再反馈结果给main函数,然后程序结束,如下图所示。

                               

       值得注意的是,当一个函数跳转到另一个函数的时候,系统会利用寄存器来保存上下文,从本次实验中可以看到,寄存器ebp和esp一起用来保护函数的栈空间,通过esp来申请和释放栈空间,ebp来保存调用函数的基栈地址,当进行函数跳转时,会保存函数跳转处的下一条指令和基栈地址(入栈保存),这样在函数返回的时候可以根据栈的顺序来恢复调用函数的基地址,这里常用的汇编指令是leave,分析中我也提到,当函数返回到调用函数中时,会用leave指令来释放被调用函数的堆栈空间,并恢复自己的基地址,这样函数与函数之间的调用就能完好的单步执行下去,并能够进行相互传参返回,直到整个单任务程序结束。

C++反汇编 利用反汇编分析常见C/C++语句的底层实现(硬核) 解释了底层C语言的语句执行情况,在此后,我也会写很多有意义的C++反汇编的代码,帮助大家理解C/C++的底层含义。 阅读详情

相关推荐

关于fork&exec之进程的创建和可执行程序的加载过程

中科大SA***243-石润成 一、预备阶段 实验环境:Ubuntu10.04 分析内核版本:Linux-2.6.11 1.编写一个fork和exec程序 myfork.c #include #include #include int main() { pid_t pid; pid = fork(); if(0 == pid) { ex

ustc_max的专栏 3947

C++反汇编代码分析

C++反汇编代码分析--函数调用   代码如下:     #include "stdlib.h"     int sum(int a,int b,int m,int n)     {          return a+b;     }     void main()     {          int result = sum(1,2,3,4)

bcbobo21cn的专栏 1299

C程序反汇编代码分析

程序代码与反汇编过程

NorthdriftHui的专栏 1968

编译与反编译 GCC 常用指令

从源代码转变为可执行代码的过程,具体可分为 4 个过程,分别为预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)链接(Linking)

denghuajing的博客 6106

C++ 反汇编分析类的实现原理

反汇编(Disassembly) 即把目标二进制机器码转为汇编代码的过程,该技术常用于逆向工程、软件汉化等领域,学习和理解反汇编对软件调试、系统漏洞挖掘、内核原理及理解高级语言代码都有相当大的帮助,软件一切神秘的运行机制全在反汇编代码里面。下面将分析VS 2013 编译器产生C代码的格式与实现方法,研究一下编译器的编译特性。

微软技术分享 1万+

基于GCC的工具objdump实现反汇编

在 Linux中,一切皆。Linux 编程实际上是编写处理各种的代码。系统由许多类型的文件组成,但目标文件具有一种特殊的设计,提供了灵活和多样的用途。目标文件是包含带有附加地址和值的助记符号的路线图。这些符号可以用来对各种代码段和数据段进行命名,包括经过初始化的和未初始化的。它们也可以用来定位嵌入的调试信息,就像语义 Web,非常适合由程序进行阅读。objdump命令是Linux下的或者的命令,它以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。另外需要讲一下符号表,后面会用到。

ftzchina的博客 6648

逆向分析系列(二):反汇编代码

请注意,实际的反汇编代码会根据编译器、操作系统、架构以及优化级别等因素而有所不同。此外,现代的反汇编和逆向分析工具通常提供了更丰富的功能,如交叉引用、数据流分析、反编译器等,这些功能可以进一步帮助逆向工程师理解程序的逻辑和行为。逆向分析中的反汇编代码是逆向工程师分析二进制程序的关键步骤之一。反汇编是将机器语言(即二进制代码)转换回人类可读的汇编语言指令的过程。这个过程帮助逆向工程师理解程序的控制流、数据流以及它如何与内存和系统进行交互。假设我们有一个简单的C程序,它打印出“Hello, World!

2401_84824274的博客 1430

LDR指令

LDR指令的格式:  LDR{条件}   目的寄存器     作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。 LDR指令的寻址方式比较灵活,实例如下: LDR R0,[R1]

10万+

反汇编器源码剖析

之前我们有对一汇编器进行源码剖析,详见《汇编器源码剖析》,并且《实现一个汇编器》。本文,我们继续之前的工作,对反汇编器进行源码剖析,之后我们会根据反汇编器的实现原理,实现一个自己版本的反汇编器。本文剖析的反汇编器代码详见:source code。          源码中反汇编器对应的文件为sdasm.c。          sdasm.c文件中包含汇编指令集的定义op_desc,

xyjikl 2636

汇编逆向-入门

JAE;无符号大于等于则跳转JE;等于则跳转JB;无符号小于则跳转JAE;无符号大于等于则跳转JE;等于则跳转JB;无符号小于则跳转。

xinqingwuji的博客 2068

反汇编代码分析

C代码: int g(int x) {   return x + 3; }   int f(int x) {   return g(x); }   int main(void) {   return f(8) + 1; } 对应的汇编: g: pushl%ebp ;12.esp-4,[esp的指向放入ebp] movl %esp, %ebp ;

Kevin's Blogs 734

简单C反汇编分析

1、将cpu寄存器的值push到栈中2、lr是r14寄存器。

qq_52251819的博客 764

Matlab中fclose函数使用

fclose函数关闭一个或所有打开的文件。 语法 fclose(fileID) fclose('all') status = fclose(___) 说明 fclose(fileID)关闭打开的文件。 fclose('all')关闭所有打开的文件。 当关闭操作成功时,status = fclose(___)将返回status0。否则,将返回-1。您可以将此语法与前面语法中的任何输入参数结合使用。 示例 1.打开和关闭文件 打开badpoem.txt文件,读取第一行...

jk_101的博客 1万+

obj analysis2

objdump的使用方法      objdump有点象那个快速查看之流的工具,就是     以一种可阅读的格式让你更多地了解二进制文件     可能带有的附加信息。对于一般只想让自己程序     跑起来的程序员,这个命令没有更多意义,对于     想进一步了解系统的程序员,应该掌握这种工具,     至少你可以自己写写shellcode了,或者看看人家     给的exploit中的shel

wtzmax的专栏 806

反汇编代码分析--函数调用

C++反汇编代码分析--函数调用代码如下:#include "stdlib.h"int sum(int a,int b,int m,int n){ return a+b;}void main(){ int result = sum(1,2,3,4); system("pause");}  有四个参数的sum函数,接着在main方法中调用sum函数。在debug环境下,单步调试如下:11:   void main()12:   {00401060   push        ebp;保存ebp,执行这句之前,

dolphin98629的专栏 7366

gcc反汇编

gcc反汇编 x86,C语言反汇编,objdump

CX19970的博客 668

gcc编译与反汇编过程详解

文章目录简单编译过程详解1.预处理2.编译3.汇编4.链接反汇编ELF总结 简单编译 编写一个简单的小程序,取名hello.c #include<stdio.h> int main(void) { printf("hello my superhero!\n"); return 0; } 这个程序,一步到位的编译指令是:gcc hello.c -o test,实质上,编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译 (Compilation)、汇编

羚漆的博客 9044

由cve-2019-9766引出的缓冲区漏洞学习

通过工程实践引出的缓冲区溢出,缓冲区溢出 缓冲区攻击的最终目的就是希望系统能执行这块可读写内存中已经被蓄意设定好的恶意代码。 1、栈的结构 1、先进后出。 2、在内存中表现为从高地址往低地址增长。 3、栈顶:栈的最上方(低地址区)。 4、栈低:栈的最下方(高地址区)。 基本的进程地址空间分布: 2、基本栈溢出: 缓冲区溢出示意图: 如果在数据段(右边的data)就保存了一系列的指令的二进制代码...

zwish的信安之路 1760

gcc生成反汇编 linux_linux反汇编调试

反汇编有有以下几种方法:1.使用gcc -S test.c 或者gcc -S test.c>out.txt2.使用gdb调试,在调试中输入disass 函数名 就可以3.objdump -D test 一般常用1,2两种,~~~~~C语言代码example.cint triangle( int width, int height){int arr{0,1,2,3,4};int area;ar...

weixin_33960655的博客 4644
上一篇: 详解 Qt 串口通信程序全程图文
下一篇: 理解(*(void(*)())0)()和void (*signal(int, void(*)(int)))(int)
ustc_max
博客等级 码龄14年 5粉丝 13原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值