精华内容
下载资源
问答
  • 《Linux C 编程站式学习》18,19章练习。 平台:x86/Debian GNU/Linux gcc 1 C源文件代码对应的指令 计算机是由数字电路组成的运算机器,只能对数字做...对可执行文件进行反汇编可以看到C代码中的每语句所对应的

    《Linux C 编程一站式学习》第18,19章练习。

    平台:x86/Debian GNU/Linux gcc


    1 C源文件代码对应的指令

    计算机是由数字电路组成的运算机器,只能对数字做运算。加载到内存中运行的文件被称之为可执行文件,可执行文件中的二进制对应着C源代码的标识符和数据。由一个C源文件到可执行文件可分为两个阶段:编译和链接。对可执行文件进行反汇编可以看到C代码中的每个语句所对应的机器指令bytes(left)及反汇编代码(right)。如以下C语言程序可用gcc编译器来描述其生成可执行文件的过程:

    /* Filename:	c_to_elf.c
     * Brife:	To see c source file to be elf file by compiling and link
     * Date:	2014.7.20 - Sunday
     * Author:	One fish
     */
    #include <stdio.h>
    
    
    //------Global varible-----------
    static int i;
    
    
    //------Functions decaration
    int add_ij(int i, int j);
    
    
    //---Main the entry of this application
    int main(void)
    {
    	int j, k = 1;
    	
    	i	= k;
    	j	= 2;
    	add_ij(i, j);
    
    	return 0;
    }
    
    
    int add_ij(int i, int j)
    {
    	int k;
    
    	k	= i + j;
    	return k;
    }
    


    (1) gcc命令选项

    Figure1.gcc 命令选项
    图中的各个名字是gcc默认生成的(不用-o选项让生成文件以其它名字生成)。以.s为后缀的为C源文件对应的汇编文件;以.o为后缀的为C源文件对应的目标文件;.outC源文件对应的可执行文件。


    (2) 目标文件

    选择由C源文件汇编文件得到目标文件:

    gcc  -g  -S c_to_elf.c [生成c_to_elf.s,是c_to_elf.c对应的汇编代码]

    gcc  -g  -c c_to_elf.s[生成c_to_elf.o,即为目标文件]

    -g选项是使生成的文件能够关联上C源代码。


    (3) 反汇编--可执行文件

    选择由(2)中生成的目标文件得到可执行文件c_to_elf:gcc -g  c_to_elf.o  -o c_to_elf。目标文件也可以进行反汇编。

    用objdump命令可对可执行文件进行反汇编: objdump –dS c_to_elf > exe_disassembly.txt 。对c_to_elf的反汇编信息都在exe_disassembly.txt文件中,只看C代码对应指令部分[第一列为指令地址,中间的几列为机器指令,最后的是汇编代码]:
    080483dc <main>:
    int add_ij(int i, int j);
    
    
    //---Main the entry of this application
    int main(void)
    {
     80483dc:	55                   	push   %ebp
     80483dd:	89 e5                	mov    %esp,%ebp
     80483df:	83 e4 f0             	and    $0xfffffff0,%esp
     80483e2:	83 ec 20             	sub    $0x20,%esp
    	int j, k = 1;
     80483e5:	c7 44 24 1c 01 00 00 	movl   $0x1,0x1c(%esp)
     80483ec:	00 
    	
    	i	= k;
     80483ed:	8b 44 24 1c          	mov    0x1c(%esp),%eax
     80483f1:	a3 84 96 04 08       	mov    %eax,0x8049684
    	j	= 2;
     80483f6:	c7 44 24 18 02 00 00 	movl   $0x2,0x18(%esp)
     80483fd:	00 
    	add_ij(i, j);
     80483fe:	a1 84 96 04 08       	mov    0x8049684,%eax
     8048403:	8b 54 24 18          	mov    0x18(%esp),%edx
     8048407:	89 54 24 04          	mov    %edx,0x4(%esp)
     804840b:	89 04 24             	mov    %eax,(%esp)
     804840e:	e8 07 00 00 00       	call   804841a <add_ij>
    
    	return 0;
     8048413:	b8 00 00 00 00       	mov    $0x0,%eax
    }
     8048418:	c9                   	leave  
     8048419:	c3                   	ret    
    
    0804841a <add_ij>:
    
    
    int add_ij(int i, int j)
    {
     804841a:	55                   	push   %ebp
     804841b:	89 e5                	mov    %esp,%ebp
     804841d:	83 ec 10             	sub    $0x10,%esp
    	int k;
    
    	k	= i + j;
     8048420:	8b 45 0c             	mov    0xc(%ebp),%eax
     8048423:	8b 55 08             	mov    0x8(%ebp),%edx
     8048426:	01 d0                	add    %edx,%eax
     8048428:	89 45 fc             	mov    %eax,-0x4(%ebp)
    	return k;
     804842b:	8b 45 fc             	mov    -0x4(%ebp),%eax
    }
     804842e:	c9                   	leave  
     804842f:	c3                   	ret   

    (4) 由反汇编分析程序运行时堆栈内存的变化

    虽然程序中的内存地址都是虚拟地址,但可根据虚拟内存与物理内存的映射关系用虚拟内存地址来模拟堆栈内存上物理地址的变化


    [1]进入main函数main栈帧的开始

    Figure2.程序进入main函数运行
    esp寄存器指向栈底,ebp寄存器指向栈顶。进入main函数时假设esp指向栈内存的内容为……。然后栈内存会随着接下来的指令而得到分配。

    [2]main函数内的局部变量的栈内存

    Figure3.main函数局部变量栈内存
    用栈内存地址esp + 0x1c 和 esp + 0x18来存储k和j(这个关系会被记住,当程序中用到k或j时,关联的就是这两个地址或者地址中的内容)。

    [3] main函数栈帧的形成

    Figure4.main函数栈帧的形成
    到main函数的return语句处就标志着main函数栈帧形成。调用子函数给子函数传参数是将参数的值压入(复制了参数)本函数栈中(这个地址会被记住,进入子函数后到这个地址来取值)。 全局变量i的地址是0x8049684这个地址是在程序链接时被分配的

    [4] 子函数add_ij()栈帧的分配与回收

    Figure5.add_ij子函数栈帧分配及回收
    进入子函数add_ij后,为add_ij及其内部的变量分配栈内存形成add_ij的函数栈帧。当退出add_ij函数执行完毕后,add_ij函数栈帧被操作系统回收。依据对ebp和esp的操作,此时会返回到调用子函数add_ij的函数中,去继续执行调用函数的下一个语句。

    [5]main函数栈帧的回收


    Figure6.main函数栈帧的回收

    main()是一个具入口性质的函数(首先被调用),当main函数执行完毕后。它的函数栈帧以相同的方式被回收,ebp与esp会返回到到上一层栈帧(如果有)。


    对可执行文件进行的反汇编中可以看出,可执行文件中的有的地址(如全局变量i)已经被分配,可程序还没有运行,无法保证这个地址的可用性。其实这个地址是虚拟地址,可执行程序被加载到内存中运行时,操作系统会检查内存中的页表看这个虚拟地址可以映射到物理地址中的哪一个地址,这个地址才是变量真正的地址。MMU的存在可以解决链接时为程序分配的地址是否可用问题。

    2 编译----C源文件到目标文件

    编译是指将C代码翻译成汇编或机器指令的过程。


    (1) C程序对应的汇编代码

    C源文件可被gcc编译为汇编文件。即此笔记前提到的c_to_elf.s文件,摘main和add_ij()函数对应的汇编代码如下:


    Figure7.main和add_ij()对应的汇编代码

    (2) C程序的目标文件

    笔记前提到的c_to_elf.o为c_to_elf.c对应的目标文件,在linux下用readelf –a  c_to_elf.o  > obj.txt命令将目标文件中的内容读到obj.txt文件中,截取一部分出来瞧瞧:


    [1] ELF Header

    Figure8.目标文件中的ELF Header

    从ELF Header中可以看出,计算机内的数字采用的2’s complement方式,小端方式存储。操作系统为UNIX,文件本身类型为REL,文件中段头(section headers)的文件起始地址为1264,一共有21个段头。

    [2] Section headers

    截图看以下section headers的信息:

    Figure9.Section headers
    与ELF Header描述相对应,一共有0 – 20个section header,除了与汇编文件中对应的.text、.data、.bss段(section)之外,其它的都是编译器自动添加的。 Addr 是这些段加载到内存中的地址,加载地址要在链接时设定(设定的虚拟地址),所以这里全是 0。Off和size列支出了各段(section)的起始文件地址和长度。 C 源文件中的全局变量 static int i ;变量被存在了 .bss section (还没有内存地址)。局部变量要在运行到局部变量处时方为其分配空间

    3 链接----C源文件到可执行文件

    链接主要有两个作用,一是修改目标文件中的信息,对地址做重定位;二是把多个目标文件合并成一个可执行文件。目标文件需要经过链接才可以成为可执行文件,才能被操作系统加载到内存中运行。可执行文件是指前笔记中生成的c_to_elf。

    [1] ELF Header

    Figure10.可执行文件的ELF Header
    在可执行文件中,文件类型变为EXEC,Entry point address为_start符号的地址。同时,program headers也诞生了,section headers的数目也发生了变化。

    [2] Section Headers

    截取一部分如下图:

    Figure11.可执行文件中的section headers
    可执行文件是由目标文件经过链接而来的,为各个段都分配了虚拟地址。原来的.text、.data、.bss段都被分配了虚拟地址。笔记前面特别关注了全局变量i的虚拟地址为0x8049684,这里的.bss段的虚拟地址为0x8049680,如果全局静态变量位于.bss段的话,为什么相差4个字节同求解释。在可执行文件中找到了i的信息:

    Figure12.全局变量i的信息
    从此表中可以看出i的地址为0x8049684。

    [3] Program Headers

    Program Headers用来描述Segment的信息。Segment由多个Section组成。一般是将具有共同属性如.data和.bss汇聚为一个Segement加入到内存。个人理解目标文件以Section的形式存在,可执行文件以Segement的形式存在以方便加载到内存中运行。


    4 小结

    一个C源文件经过编译和链接可形成可执行文件。编译的过程C源码翻译成机器指令或汇编代码。对目标文件进行反汇编可以看到,程序中地址如函数的地址是用的相对地址。经过链接的目标文件为程序分配了虚拟地址,程序中使用的是绝对地址(反汇编查看)


    虚拟内存可解决链接时为可执行文件加载到内存中的地址冲突问题。如果直接使用物理地址,怎么敢保证链接时为程序分配的地址没有被用到。而有了MMU后,跟程序有关的地址都是虚拟地址,操作系统会根据内存中的页表将程序加载到可用的内存中去。


    《Linux C 编程一站式学习》P.299:程序的函数调用规则(1中的函数栈帧)并不是体系结构所强加的,ebp寄存器并不是必须这么用,函数的参数和返回值也不是必须这么传,只是操作系统和编译器选择了以这样的方式实现C代码中的函数调用,这称为Calling Convention,Calling Convention是操作系统二进制接口规范。

    CNote Over.
    展开全文
  • 详解main函数反汇编代码(超级详细)

    千次阅读 2020-12-02 13:52:16
    lea 0x4(%esp),%ecx 该指令的作用是,取出esp寄存器里的值,加上4,不再继续寻址,而是将得到...EBP存储着当前函数栈底的地址,栈低通常作为基址,我们可以通过栈底地址和偏移相加减来获取变量地址(很重要)。 push .

    一、前言
    为了弄清楚**缓冲区溢出攻击**,先花大篇幅讲清楚main函数的反汇编代码是有必要的(见二、main函数的反汇编代码解析)。
    二、main函数的反汇编代码解析
    1.main函数的源代码
    在这里插入图片描述
    2.main函数的反汇编代码
    在这里插入图片描述
    (1)前三行
    ①lea 0x4(%esp),%ecx

    解析:
    1)实现的功能:esp寄存器中的值(存的是地址,指向的是栈顶)+4,存入寄存器ecx。
    程序计数器(pc) : 0x8048484bb, 即将要执行main函数
    在这里插入图片描述
    此时esp, ecx的值如下:
    在这里插入图片描述
    2)为啥要把esp+4后存入ecx?
    main函数是由一个_start函数调用执行的。
    此时esp指向的栈顶,内容属于_start函数,为了在调用并执行完main函数后回到_start函数继续执行,所以需要先保存一下esp。
    那么直接保存不就好了,为啥要esp+4呢?
    目前这点没找到有说服力的解释,我谈几点我的猜想:
    因为下一条汇编指令会改变esp的值,所以保存esp+a(之所以是+,是因为栈底是高地址,栈顶是低地址),a取多少呢?由于是32位架构的,即4个Byte,故esp+4。
    我们来看看esp指向的栈顶,内容是啥。
    在这里插入图片描述
    确实是一条指令,猜测是_start函数的,但还未执行,就转去执行main函数了。故main函数执行完,需要返回到这条指令继续执行。

    ②and $0xfffffff0,%esp

    解析:
    执行该指令之前,esp的值为0xbffff0ac, 没有与16字节对齐。
    未对齐的栈调用函数的后果是速度非常慢,因为16字节是x86上的缓存线宽。
    执行后,esp的情况如下:
    在这里插入图片描述

    ③pushl -0x4(%ecx)

    解析:
    pushl表示双字(32位)压栈, 也即把ecx-4后压栈。
    ecx-4的值即在未执行main函数之前,esp的值,如下所示:
    在这里插入图片描述
    当时_start函数的esp执行了这条指令,但是没有执行便调用执行main函数了,之后要返回这条指令进行执行_start函数。
    x/i 反汇编

    总结
    综合指令①~③即保存了_start函数的返回地址,又实现了16字节对齐(为了效率)。

    (2)剩余汇编代码解析
    在这里插入图片描述
    1)先讲个“套路”:
    函数调用(main函数也是被调用),汇编代码中,首先要做的工作如下:
    ①保存调用者的ebp(下文介绍功能);(push %ebp)
    在这里插入图片描述
    调用者_start函数的ebp一开始为0(挺奇怪的);

    ②将被调用者的esp存储到ebp;(mov %esp,%ebp)

    EBP存储着当前函数栈底的地址,栈低通常作为基址,我们可以通过栈底地址和偏移相加减来获取变量地址(很重要)。

    在这里插入图片描述
    从esp起,栈的内容属于main函数
    在这里插入图片描述
    ebp存的就是main函数栈底的地址。

    2)存疑点
    ①push %ecx
    为啥要保存ecx的内容?
    _start函数的返回地址已经通过“pushl -0x4(%ecx)”存到栈中了啊。ecx的内容已经没啥意义了。
    而且调用的foo01函数,就没有push %ecx。

    3)⑥给了进一步解释

    ②sub $0x4,%esp
    在调用函数之前要传入参数到栈中,规则是从右往左
    可foo01函数,并不需要传参啊,为啥要分配4个字节呢?
    在执行这条语句之前,esp的值为0xbffff094!!!赶紧回忆上文提到的16字节对齐

    我猜测:因为接下来要调用foo01函数,为了使其栈对齐,而进行了sub $0x4,%esp。

    执行该指令后,esp确实是16字节对齐的。
    在这里插入图片描述
    (3)继续解析剩余汇编代码
    ①call 0x804840b <foo01>

    调用foo01函数

    ②mov $0x0,%eax

    清零操作。在windows中,函数返回值都是放在eax中然后返回,外部从eax中得到返回值。这就代表return 0操作。

    ③add $0x4,%esp

    调用完foo01函数了,不需要考虑其栈对齐了,对应于sub $0x4,%esp

    ④pop %ecx

    对应与push %ecx

    ⑤pop %ebp

    对应于push %ebp

    ⑥lea -0x4(%ecx),%esp

    猜测 : 并不是通过pushl -0x4(%ecx)来返回的
    所以需要lea -0x4(%ecx),%esp的方式得到返回地址。

    ⑦ret

    把esp指向的栈中的数值赋给eip(程序计数器),回到_start函数开始执行。
    在这里插入图片描述
    结合上文,不是00000025,而是0xbffff09c。

    三、缓冲区溢出攻击
    再次强调,esp存的是内存地址,即指向栈顶。
    下一篇博客介绍的**缓冲区溢出攻击**,即esp存的内存地址没变,但该地址指向的内容从返回地址变成了攻击者函数的入口地址。那么执行ret指令后,eip中就是攻击者函数的入口地址了。

    四、参考文献
    1.Understanding the purpose of some assembly statements
    2.ret指令的原图

    展开全文
  • 一个文件从源代码到可执行程序会经历以下4步骤: 预处理:在程序运行(main函数执行)之前,修改源码,主要处理代码中的#include头文件和#define宏定义代码(将程序运行时用到的#include头文件中的代码和#define宏...

    一、程序编译原理

    • 一个文件从源代码到可执行程序会经历以下4个步骤:
      • 预处理:在程序运行(main函数执行)之前,修改源码,主要处理代码中的#include头文件和#define宏定义代码(将程序运行时用到的#include头文件中的代码和#define宏定义的代码进行替换),最后生成一个.i文件(.i文件里面是替换代码之后的代码文件)
      • 编译:此阶段会检查代码的规范性、是否有语法错误等。在检查无误后,把.i代码文件进行编译,然后生成一个汇编语言.s文件(.s文件里面都是汇编语言)。此处只进行编译生成汇编代码,而不真正的进行汇编
      • 汇编:此阶段把.s文件翻译成二进制机器指令.o文件。生成的.o文件是二进制文件(直接用文本工具打开看到的将是乱码,我们需要反汇编工具如GDB的帮助才能读懂它),Windows下为.obj文件
      • 链接:此阶段会链接所有的函数、全局变量,将所有的.o文件链接成一个可执行文件(例如hello.c文件调用了printf函数,printf函数存在一个名为printf.o的文件中,而我们必须把printf.o合并到hello.o中。不过有时.o文件太多,链接会很不方便,所以我们会给.o文件进行打包生成静/动态库文件(Windows下为.lib和.dll文件,Linux下为.a和.so文件)

    • 注意事项:
      • 1.在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但仍可以生成Object File。但是链接时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码
      • 2.一个.c文件只生成一个.i和.s和.o文件,链接时是将所有的.o文件一起链接
      • 3.h文件不直接参与源码编译,.cpp/.c等参与源码编译
      • 4.承上,因为.h文件不参与源码编译,所以在.h文件中不要写带内存的代码
    • 各种后缀名文件的意义:
      • .c:C语言源代码文件
      • .h:程序所包含的头文件
      • .i :C语言源代码文件经过预处理生成的文件
      • .s:.i文件经过编译生成的汇编文件(文件中都是汇编语言)
      • .o:.s文件经过汇编生成的二进制机器执行文件
      • .S:是经过预编译的汇编语言源代码文件

    二、演示案例

    第一步(预处理):

    • 现在我们有一个源代码文件hello.c

    #include <stdio.h>
    
    #define NUM 10
    
    int main()
    {
        printf("num is %d\n",NUM);
    }
    • 现在我们使用gcc的-E选项将一个.c源文件编译成一个.i文件
    gcc -E -o hello.i hello.c

    • 之后查看.i文件的内容,我们知道预处理会将源代码中用到的头文件代码和宏进行替换,此程序中使用到了stdio.h头文件和一个NUM宏,因此会将stdio.h头文件中的代码都包含进来了(可以看到代码变成了八百多行),并且将宏替换为实际的数字(下面也替换了)

    第二步(编译):

    • 现在我们使用gcc的-S选项,将.i文件编译成一个.s文件
    gcc -S -o hello.s hello.i

    • 接着查看.s文件的内容:可以看到编译阶段会将.i文件中的源代码都替换为汇编代码(此处只进行编译生成汇编代码,而不真正的进行汇编)

    第三步(汇编):

    • 使用gcc的-c选项将.s文件汇编为一个.o文件
    gcc -c -o hello.o hello.s

    • 之后查看.o文件的内容:.o文件时二进制文件,因此用普通文本软件打开查看都是乱码

    第四步(链接):

    • 使用gcc的-o选项将.o文件链接为可执行程序
    gcc -o hello hello.o

    • 这个程序就是我们最终可以执行的程序,我们尝试运行这个程序,结果显示运行成功

    展开全文
  • Linux下C程序反汇编

    万次阅读 多人点赞 2015-12-08 21:07:22
    Linux下C程序反汇编前言:本文主要介绍几种反汇编的方法。gccgcc的完整编译过程大致为:预处理->编译->汇编->链接前三步骤分别对应了-E、-S、-c三选项。今天我要介绍的第一种方法就是使用-S这选项。源程序...

    Linux下C程序的反汇编

    前言:本文主要介绍几种反汇编的方法。

    gcc

    gcc的完整编译过程大致为:预处理->编译->汇编->链接

    前三个步骤分别对应了-E、-S、-c三个选项。

    今天我要介绍的第一种方法就是使用-S这个选项。

    源程序main.c:

    /*************************************************************************
        > File Name: main.c
        > Author: AnSwEr
        > Mail: 1045837697@qq.com
        > Created Time: 2015年12月08日 星期二 20时06分19秒
     ************************************************************************/
    
    #include<stdio.h>
    int i = 1;
    int main(void)
    {
        ++i;
        printf("%d\n",i);
        return 0;
    }

    执行以下命令:

    gcc -S -o main.s main.c

    查看汇编源程序main.s:

        .file   "main.c"
        .globl  i
        .data
        .align 4
        .type   i, @object
        .size   i, 4
    i:
        .long   1
        .section    .rodata
    .LC0:
        .string "%d\n"
        .text
        .globl  main
        .type   main, @function
    main:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    i(%rip), %eax
        addl    $1, %eax
        movl    %eax, i(%rip)
        movl    i(%rip), %eax
        movl    %eax, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
        .section    .note.GNU-stack,"",@progbits

    哈哈,大家看是不是成功了?至于汇编程序的具体解释则不在本文的讨论范畴。

    最后介绍一下gcc的具体过程:
    参考: https://github.com/1184893257/simplelinux/blob/master/gcc.md#top

    编译阶段命令截断后的产物
    C源程序
    预处理gcc -E替换了宏的C源程序(没有了#define,#include…), 删除了注释
    编译gcc -S汇编源程序
    汇编gcc -c目标文件,二进制文件, 允许有不在此文件中的外部变量、函数
    链接gcc可执行程序,一般由多个目标文件或库链接而成, 二进制文件,所有变量、函数都必须找得到

    objdump

    objdump是linux下一款反汇编工具,能够反汇编目标文件、可执行文件。

    主要选项:

    objdump -f 
    显示文件头信息
    
    objdump -d 
    反汇编需要执行指令的那些section
    
    objdump -D-d类似,但反汇编中的所有section
    
    objdump -h 
    显示Section Header信息
    
    objdump -x 
    显示全部Header信息
    
    objdump -s 
    将所有段的内容以十六进制的方式打印出来

    目标文件

    反汇编:

    gcc -c -o main.o main.c
    objdump -s -d main.o > main.o.txt

    查看汇编文件:

    
    main.o:     文件格式 elf64-x86-64
    
    Contents of section .text:
     0000 554889e5 8b050000 000083c0 01890500  UH..............
     0010 0000008b 05000000 0089c6bf 00000000  ................
     0020 b8000000 00e80000 0000b800 0000005d  ...............]
     0030 c3                                   .               
    Contents of section .data:
     0000 01000000                             ....            
    Contents of section .rodata:
     0000 25640a00                             %d..            
    Contents of section .comment:
     0000 00474343 3a202855 62756e74 7520342e  .GCC: (Ubuntu 4.
     0010 382e322d 31397562 756e7475 31292034  8.2-19ubuntu1) 4
     0020 2e382e32 00                          .8.2.           
    Contents of section .eh_frame:
     0000 14000000 00000000 017a5200 01781001  .........zR..x..
     0010 1b0c0708 90010000 1c000000 1c000000  ................
     0020 00000000 31000000 00410e10 8602430d  ....1....A....C.
     0030 066c0c07 08000000                    .l......        
    
    Disassembly of section .text:
    
    0000000000000000 <main>:
       0:   55                      push   %rbp
       1:   48 89 e5                mov    %rsp,%rbp
       4:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # a <main+0xa>
       a:   83 c0 01                add    $0x1,%eax
       d:   89 05 00 00 00 00       mov    %eax,0x0(%rip)        # 13 <main+0x13>
      13:   8b 05 00 00 00 00       mov    0x0(%rip),%eax        # 19 <main+0x19>
      19:   89 c6                   mov    %eax,%esi
      1b:   bf 00 00 00 00          mov    $0x0,%edi
      20:   b8 00 00 00 00          mov    $0x0,%eax
      25:   e8 00 00 00 00          callq  2a <main+0x2a>
      2a:   b8 00 00 00 00          mov    $0x0,%eax
      2f:   5d                      pop    %rbp
      30:   c3                      retq   

    可执行文件

    反汇编:

    gcc -o main main.c
    objdump -s -d main > main.txt

    查看汇编文件(由于文件较大,只取部分展示):

    Disassembly of section .init:
    
    00000000004003e0 <_init>:
      4003e0:   48 83 ec 08             sub    $0x8,%rsp
      4003e4:   48 8b 05 0d 0c 20 00    mov    0x200c0d(%rip),%rax        # 600ff8 <_DYNAMIC+0x1d0>
      4003eb:   48 85 c0                test   %rax,%rax
      4003ee:   74 05                   je     4003f5 <_init+0x15>
      4003f0:   e8 3b 00 00 00          callq  400430 <__gmon_start__@plt>
      4003f5:   48 83 c4 08             add    $0x8,%rsp
      4003f9:   c3                      retq   
    
    Disassembly of section .plt:
    
    0000000000400400 <printf@plt-0x10>:
      400400:   ff 35 02 0c 20 00       pushq  0x200c02(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
      400406:   ff 25 04 0c 20 00       jmpq   *0x200c04(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
      40040c:   0f 1f 40 00             nopl   0x0(%rax)
    
    0000000000400410 <printf@plt>:
      400410:   ff 25 02 0c 20 00       jmpq   *0x200c02(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
      400416:   68 00 00 00 00          pushq  $0x0
      40041b:   e9 e0 ff ff ff          jmpq   400400 <_init+0x20>

    linux 下目标文件(默认扩展名是.o)和可执行文件都是 ELF 格式(文件内容按照一定格式进行组织)的二进制文件; 类似的,Windows 下 VISUAL C++ 编译出来的目标文件 (扩展名是.obj)采用 COFF 格式,而可执行文件 (扩展名是.exe)采用 PE 格式, ELF 和 PE 都是从 COFF 发展而来的。

    因为 linux 下目标文件和可执行文件的内容格式是一样的, 所以 objdump 既可以反汇编可执行文件也可以反汇编目标文件。

    总结

    掌握了反汇编的方法,当你的程序遇到一些未知的变量错误等,可以直接反汇编来查看汇编代码,一切一目了然。PS:汇编我已经忘得差不多了。

    参考

    1. https://github.com/1184893257/simplelinux

    反馈与建议

    展开全文
  • 反汇编算法的局限性反汇编软件在拿到堆机器码时,采用什么样的思维和算法来“断词断句”,又基于哪些假设,都会决定最终的解析结果。运用不同的反汇编器,同样的字节码会被“翻译”出完全不同的指令序列。而...
  • Linux下反汇编指定的函数

    千次阅读 2014-11-20 21:38:07
    在debug二进制程序的时候,难免会用到
  • 1. 如何进行反汇编 在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息。如下图所示。 记得中断程序的运行,不然看不到反汇编的指令 看一个简单的程序及其生成的汇编指令 #...
  • 反汇编简介

    2020-06-02 11:20:01
    什么是反汇编 在传统软件开发模型中,
  • 在Linux下运行你的第一个汇编程序

    万次阅读 2020-02-21 12:40:34
    在Linux下运行你的第一个汇编程序 汇编语言对于大多数程序员来说都是进而远之的,原因当然是汇编语言晦涩难懂,各种指令搞得人头疼,不过汇编语言适当了解一些还是蛮有意思的,今天带大家在Linux上运行第一个汇编...
  • 反汇编代码分析--函数调用

    千次阅读 2014-07-21 17:02:59
    分类: VC Linux 2010-12-01 14:16 1681人阅读 评论(2) 收藏 举报 ...C++反汇编代码分析--函数调用 代码如下:  #include "stdlib.h"  int sum(int a,int b,int m,int n)  {  retu
  • static函数作用 这篇文章总结的十分到位,学习到了。https://blog.csdn.net/guotianqing/article/details/79828100 将 hello.c 用gcc命令编译成可重定位的目标文件,并对其中的内容解读。 #include<stdio.h>...
  • ida反汇编窗口如何设置函数

    千次阅读 2018-02-02 12:01:47
    第一函数注释:一般选用重复注释,可以在调用该函数处,方便看到关于该函数的注释。 第二行函数属性:在编辑函数对话框中修改,这属性的额意思是:不返回调用方、基于ebp栈帧。修改如下图: 第三行函数...
  • 汇编语言:将系列与处理器相关的汇编指令用某种语法和结构组织在一起的程序语言形式 用特定汇编语法规范编写的汇编代码,被完整地编译或嵌入其他高级语言 Android 中的 ARM 汇编使用 GNU 汇编格式,现在开始学习...
  • 因近期工作需要,需要利用objdump工具剖析程序指定可执行程序,以检查错误函数(语句)。 objdump命令参考:https://blog.csdn.net/zoomdy/article/details/50563680 本文以最简单的程序开始,剖析反汇编之后的...
  • 本文主要讲解动态库函数的地址是如何在...地址的设置就涉及到了PLT,Procedure Linkage Table,它包含了一些代码以调用库函数,它可以被理解成系列的小函数,这些小函数的数量其实就是库函数的被使用到的函数的数量
  • 本篇文章来弄明白一问题:在C/C++程序被加载到内存中准备运行时,main函数第一个执行函数么?答案肯定不是!如果是,就没必要去写这文章了!!! 1、_start()函数 先说结果:_start() 是第一个被...
  • 浅析VS2010反汇编

    万次阅读 2015-07-25 21:53:11
    第一1. 如何进行反汇编在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息。如下图所示。记得中断程序的运行,不然看不到反汇编的指令看一简单的程序及其生成的汇编指令#include #include...
  • IDA栈帧分析与反汇编

    2020-04-10 13:02:32
    编译器的第一个任务是,计算出函数的局部变量所需的空间。编译器的第二任务,则是确定这些变量是否在CPU寄存器中分配,或者它们是否必须在程序栈上分配。 至于具体的分配方式,既与函数的调用方无关,也与被调用...
  • 它可以直接反汇编出二进制文件的汇编代码,是目前软件逆向与安全分析领域最好用、最强大的一个静态反汇编软件,已成为众多软件安全分析人员不缺少的利器!它支持Windows、Linux等多平台,支持Intel X84、X64、...
  • 实验要求:使用gdb调试器和objdump来反汇编炸弹的可执行文件,并单步跟踪调试每阶段的机器代码,从中理解每汇编语言代码的行为或作用,进而设法“推断”出拆除炸弹所需的目标字符串。 实验语言:c。 实验环境:...
  • IDA Pro 权威指南——读书笔记(第一章:反汇编简介)本章简介1.反汇编理论2.何为反汇编3.为何反汇编 本章简介 反汇编简介作为本书的第一章,介绍了IDA诞生的主要目的和其中遇到的一些困难、IDA如何解决这些困难 ,...
  • 不知的反汇编相关知识

    千次阅读 2016-08-16 23:59:58
    编程语言相关我们都知道编程语言有好几代,那他们都是什么第一代语言最低级的语言,一般有0和1组成,人很难讲指令和数据区分开也称机器语言,字节码,二进制...他们通常不依赖任何平台,如:C,Java什么是反汇编传统软
  • 汇编函数调用

    千次阅读 2019-07-18 18:57:33
    一个程序员脑子里应该都有这么种印象:“程序是顺序执行的”。这观点其实和我们开篇所讲的cpu的流水线执行过程直接相关。 让我们再回忆一下脑海中关于函数调用的概念,也许会是这样子: 这里的“控制流转移...
  • 本文是《go调度器源代码情景分析》系列 第一章 预备知识的第6小节。 前面几节我们介绍了CPU寄存器、内存、汇编指令以及栈等基础知识,为了达到融会贯通加深理解的目的,这一节我们来综合运用一下前面所学的这些...
  • LINUX下GDB反汇编和调试

    千次阅读 2015-05-15 15:28:31
    Linux下的汇编与Windows汇编最大的不同就是第一个操作数是原操作数,第二是目的操作数,而Windows下却是相反。 1、 基本操作指令 简单的操作数类型说明,一般有三种, (1)立即数操作数,也就是常数值。立即数...
  • 今天要给大家介绍款全能型的反汇编引擎Capstone。这款引擎不仅能够跨平台,还跨多种语言,其中就有我们喜爱的Python。 我们利用Capstone也能轻松写出高大上的反汇编工具啦~~~ Capstone 能轻松反汇编多种平台的...
  • 基于arm的C++反汇编 函数的工作原理

    千次阅读 2016-05-23 19:04:14
    gdbserver 调试环境栈帧的形成和关闭栈在内存中是块特殊的存储空同, 它的存储原则是“先进后出”, 即最先被存储的数据最后被释放, 汇编过程通常使用 push 指令与 POP指令对栈空间执行数据压入和数据弹出操作。...
  • MIPS - 反汇编 - 拆炸弹 - bomb

    千次阅读 2020-02-23 22:24:48
    MIPS - 反汇编 - 拆炸弹 - bomb 前沿 整理文档发现了之前的实验报告,鉴于从17级开始才开始使用MIPS实验环境吗,取实验报告精华,整理主要思路如下。该博客叙述风格参考了窦优秀学长的博客。 该博客旨在帮助入门分析...
  • 、简单C程序的编译与执行 二、使用 GDB 进行程序基本的程序调试以及一些常用的调试指令 三、编译目标代码(.o文件) 、简单C程序的编译与执行 使用“gedit hello.c”命令在主文件夹下创建一个 hello.c ,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 31,892
精华内容 12,756
关键字:

反汇编可执行程序第一个函数是什么