逆向入门简介 byRh
简简单单以我的理解写一下逆向工程的入门方法。
0x00 什么是逆向工程 ¶
什么是逆向? 通俗来讲,计算机科学中的逆向工程就是将机器才能够懂的机器代码(二进制代码)翻译成人能够读懂的代码(汇编代码,C 语言代码),并在此基础上分析出程序的工作流程。
举个例子 ¶
先从一开始最先接触的 C 语言开始。
写一个 C 语言程序
//example1.c #include <stdio.h> int main(void){ puts("Welcome to the world of Re"); return 0; }
使用gcc
或者其他编译器或者 IDE 编译
gcc example1.c -o example1.exe
gcc
实际上主要是Linux
等类Unix
平台的开源编译器,但是Windows
平台上也有阉割版gcc
,又称mingw
。我这里使用的就是mingw
。
然后用objdump
把程序进行反汇编:
objdump -S example1.exe > dump.txt
得到的dump.txt
里面反汇编了不少启动函数,不管,直接找到main()
主函数。
这个就是我们编译出来的代码的汇编语言。
虽然现在有ghidra
,ida
这种高级反汇编工具能生成和源码很接近的伪 C 代码,但是作为逆向工程的基础,汇编语言还是很重要的,还是需要尝试去阅读,分析这种格式的汇编代码。
仅仅简单扯一下,这里详细的知识点就不讲了。
0x01 前置技能 ¶
入门需要的技能:
- C 语言代码审计能力(入门时期最重要的技能)
- 调试能力
- 汇编语言能力:通常是 x86-64 架构指令,毕竟大部分用户笔记本电脑,Windows 系统都是基于这个架构的 CPU 的。
0x02 CTF-Re 快速入门 ¶
刷题!!!!
刷题平台:buuoj,攻防世界,ctfshow。。。
入门期间,最好保持每天 1 题的频率。在刷题的时候,顺便学习知识。
实在做不出来,可以在网上查别人的 write up(简称 wp),也就是解题思路。可以多查几个 wp,毕竟不同人写的 wp 的详细程度层次不齐。
就我个人而言,我在 buuoj 上暂时刷了 5-6 页的题目。后面开始慢慢地正式的打比赛,于是 buuoj 上面的老题也就不刷了。
0x03 推荐书籍 ¶
入门时期,书籍其实是不怎么推荐的。深入研究的时候就很重要了。
不过我还是跟风推荐一下我喜欢 / 看过的书籍。
- CSAPP: 理论上应该是大一上学期《计算机导论》的教科书的,不少高质量高校用的都是这本书,而不是给外行人看的某《计算机文化》。讲的很全,但是书很厚,我猜友友们应该没这么多时间细读。bilibili 上面有一个 up 主在做 CSAPP 的教学视频,叫做九曲阑干,有兴趣就去学学。
- x86 从实模式到保护模式:前一大半写 16 位汇编知识,也就是 DOS 时代的实模式汇编;后面开始写 32 位以及 64 位保护模式的汇编
- 程序员的自我修养——链接、装载与库:介绍了 C 源代码如何经过一系列的操作最终变为二进制程序。
- C primer plus:C 语言学习书籍。讲的比较详细。对于一些比较偏的语法,或者比较新的语法特性,就没必要看了。
- C++ 反汇编与逆向分析:经典的一本书籍,江湖人称小黄书,因为封面是很亮的黄色。第一版书籍中的 C++ 代码,都是基于 VC++6.0 编译器的。最近新出第二版,建议过一会儿等京东打折后入手。
- 逆向工程核心原理:Windows 逆向书籍,里面详细介绍了 dll 注入,PE 文件结构等内容。
- Intel Developer Manual:x86CPU 架构全集,百科全书,详细的描述了 x86 架构。我上次下载下来,用于查一些比较偏的指令。Intel 官方网上有 pdf,直接下载来看就好了。
0x04 推荐资源 ¶
教程类 ¶
- ctf-wiki:入门知识快速了解。
- bilibili 上面应该有不少 CTF 逆向的解题视频。当然一堆时长超级长的什么游戏逆向,Windows 逆向什么的视频,虽然属于是逆向工程,但是与 CTF 没什么关系,就别看了,专注于 CTF 题解。
- 谷歌上多搜搜别人的博客。(百度就算了,避坑 CSDN)
刷题类 ¶
比赛类 ¶
0x05 工具 ¶
先讲一下我经常用到的工具吧。
反汇编工具 ¶
IDA¶
现在已知最好的商业用户态反编译器。单人直接购置比较昂贵。可以选择组团购买(有钱佬或者追求最新版本的人可以考虑)。或者选择网上的破解过的老版本。
IDA
支持多种架构,在主流架构中,比如x86
,x64
,arm
,arm64
等都支持反编译,即将汇编代码还原回 C 伪代码。较新的 7.5 版本也支持了对mips
架构的反汇编。
IDA
支持插件拓展,以提升工作效率。我个人觉得比较好的有Keypatch
插件,用于快速对代码进行打补丁;PyIDA
插件,提供了一个基于IPython
的交互式界面,写IDAPython
代码更有效率;FindCrypt
,根据密码算法的特征码识别主流加密算法。
如上所述IDA
有一个IDAPython
脚本语言环境作为额外支持,这能够使得用户快速写出便捷的脚本,实现自动化。
Ghidra¶
NSA 美国国家安全局的开源用户态反编译器。在Github
上面能找到。功能也很强大,而且开源,想深入研究反编译原理的可以考虑去阅读Ghidra
的源码。(没试过但大为震撼)
而且Ghidra
早已支持mips
架构的反编译,非常有优势。
Ollydbg¶
Windows 平台下祖传的 32 位程序用户态动态调试器。在IDA
还没有因为泄露版而爆火之前,Od
是最常用的反汇编工具。Ollydbg
因为有良好的社区以及众多的用户支撑,所以它有很多插件可供使用。
可以选择在吾爱破解网站上下载由各位大佬魔改,加过插件后的Ollydbg
版本。
x64dbg/x32dbg¶
也是 Windows 平台下的用户态调试器。其x64dbg
弥补了Ollydbg
只能调试 32 位程序而无法调试 64 位程序的缺陷。
gdb¶
Linux 平台上最常用的调试器。功能强大,是 pwn👴的最爱。
调试 Linux 程序的时候可以选择使用该工具。
当然其特点是,它是一个命令行工具,而刚刚介绍的都是 Windows 平台上的图形化调试器,所以可能需要一段时间熟悉操作指令。
调试 Linux 程序,也可以使用IDA
远程调试。
jeb3¶
这其实也是一个全能型商业反汇编器,但是由于其他架构的支持有点拉跨,所以通常用于分析安卓应用。
付费软件。
Windbg¶
Windows 专业调试器。有内核态和用户态两种模式。十分万能。内核态调试器也不算多,所以 windbg 算是十分厉害的工具了。
对于内核态和用户态两类调试器的区别,可以暂且简单认为内核态更厉害,速度也更快,毕竟需要管理员权限才能使用;而用户态调试器仅仅调用了系统允许使用的普通 API,有不少局限性。
dnspy¶
.Net 程序分析工具。很好用。
实用脚本工具 ¶
Github 上面有很多工具可供使用。谈谈我经常用的。
这些工具通常都是基于 python 的,可以快速写出一个解题脚本。
z3¶
微软实验室推出的 SMT 求解器。近年来开源了,可以在 GitHub 上面找到。
z3 简单来说就是一个用于解方程的工具。
虽然也有局限性,但是 z3 确实能够解决挺多的基于算法的 CTF 题。z3 自带的例子就有八皇后问题,幻方等经典算法谜题求解脚本。
z3 也是 angr 和 triton 底层的约束求解器。
z3py api guide | (´∇`) Wuuuudle Blog 吴师傅的博客,可以作为学习参考。
capstone¶
开源反汇编器。支持多个架构。
有利于快速获得一些小片字节码的汇编代码。
capstone 算是支持指令集最多的反汇编器了。IDA
有些会识别错误的指令,capstone 都能正常反汇编出来。
keystone¶
开源编译器。支持多个架构。
有利于快速从小片汇编代码中编译出字节码,而不需要像gcc
编译器那样需要一个完整的程序声明。
keystone 也是 IDA 插件 keypatch 的底层。
angr¶
虽然是一个比较全能的二进制分析框架,但是对于大部分使用人员来说,它还是用于” 符号执行 “的工具。
利用” 符号执行 “,angr
能够解决不少简单的 CTF 逆向题。
符号执行是一个程序分析理论,后面会讲。
triton¶
triton 是一位法国佬写的,一开始是基于 pintools 的动态符号执行二进制程序分析框架。
是一个比较新兴的工具,作者也在积极更新。有兴趣的话可以去看看他的博客。
作者的名字叫做 Jonathan Salwan。
unicorn¶
一个基于 qemu 的 CPU 模拟器,支持 x64,x86,powerpc,mips,arm,arm64 等多个平台。用于模拟执行程序,能够弥补很多动态调试器的缺陷。
miasm¶
一个二进制分析框架。稍微老了一点,但还是挺好用的。
qemu¶
架构模拟器。可以跨平台模拟程序。比如可以在 x86 平台的 Linux 上模拟 arm Linux 程序。
qiling¶
基于 Unicorn 的工具。Unicorn 作为单纯的 CPU 模拟器,不能处理系统调用,异常处理等一些基于系统的功能;而 qiling 在 Unicorn 的基础上尝试模拟系统调用等功能,实现了一个真正的对程序的模拟运行。
比较新兴的工具,好像还是国人写的工具。
Crypto 库 ¶
密码学库,内含多个现代密码学算法。可以用于解不魔改情况下的现代密码学加密题。
Re 出密码题通常只出现代密码学题,但通常少不了魔改,在魔改情况下就无法使用了,只能用自己写的解密脚本去解题。
Frida/xposed¶
安卓方向比较常用的分析框架。
其他 ¶
pin¶
Intel 提供的一个插桩工具。其内核的实现方式不开源,但是 Intel 提供了编写 pintools 的 API。
pin 和 pintools 是两个概念。pin 是底层,由 Intel 提供,本质是一个虚拟机;pintools 是由用户编写的,基于 pin 的工具。具体的描述比较复杂,编写 pintools 也需要一定技巧,所以不再赘述。以后我会继续更新关于 pintools 的博客。
最常用的 pintools 是指令计数工具,能够根据指令数分析程序效率。基于侧信道攻击理论,指令计数工具能用于爆破 CTF 的简单题 flag,或者猜测输入字符串长度。
triton 作者对于 pintools 编写是有一手的。可以看看它的博客。
程序性质检查工具 ¶
遇到题目,通常先要知道这是什么架构的,什么位数的,可能加过什么壳。
DIE,PEiD 就是这种 Windows 平台上的检查工具。
我通常用的是 DIE,能应付大多数要求,但是有些老的保护壳还是有可能查不出来。
WindowsPE 文件分析工具 ¶
CFF explorer, DIE, lord PE...
吾爱破解上有个工具库,这些都有。
不过由于我还没很深入的分析 Windows 程序文件,大多数工具也仅仅是了解, 或者用过一两次,不够熟练。
0x02 理论 ¶
程序分析理论 ¶
程序分析通常分为静态分析和动态分析。
静态分析 ¶
使用 IDA 等工具直接嗯看伪代码,来观察其大致的总体逻辑。
优势:静态分析能够快速探索多个分支(反正是肉眼看,想跳到哪里就跳到哪儿),获得大致的程序流程。
缺点:没法获得 CPU 的实际内容,有可能存在误分析的情况;在被加壳,代码混淆,程序流混淆的情况下,静态分析变得尤其困难。
动态分析 ¶
使用 ollydbg 等调试器,在调试状态下,对一个实际的程序路径进行分析。
优势:能获得实际的 CPU 内容,便于了解真正的程序状态。动态分析可以获得内存中的实际内容,比静态分析中的静态字节码更有真实性:加壳程序,混淆程序的实际程序流程大都可以在调试的过程中摸清。动态调试脱壳也是一种常见手法。
缺点:只能局限于一个程序执行流;遇到反调试,异常处理等手段下难以动态调试。
实际分析中,都是动静态同时使用的。
SAT/SMT 理论 ¶
z3 的底层理论,十分的离散数学。
入门时不需要了解,只要会使用 z3 梭哈题目就行了。
0x04 目前遇到的题目类型 ¶
本节谈谈现在比赛里遇到的各种题型。
虚拟机 ¶
虚拟机的简单理解,就是机器套机器,一种套娃行为。
其本质就是实现一个作者自己实现的迫真指令集,然后基于这个指令集实现操作。
虚拟机这个理念,最有名的实现,就是一个很恶俗的壳,叫做 VMP。
buuoj 上经典题目就是EzMachine
,有兴趣可以去查查。
现代密码学加密 ¶
入门时最容易遇到的加密题就是基于 base64 及其变体的题目。不过 base64 实际上不是加密,其实就是一个编码方式。
正经比赛里的现代密码学加密题,包括但不局限于:TEA 家族算法,RC4 流密码,AES 及其变体,DES 及其变体。。。
偶尔还会出一些少见的密码,比如 Chacha20,Salsa20,ECC 非对称椭圆加密,甚至用 gmp 大数运算库实现 RSA。非对称加密算法通常都是标准的,不会有什么魔改,也没有什么攻击要求,不像密码方向的题目。
面对现代密码学加密,最好要提前,一个密码类型一个密码类型的去了解这个密码的加密流程,并尝试自己本地写一份能快速编译通过,快速使用的密码算法样本。这样能让你在比赛时节省不少时间。
Python¶
Py 脚本 ¶
这个比较简单,入门时可能会遇到。可能会配合代码混淆,或者虚拟机一起出现。
Pyc 字节码 ¶
Py 脚本编译成 Pyc 字节码文件。最好了解一下 Python 栈虚拟机实现,以及 Python 的汇编语言。
由 Pyc 字节码得到汇编,可以使用 python 自带的 Pydisasm 程序进行反汇编。
Github 上面也有不少反编译工具,能够直接将 Pyc 反编译成 Py 源代码。但是貌似没几个支持 3.9 及其以上的高版本的,所以学会读 Python 汇编还是一个很重要的技能。
哦对,还要了解 Pyc 字节码文件的结构。反正很简单。
Pyd 编译文件 ¶
这是最恶心的题目,需要你读 Cython 自动生成的代码。Windows 平台下用 mingw 编译出来的 Pyd 是最恶心的,没有调试信息。Linux 平台下编译出 so 文件,至少还是有调试信息的。遇到这种题目,建议放到最后去看,因为大概率会看自闭。
Pyinstaller 打包程序 ¶
利用 Pyinstaller 打包后的 exe 程序。Github 上面有几个解包工具,解包后,会得到一大坨的库文件,以及关键的程序文件。
通常解包后会得到 Pyc 文件,但是是缺损头部信息的,需要使用配套的 struct 文件进行复原。
具体不细说,反正就是要去了解 Pyc 字节码文件结构。
Go¶
Go 语言也是一个很恶俗的语言。IDA 的反编译器生成的代码不精确,最多作为参考。
需要了解 Go 语言的内存模型,调用约定等东西。以后我会整理一下知识点的。
Rust¶
纯纯的不会,和 Go 一样恶俗。
算法谜题 ¶
一些小游戏一样的感觉。
八皇后谜题,跳棋,走迷宫。。。
建议学习 DFS,BFS 或者 A * 走迷宫算法,或者尝试用 z3 解题。
.Net¶
用 dnspy 去分析. Net 题。核心是 C#。
Android¶
安卓 apk 逆向题。这是一个很大的方向,且一些混淆,加壳方法在 apk 上都能用。
Java 逆向 ¶
jeb3 逆向 apk,审计 java 代码分析主体流程。
JNI Native¶
恶俗的出题壬会将一些重要函数写成 C 语言,然后基于架构(通常是 arm)编译;然后在 java 层调用这个函数。这个逆向就得用 IDA 去看了。
Windows¶
基于 Windows 特性的一些题目。比如 SEH 异常调用,一大堆 API 调用,驱动通信机制等等。也是一个很大的面。
Linux¶
基于 Linux 特性的一些题目。ptrace 反调试,fork 创造子进程等等。对 Linux API 要有一定的了解。
架构 ¶
除了常见的 x86-64 架构,还有其他架构。
常见的有 arm,mips。
更恶心的就是一些很偏的 riscv 架构。比如一些单片机的架构。
常见架构,要了解常见指令集。
代码混淆 ¶
简单的比如有:变量名混淆,函数名混淆。这都是在有调试信息的情况下搞的恶俗事情。
Re 中比较常见的是真正的对程序执行流进行调整,变形而实现的混淆。
比如 ollvm,虚假控制流等。这些混淆在 GitHub 上面都有复原工具。