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 ...
PE的基本概念
PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任何扩展名。
PE文件并不是作为单一内存映射文件被装入内存,Windows加载器(又称PE加载器)遍历PE文件并决定文件的哪一部分被映射,这种映射方式是将文件较高的偏移位置映射到较高的内存地址中。PE文件的结构在磁盘和内存中是基本一样的,但在装入内存中时又不是完全复制。Windows加载器会决定加载哪些部分,哪些部分不需要加载。而且由于磁盘对齐与内存对齐的不一致,加载到内存的PE文件与磁盘上的PE文件各个部分的分布都会有差异。
PE文件至少包含两个段,即数据段和代码段。Windows NT 的应用程序有9个预定义的段,分别为 .text 、.bss 、.rdata 、.data 、.pdata 和.debug 段,这些段并不是都是必须的,当然,也可以根据需要定义更多的段(比如一些加壳程序)。
在应用程序中最常出现的段有以下6种:
.执行代码段,通常 .text (Microsoft)或 ...
GCC交叉编译
使用 GCC 在单一的构建机器上来为不同的 CPU 架构交叉编译二进制文件。
如果你是一个开发者,要创建二进制软件包,像一个 RPM、DEB、Flatpak 或 Snap 软件包,你不得不为各种不同的目标平台编译代码。典型的编译目标包括 32 位和 64 位的 x86 和 ARM。你可以在不同的物理或虚拟机器上完成你的构建,但这需要你为何几个系统。作为代替,你可以使用 GNU 编译器集合 (GCC) 来交叉编译,在单一的构建机器上为几个不同的 CPU 架构产生二进制文件。
假设你有一个想要交叉编译的简单的掷骰子游戏。在大多数系统上,以 C 语言来编写这个相对简单,出于给添加现实的复杂性的目的,我以 C++ 语言写这个示例,所以程序依赖于一些不在 C 语言中东西 (具体来说就是 iostream)。
12345678910111213141516171819202122232425262728293031323334353637#include <iostream>#include <cstdlib>using namespace std;v ...
ollvm原理
Obfuscator-LLVM
Ollvm大致可分为 bcf(虚假块), fla(控制流展开/扁平化), sub(指令膨胀), Split(基本块分割)
bcf:
克隆一个真实块,并随机替换其中的一些指令,然后用一个永远为真的条件建立一个分支。克隆后的块是不会被执行的。
Fla:
将所有的真实块使用一个switch case结构包裹起来,每个真实块执行完毕后都会重新赋值switch var,对于有分支的块会使用select指令,并跳转到switch起始代码块(分发器)上,根据switch var来执行下一个真实块。
Sub:
指令膨胀,将一条运算指令,替换为多条等价的运算指令。
Split:
利用随机数产生分割点,将一个基本块分割为两个,并使用绝对跳转连接起来。
关于ollvm具体的实现,可参考源码。
指令替换 -mllvm -sub
虚假控制流 -mllvm -bcf
控制流展平 -mllvm -fla
函数(Funtions)注解
还原思路
网上有很多还原ollvm的脚本,但是只能还原特征很明显的ollvm,或者说只是debug版的ollvm。在debug版中o ...
ELF程序头
程序头表提供了二进制文件的段视图,与节头表提供的节视图相反。早前讨论过的ELF二进制文件的节视图仅适用于静态链接。相比之下,下面我们将要讨论的是段视图。在将ELF二进制文件加载到进程并执行的时候,定位相关代码和数据并确定加载到虚拟内存中的内容时,操作系统和动态链接器就会用到段视图。
ELF段包含零个或多个节,实际上就是把多个节捆绑成单个块。段提供的可执行视图,只有ELF二进制文件会用到它们,而非二进制文件(如可重定位对象)则用不到它们。
程序头表使用Elf64_Phdr结构体类型的程序头对段视图进行编码,每个程序头均包含清单2-11所示的字段。
p_type字段
p_type字段标识了段的类型,该字段的重要类型包括PT_LOAD、PT_DYNAMIC及PT_INTERP。
PT_LOAD类型的段会在创建进程时加载到内存中,程序头的剩余部分描述了可加载块的大小和将其加载到的地址。
通常至少有两个PT_LOAD类型的段,一个包含不可写数据节,另一个包含可写数据节。
PT_INTERP类型的段包含了.interp节,该节提供了加载二进制文件的解释器的名称。 ...