二进制分析
未读makefile介绍¶
make命令执行时,需要一个makefile文件,以告诉make命令需要怎么样的去编译和链接程序。
首先,我们用一个示例来说明makefile的书写规则,以便给大家一个感性认识。这个示例来源于gnu 的make使用手册,在这个示例中,我们的工程有8个c文件,和3个头文件,我们要写一个makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:
如果这个工程没有编译过,那么我们的所有c文件都要编译并被链接。
如果这个工程的某几个c文件被修改,那么我们只编译被修改的c文件,并链接目标程序。
如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的c文件,并链接目标程序。
只要我们的makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自动编译所需要的文件和链接目标程序。
makefile的规则¶
在讲述这个makefile之前,还是让我们先来粗略地看一看makefile的规则。
1234target ... : prerequisite ...
二进制分析
未读Makefile概述¶
什么是makefile?或许很多Windows的程序员都不知道这个东西,因为那些Windows的集成开发环境(integrated development environment,IDE)都为你做了这个工作,但我觉得要作一个好的和专业的程序员,makefile还是要懂。这就好像现在有这么多的HTML编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标签的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效 ...
二进制分析
未读写个简单的Makefile做开场白
需要说明一下,文档目录结构是用户目录HOME下有src incl bin lib。
src:源码
incl:头文件
bin:执行码
lib:静态/动态库
这是大家最常见的Linux编程目录结构,以下代码编译都是依据这个结构。
简单的Makefile代码
12345hello:hello.c gcc -I${HOME}/incl -c hello.c gcc -o hello hello.o rm -f hello.o mv hello ${HOME}/bin
没接触过Makefile的同学肯定能看出,这段代码不就是把编译、链接、删除、移动写成shell脚本执行吗?没错的,把第一行去掉,其他代码粘贴到shell脚本里同样可以编译成功,一点问题都没有。
Makefile结构说明
Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。
1、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展 ...
ELF简介
可执行与可链接格式(Executable and Linkable Format,ELF),是Linux操作系统上的默认二进制格式
ELF用于可执行文件、对象文件、共享库及核心转储。64位ELF二进制格式与32位是相似的,主要区别在于某些头部字段和其他数据结构的大小和顺序。
类型
实例
可重定位的对象文件(Relocatable file)
.o;.a;.ko
可执行的对象文件(Executable file)
vi、gdb、及我们用链接器生成的可执行文件、bash shell 程序
可被共享的对象文件(Shared object file)
.so
核心转储文件(Core Dump File)
当进程意外终止时,系统可以将该进程的地址空间的内容及终止时的一些其他信息转储到核心转储文件 core dump
64位ELF二进制文件的格式和内容:
ELF二进制文件实际上包含4种类型的组件:
ELF 头部(executable header,也称为可执行文件头)、
一系列(可选)程序 头、
多个节、
节对应的各个(可选)节头。 ...
ELF节头
ELF二进制文件中的代码和数据在逻辑上被分为连续的非重叠块,称为节(section)。节没有任何预设的结构体,相反,每个节的结构体取决于内容。实际上,节甚至可能没有任何特定的结构体。通常,节只不过是代码或者数据的非结构化blob。每个节由节头描述,节头指定了节的属性,并允许你找到节中字节的位置。二进制文件中所有节的节头都包含在节头表中。
对节进行划分为链接器的使用提供了方便,当然节也可以被其他工具解析(如静态二进制分析工具),这意味着在设置进程和虚拟内存来执行二进制文件的时候,实际上并不需要每个节所包含的数据,有些节所包含的数据在执行的时候是根本不需要的,如符号信息或者重定位信息。
由于节只为链接器提供视图,因此节头表是ELF格式的可选部分,不需要链接的ELF二进制文件不需要有节头表。如果没有节头表,则ELF头部中的e_shoff字段将设置为零。
为了在进程中加载并执行二进制文件,需要对二进制文件中的代码和数据进行不同的组织,为此ELF二进制文件指定了另一种逻辑组织, 称为段(segment),它们在执行的时候使用,与节相对,节在链接的时候使用。
节的内容的逻辑组织只在 ...
ELF头部
每个ELF二进制文件都是从ELF头部开始的,该头部是一系列结构化的字节,这些字节可以告诉你这是一个什么样的ELF二进制文件,以及在文件的什么地方查找其他内容。要找出ELF头部的格式,可以在/usr/include/elf.h或者ELF规范中查找其类型定义(以及其他与ELF相关的类型和常量的定义)。
64位ELF文件头部:
ELF头部在此以C结构体Elf64_Ehdr的形式表示。如果你在/usr/include/elf.h中查找该结构体的定义,你可能会注意到给出的结构体定义包含诸如Elf64_Half和Elf64_word的类型。这些类型只用于uint16_t和uint32_t等整数类型的预定义(typedef)。
e_ident数组
ELF头部(和ELF二进制文件)以被称为e_ident的16字节数组开始。e_ident数组始终以4字节的“幻数”开头,以此标识该文件为ELF二进制文件。幻数由十六进制数字0x7f组成,后跟字母E、L及F的ASCII字符代码。
紧跟在幻数后面,有更多字节提供了有关ELF二进制文件类型规范的详细信息。在elf.h中,这些字节的索引(e_id ...
PE加载过程 FileBuffer-ImageBuffer
一、FileBuffer到ImageBuffer常见的误区
1.文件执行的总过程
我们知道一个硬盘上的文件读入到内存中(FileBuffer),是原封不动的将硬盘上的文件数据复制一份放到内存中
接着如果文件要运行,需要先将FileBuffer中的文件数据"拉伸",重载到每一个可执行文件的4GB虚拟内存中!此时称文件印象或者内存印象,即ImageBuffer
但是ImageBuffer就是文件运行时真正在内存中状态吗?或者说文件在ImageBuffer中就是表示文件被执行了吗?不!!!!!!
在ImageBuffer中的文件数据由于按照一定的规则被"拉伸",只是已经无线接近于可被windows执行的文件格式了!但是此时还不代表文件已经被执行了,因为此时文件也只是处在4GB的虚拟内存中,如果文件被执行操作系统还需要做一些事情,将文件真正的装入内存中,等待CPU的分配执行
所以不要理解为ImageBuffer中的状态就是文件正在被执行,后面操作系统还要做很多事情才能让Ima ...
PE简介
可移植可执行(Portable Executable,PE)格式。由于PE是Windows操作系统上使用的主要二进制格式,因此熟悉PE格式对在Windows操作系统上分析常见的二进制恶意软件非常有用。
PE是通用对象文件格式(Common Object File Format,COFF)的修改版本,在被ELF取代之前,COFF还在UNIX操作系统上使用。PE有时也被称为PE/COFF。让人困惑的是,PE的64位版本被称为PE32+。PE32+和原始PE格式相比只有很小的差异。
图3-1中显示的数据结构在WinNT.h中定义,该文件包含在Windows的软件开发工具包(Software Development Kit,SDK)中。
1.MS-DOS头和MS-DOS存根
MS-DOS是Microsoft在1981年发行的一款操作系统,Microsoft为了实现向后兼容,将其包含在二进制格式中。
引入PE格式时,有一段过渡期,即用户同时使用老旧的MS-DOS二进制文件和较新的PE二进制文件。为了避免在过渡期人们对此产生混淆,每个PE二进制文件都会以MS-DOS头开始,因此 ...
ELF节
对于各个节,readelf都会显示相关的基本信息,包括节头表里的索引、节的名称和类型。此外,你还可以查看节的虚拟地址、文件偏移及大小。对包含诸如符号表和重定向表的节,还有一列显示每个条目的大小。最后,readelf还显示每个节的相关标志、链接节的索引(如果存在)、其他信息(特定于节类型)及对齐要求。
.init和.fini节
.init节(清单2-5中的索引11)包含可执行代码,==用于执行初始化工作,并且在二进制文件执行其他代码之前运行。==可执行代码会有SHF_EXECINSTR标志,使用readelf查看Flg列,可发现该值为X❷。将控制权转移到二进制文件的main入口点之前,系统会先执行.init节的代码,如果熟悉面向对象编程,你可以将.init节看作构造函数。
.fini节(索引15)类似于.init节,不同之处在于其在主程序运行完后执行,本质上起到一种析构函数的作用。
.text节
.text节包含程序的主要代码,所以它是二进制文件分析或者逆向工作的重点。
.text节的类型为SHT_PROGBITS❸,因为其包含用户定义的代码。同时要注意节的标志,这些标志位 ...
介绍
GCC(英文全拼:GNU Compiler Collection)是 GNU 工具链的主要组成部分,是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件,由 Richard Stallman 于 1985 年开始开发。
GCC 原名为 GNU C语言编译器,因为它原本只能处理 C 语言,但如今的 GCC 不仅可以编译 C、C++ 和 Objective-C,还可以通过不同的前端模块支持各种语言,包括 Java、Fortran、Ada、Pascal、Go 和 D 语言等等。
GCC 的编译过程可以划分为四个阶段:预处理(Pre-Processing)、编译(Compiling)、汇编(Assembling)以及链接(Linking)。
Linux 程序员可以根据自己的需要控制 GCC 的编译阶段,以便检查或使用编译器在该阶段的输出信息,帮助调试和优化程序。以 C 语言为例,从源文件的编译到可执行文件的运行,整个过程大致如下。
各文件后缀说明如下:
后缀
描述
后缀
描述
.c
C 源文件
.s/.S
汇编语言源文件
.C/.cc/.cxx/.cp ...