二进制安全

什么是二进制漏洞?

二进制漏洞是可执行文件(PE、ELF文件等)因编码时考虑不周,造成的软件执行了非预期的功能。由于二进制漏洞大都涉及到系统层面,所以危害程度比较高。

比如经典的office栈溢出漏洞(CVE-2012-0158)、(CVE-2017-11882)以及(CVE-2017-11882)的补丁绕过漏洞(CVE-2018-0802)等,都是危险程度极高的0day和1day漏洞。

所以,二进制漏洞的挖掘和分析就显得尤为重要,本篇文章将对常见的二进制漏洞进行简要的介绍和分析。逆向工程是二进制分析的基础能力。

常见二进制漏洞分类

  • 栈溢出漏洞(Stack-Overflow)

  • 堆溢出漏洞(Heap-Overflow)

  • 释放后重引用漏洞(Use-After-Free)

  • 双重释放漏洞(Double-Free)

  • 越界访问漏洞(Out-of-bounds)

二进制漏洞挖掘常用工具

  • GDB: Linux调试中必要用到的
  • gdb-peda、pwndbg、gef: GDB调试插件
  • pwntools:写exp和poc的利器
  • libc-databases:可以通过泄露的libc的某个函数地址查出远程系统是用的哪个libc版本
  • checksec:可以很方便的知道elf程序的安全性和程序的运行平台
  • objdump :可以很快的知道elf程序中的关键信息
  • readelf:可以很快的知道elf程序中的关键信息
  • ida pro:反汇编工具
  • ROPgadget:强大的rop利用工具
  • one_gadget:可以快速的寻找libc中的调用exec('bin/sh')的位置

基础知识

都是基础知识,建议理解清楚,否则会影响相关书籍的阅读理解。

为什么调试器能调试?

学习调试器的基本原理。

大端序和小端序

大端序(Big-Endian)和小端序(Little-Endian)是数据在内存中存储的两种不同的顺序。这两种顺序定义了多字节数据类型(如整数、浮点数)中每个字节的排列方式。

大端序(Big-Endian):

在大端序中,一个数的最高位字节(即“大端”)存储在内存的低地址处,其后的字节按照数值逐渐减小的顺序存放。 例如,假设我们有一个16位的数字0x1234(十六进制表示),在大端序的系统中,内存的存储布局将会是:

低地址 --> 0x12  | 高位字节
高地址 --> 0x34  | 低位字节

此种排列方式与我们人类阅读数字的习惯一致,即从左至右读取。

小端序(Little-Endian):

在小端序中,一个数的最低位字节(即“小端”)存储在内存的低地址处,其后的字节按照数值逐渐增大的顺序存放。 同样是16位的数字0x1234,在小端序的系统中,其在内存中的存储布局则是:

低地址 --> 0x34  | 低位字节
高地址 --> 0x12  | 高位字节

此种排列方式与人类阅读习惯相反,即我们需要从右至左读取,才能得到正确的数值。

重要性和影响

  • 交互性问题: 当不同的计算机系统需要互相通信时,字节序可能会成为一个重要问题。如果两端的系统采用不同的字节序,那么在数据传输过程中必须进行转换,否则接收端会得到错误的数据。
  • 性能问题: 有时候在某些特定运算中,小端序可能会有微小的性能优势,因为它的低位字节在低地址位置,这与算数运算的操作顺序相符。但这种差别通常可以忽略不计。
  • 跨平台开发: 编程时一定要考虑到字节序的问题。特别是在网络编程和文件格式设计时,通常会选用网络字节序(即大端序),即使平台本身采用的是小端序。

为什么0x12是高位字节,0x34是低字节位

数字0x1234是一个16位的十六进制数,在内存中存储时会分为两个字节。在这里,“0x12”和“0x34”代表了两个不同的字节。

十六进制数“0x1234”可以被拆分为两部分:“0x12”是高位字节,而“0x34”是低位字节。

解释起来: - “高位字节”指的是数值中占用更高数值位的字节。在这个例子中,两个字节构成的数值0x1234中,“0x12”部分占据了更高的数值位置,即千百位。 - “低位字节”指的是数值中占用更低数值位的字节。在同一个数值中,“0x34”占据了较低的数值位置,即十个位。

当我们将这个十六进制数表示为二进制时,0x1234对应的是:

0001 0010 0011 0100

从二进制的角度看,左边的“0001 0010”是更高的位,即“高位”,对应十六进制的“0x12”。右边的“0011 0100”是更低的位,即“低位”,对应十六进制的“0x34”。 而在计算机存储和处理数值时,通常是由低位到高位依次存储和计算的。在不同的系统中,这些位的存储顺序是由大端序还是小端序决定的,如我之前解释的那样。 希望这能清楚地解释为何在十六进制数0x1234中,“0x12”是高位字节,“0x34”是低位字节。

大端序中,为什么0x12是低地址,而0x34是高地址

在大端序(Big-Endian)中,数值的高位字节(即数值大小上处于更为重要的位置的那部分)存储在低地址的位置,而数值的低位字节(大小上相对次要的位置)则存储在高地址的位置。

为什么在大端序中 0x12 是低地址位?

在大端序的表示法中,如果我们有 0x1234 这个数值,那么:

“0x12”是这个数值的高位字节,因为它代表的是数值中的较大部分(即2^8以上的部分)。 “0x34”是低位字节,因为它代表的是数值中的较小部分(即2^8以下的部分)。

