问:为什么还需要另一个反编译器,尤其是一个有缺陷的反编译器?
答:一个可悲的事实是,大多数反编译器都有缺陷。许多人无法反编译琐碎的结构,其他人无法反编译更高级的结构,那些看似可以处理它们的人,却因仅支持无聊的体系结构和操作系统而陷入瘫痪。几乎所有的编写方式都使得调整它或添加新的架构都很复杂。反编译器是一种逆向工程工具,但讽刺的是,如果您想高效地使用典型的反编译器或使其满足您的需求,首先您需要对反编译器本身进行逆向工程,这很容易需要数月(或数年) 。
反编译器(以及任何程序转换框架)的核心部分是中间表示(IR)。反编译器应该在 IR 上工作,并且应该将其作为输入,并且特定架构的汇编器到该 IR 的转换应该与反编译器很好地解耦,否则需要付出巨大的努力来添加对另一种架构的支持(这反过来又限制了反编译器的用户群)。
反编译是一项复杂的任务,因此应该轻松了解反编译过程。这意味着反编译器使用的 IR 应该是人性化的,例如使用程序员熟悉的语法、尽可能直接映射到典型的机器汇编器等。
上述要求本身应该是非常明显的。如果没有,可以从有关此事的书籍中学习,例如:
“编译器编写者还需要让人们轻松直接地检查 IR 程序的机制。自身利益应该确保编译器编写者注意最后一点。”
(Keith Cooper、Linda Torczon,“设计编译器”)
然而,反编译器项目,包括开源项目,经常违反这些要求:它们与特定的机器架构紧密耦合,不允许输入 IR,并且通常根本不向用户公开或记录它。
ScratchABlock就是试图对这种做法说“不”,并根据上述要求开发一个反编译框架。请注意,ScratchABlock 可以被视为一个学习/研究项目,除了良好的意图和对其他项目的批评之外,可能不会为临时用户提供太多东西 - 目前或可能根本没有。当然,它也可以在很多方面受到批评。
ScratchABlock 是根据 GNU 通用公共许可证 v3 (GPLv3) 的条款发布的。
ScratchABlock 是用 Python3 语言编写的,并在 3.3 及更高版本上进行了测试,但也可能适用于 3.2 或更低版本(不适用于旧版 Python2 版本)。有一些依赖关系:
在 Debian/Ubuntu Linux 上,可以使用sudo apt-get install python3-yaml python3-nose
安装它们。或者,您可以通过 Python 自己的pip
包管理器安装它们(应该适用于任何操作系统): pip3 install -r requirements.txt
。
ScratchABlock 使用PseudoC汇编器作为其 IR。它是一种尽可能使用熟悉的C语言语法来表达的汇编语言。这个想法是任何 C 程序员都会直观地理解它(示例),但人们正在努力更正式地记录 PseudoC。
请注意,根据文档上一节中描述的要求,并遵循众所周知的“Unix范式”,ScratchABlock 做了“一件事”——对 PseudoC 程序进行分析和转换,并且明确不关心转换特定体系结构的机器指令进入 PseudoC(至少目前如此)。这意味着 ScratchABlock 不会强迫您使用任何特定的转换器/升降机 - 您可以使用任何您喜欢的。警告:您需要有一个才能使用它。有关这方面的一些提示,请参阅文档末尾。
源代码和接口脚本位于存储库的根目录中。最重要的脚本是:
apply_xform.py
- 中央驱动程序,允许将一系列转换(或一般来说,高级分析/转换脚本)应用于单个文件或文件目录(“项目目录”)。
inter_dataflow.py
- 过程间(全局)数据流分析驱动程序(WIP)。
script_*.py
- apply_xform.py
的高级分析/转换脚本( --script
开关)。
script_i_*.py
- inter_dataflow.py
的分析脚本。
run_tests
- 回归测试套件运行程序。大多数测试套件都是高级的,包括对文件进行不同的传递来运行 apply_xform.py 并检查预期结果。
存储库的其他子目录:
tests_unit
- Python 模块的经典单元测试,用 Python 编写。
tests
- 主要测试套件。虽然本质上是集成的,但它通常对一个简单文件进行一次测试,因此遵循单元测试原理。测试表示为 PseudoC 输入文件,而预期结果 - 表示为带有基本块注释的 PseudoC 和(如果适用).dot 格式的 CFG。查看这些测试用例,尝试修改它们并查看结果是了解 ScratchABlock 工作原理的最佳方式。
docs
- 不断增长的文档集合。例如,有一个 PseudoC 汇编语言规范作为 ScratchABlock 的中间表示 (IR),以及一项为何不选择另一个现有 IR 的调查。
ScratchABlock 目前的方法是开发一组相对松散耦合的算法(“pass”),用于程序分析和转换,对它们进行测试,并允许用户轻松访问它们。反编译的魔力在于以正确的顺序和正确的次数应用这些算法。然后,为了提高反编译的性能,这些通道通常需要更紧密的耦合。在实施如上所述的通行证清单之后,探索这些方向是下一个优先事项。
ScratchABlock 实现的算法和转换:
图算法:
静态单一作业表(SSA):
数据流分析:
传播:
死码消除 (DCE)
重写:
控制流结构:
输出格式:
ScratchABlock 的合作伙伴工具是 ScratchABit,它是一个交互式反汇编器,旨在执行反编译过程的最低级别任务,例如将代码与数据分离以及识别函数边界。 ScratchABit 通常使用原生架构汇编语法,但对于某些架构(通常是忠实的 RISC),如果有合适的插件可用,它可以输出 PseudoC 语法,该语法可以作为 ScratchABlock 的输入。