根据大端序的定义,我们将“0x12”(高位字节)放在低地址位上,此时数值的最重要的部分(最高位)就位于内存的起始部分。 紧接着,内存地址递增,“0x34”(低位字节)就被放在高地址位上。这种存储方式类似于我们阅读文字时从左至右的顺序,数字和文档通常也是这样的表现方式。

例如,如果有两个连续的内存地址位置是0x01和0x02,那么在大端序下:

内存地址 0x01 --> 0x12 (数值的高位字节)
内存地址 0x02 --> 0x34 (数值的低位字节)

所以,在大端序中,“0x12”(作为高位字节)存储于低地址,“0x34”(作为低位字节)存储于高地址,这是一种按照数值重要性排序字节的表现形式。

为什么在大端序中,高位字节存储在低地址位置?

在大端序中,高位字节存储在低地址位置主要是一种设计决策,它是数据存储的一种约定,源自网络通信和早期的计算机架构设计。

常用命令

查看ELF的导入/导出符号

-速查手册

查看动态符号

objdump -CT <ELF>
nm -CD <ELF>
readelf -W --dyn-syms --demangle <ELF>

若已知导入/导出符号名,grep上述命令的输出即可。

Windows中可以查看PE的导入表: dumpbin /imports

  1. 命令 nm -D,如下所示:

nm -D liblistdevs.so > listdevs.txt  //列出 liblistdevs.so 的函数 输出到 listdevs.txt 文本文件里面

  1. 命令 objdump -tT,如下所示:

objdump -tT liblistdevs.so > listdevs.txt  //列出 liblistdevs.so 的函数 输出到 listdevs.txt 文本文件里面

重要的基础概念

PE文件与虚拟内存(VA)之间的映射关系

from 0day安全 1.2.3

1.文件偏移地址(File Offset)

数据在PE文件中的地址叫文件偏移地址。(这是文件在磁盘上存放时相对于文件开始处0字节的偏移。)

2.装载基址(Image Base,又称镜像基址,映射基址)

PE装入内存时的基地址。

默认情况下:
EXE文件在内存中的基地址是0x00400000
DLL文件在内存中的基地址是0x10000000

这些位置可以通过修改编译选项更改。
可以先用LoadPE之类的软件检查下exe

3.虚拟内存地址(Virtual Address,VA)

PE文件中的指令被装入内存后的地址。

4.相对虚拟地址(Relative Virtual Address, RVA)

内存地址相对于映射基址的偏移量。

VA、Image Base、RVA关系

VA = Image Base + RVA

近期的二进制阅读规划

基础部分

主要需要学习的语言:C、C++、Python以及汇编。(总共4门,C和C++属于一脉相承可以算一门半语言,那也有3.5门)

PS:动态分析中没有任何一款工具可以把代码还原成伪代码执行,所以动态分析过程中所接触的全都是汇编代码。

语言基础:C语言入门经典书籍随便选一本,王爽 汇编语言 第4版 --> 逆向基础:逆向工程核心原理,再看加密与解密 第4版

PS: 这里有另一套语言基础学习方案: - 《C Primer Plus》:有中文版,详尽的说明了C语言语法你所需要了解的一切。推荐花30天时间简单学习。 - 《C++ Primer》:有中文版,推荐花30天时间简单学习。 - 《算法导论》:数学系底子要好,跟不上就要找其他零基础学算法的。的推荐学习时长为60天。 - 《Python核心编程》:7天熟悉基础语法,后续库使用可以需要用时再查。 - 《汇编语言 基于x86处理器》:容易理解,也有人是用王爽的汇编语言入门,都可以。学完之后就是学习系统编程。 - 《Windows核心编程》:主要讲的是Win32 API编程,需要好好了解一下,因为Windows下的恶意代码一类的,万变不离其宗,最后还是要走API这条路。学习时间是90天。

学习完系统编程,学习的是Windows下的文件结构,也就是PE(Portable Executable)结构,这个结构对于我们分析病毒还是漏洞都有着至关重要的作用,因此需要详细了解,讲解这个结构的书非常多, - 《Windows PE权威指南》:既学习了PE结构,又复习了汇编语言。推荐时长30天。

然后学习逆向: - 《C++反汇编与逆向分析技术揭秘》,软件逆向看这一本书就够了,但是看完之后建议看一些综合类的实战书籍,比如《加密与解密4》,然后我们还需要对Windows的调试原理有些了解,这里使用《Windows高级调试》以及《软件调试》来学习。

细分方向部分

  • 恶意代码分析:恶意代码分析实战。

  • 漏洞挖掘:0day安全:软件漏洞分析技术 第2版(入门)、漏洞战争(进阶)。

  • shellcoder编程揭秘:了解漏洞利用中的奇淫技巧。

上述学习阶段建议学习时长90天。

以上内容学完应该能够踏入二进制安全的正轨,后续就是在工作中不断精进,不断成长。

二进制漏洞分析模板

推荐看雪的这个模板 二进制漏洞分析文章模板

其它资料

如何在Windows系统下进行二进制安全学习 - Freebuf有视频

1. 游戏安全入门

  • 游戏安全的本质:控制游戏内外部风险,使得其游戏环境健康可持续,游戏内金融体系不崩溃。
  • 游戏安全通常从哪些方向下手?
    1. 风险控制
    2. 原生游戏漏洞 原生游戏漏洞举例
    3. 人为外挂风险

2. 破解技术入门

3. 恶意代码入门

4. 病毒分析入门

5. 壳与脱壳入门

Windows逆向工程入门指南

Win32汇编在Linux系统上是不适用的。

此外,rkvir在B站有一些列 windows逆向入门视频 ,入门推荐先学习。

REF