简介

逆向工程的学习过程类似于成年人学习外语的过程。学习外语的第一个阶段是从字母表开始的,这些字母构造了具有明确语义的单词。接下来的阶段涉及对语法规则的理解,语法规则决定了如何把单词连接起来产生正确的句子。一个人掌握了这些规则之后,就开始学习如何把多个句子组织起来,清晰表达复杂的思想。最终,学习者就能够阅读大部头书籍,即使这些书籍风格不同,他仍然能够掌握其中的思想。到达这个阶段之后,学习者就可以阅读关于这门语言更深奥主题(如历史句法学、音韵学等方面)的参考书了。

在逆向工程领域中,“语言”就是体系结构和汇编语言,“单词”则是一条条汇编指令,“段落”即是汇编指令序列,一本“书”就是一个程序。要完全理解一本书,读者不仅仅要掌握单词和语法,还应了解叙事风格和结构,以及不成文的写作惯例等因素。同样,理解计算机程序需要掌握的概念也不仅仅是汇编指令。

某种程度上说,开始从一本书去学习一个全新的技术主题有点让人望而却步。但如果我们因此声称逆向工程的学习过程很简单,可以通过阅读本书完全掌握,则是在误导读者。实际上这个学习过程是非常复杂的,因为这项技术涉及几个分散的知识领域。比如,一个高效的逆向工程师需要对计算机体系结构、系统编程、操作系统、编译器等技术都有所了解;对于某些领域来说,还需要具备较强的数学背景。那么如何确定从哪里开始学起呢?这取决于各人的经验和技能。而我们无法适应每个人的背景条件,因此在这个简介中为那些没有任何编程背景的读者列出了学习和阅读的方法。读者应该可以从中找到自己的位置,并从那里开始学习。

为了讨论方便,这里把逆向工程不严格地定义为对一个系统的理解过程。这是一个解决问题的过程。一个系统可能是一个硬件设备、一个软件程序、一个物理或化学过程等。对于本书来说,这个系统就是指一个软件程序。要理解一个程序,首先必须理解软件是如何编写的。因此,第一个要求是了解如何通过某种语言比如C、C++、Java等为计算机编写程序。由于C语言的简洁高效及其用途的广泛性,我们建议从它开始学起。这里给出一些值得考虑的优秀参考书,包括Brian Kernighan和Dennis Ritchie所著的《C程序设计语言》以及Samuel Harbison所著的《C语言参考手册》。在熟悉了编写、编译和调试简单程序的过程后,就可以考虑阅读Peter Van Der Linden所著的《C专家编程》(Expert C Programming: Deep C Secrets,Prentice Hall,1994)。到了这个阶段,你应该已经熟悉了变量、作用域、函数、指针、条件式、循环、调用栈、库等高级概念。对于栈、队列、链表和树等数据结构的了解可能是有所帮助的,不过就目前阶段来看还不是必需的。除此以外,你还可以简单阅读下面这些书籍,以求更好地了解程序是如何真正被连接到一起的:Alfred Aho、Ravi Sethi和 Jeffrey Ullman所著的《编译原理》(Compilers: Principles, Techniques, and Tools,Prentice Hall,1994)以及John Levine的《连接器与加载器》(Linkers and Loaders,Morgan Kaufmann,1999 )。阅读这些书的主要目的是了解基本概念,目前还不需要完全理解全部内容(关于这一点,稍后会加以详述)。学有余力的读者还可以考虑阅读Steven Muchnick所著的《高级编译器设计与实现》(Advanced Compiler Design and Implementation,Morgan Kaufmann,1997)。

一旦对程序的编写、运行和调试过程有了充分的理解,就可以开始探索程序的执行环境了,这包括进程和操作系统。我们建议首先通过从英特尔公司的Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture来学习Intel处理器,特别要注意其中的2~7章。这些章节解释了现代计算机的基本组成部分。对ARM体系结构感兴趣的读者可以阅读ARM的Cortex-A Series Programmer's GuideARM Architecture Reference Manual ARMv7-A and ARMv7-R Edition。尽管我们这本书讲述了x86/x64/ARM架构,但并不会讨论这些体系结构的全部细节。(我们假定读者会根据需要来参考以上介绍的这些手册。)通过浏览这些手册,读者应该能够对计算系统的技术构建模块有一个基本的识别和判断。如果要对概念有更深入的理解,可以考虑阅读Andrew Tanenbaum所著的Structured Computer Organization(Prentice Hall,1998)一书。另外,所有读者都应该查阅Microsoft PE and COFF Specification。到了这一阶段,读者应该已经具备了阅读并理解第1章和第2章所需的所有背景知识。

接下来就要开始探索操作系统了。尽管操作系统的种类很多,但多数概念是共通的,包括进程、线程、虚拟内存、特权隔离、多任务等。要理解这些概念,最好的方法就是阅读Andrew Tanenbaum所著的《现代操作系统》一书。尽管Tanenbaum的书对于理解概念很有帮助,但其中并没有讨论实际操作系统中的很多重要技术实现细节。对于Windows来说,可以考虑阅读Peter Viscarola 和Anthony Mason 所著的Windows NT Device Driver Development。尽管这是一本关于驱动程序开发的书,但其中的背景知识章节很好地对Windows操作系统做了集中介绍。(这本书也是对本书中第3章很好的补充材料。)另外很有启发性的一本书(也是关于Windows内存管理的优秀著作)是Enrico Martignetti 所著的What Makes It Page? The Windows 7 (x64) Virtual Memory Manager

到了这一阶段,读者应该已经具备了阅读本书第3章所需的所有背景知识。可以考虑开始学习Win32编程了。 Johnson Hart 所著的Windows System Programming,4th Edition(Addison-Wesley Professional,2010) 以及Jeffrey Richter和Christophe Nasarre所著的《Windows核心编程》(Windows via C/C++,Microsoft Press,2007)都是非常优秀的参考书。

针对于第4章调试与自动化的内容可以考虑的参考书是Tarik Soulami 所著的Windows Debugging: A Practical Guide to Debugging and Tracing Strategies in Windows(Microsoft,2012)和Mario Hewardt和Daniel Pravat所著的《Windows高级调试 》(Advanced Windows Debugging,Addison-Wesley Professional,2007)。

阅读第5章则需要对汇编语言有充分的理解,应该在阅读x86/x64/ARM章节之后开始阅读。相关背景知识可以通过阅读Christian Collberg和Jasvir Nagra所著的《软件加密与解密》(Surreptitious Software: Obfuscation, Watermarking, and Tamperproofing for Software Protection,Addison-Wesley Professional,2009)一书获得。

注意 本书包含了针对真实病毒和后门程序的练习和实验。我们有意这么做是为了确保读者能够立即把新学的技术应用于实际。这些恶意代码示例用字母序来指代(如示例A、B、C等),可以在附录中找到其对应的SHA1散列值。出于法律方面的顾虑,我们决定不随本书发布这些示例。但是读者可以通过搜索各种恶意代码库比如www.malware.lu来下载,或者在http://kernelmode.info这样的论坛上请求得到这些示例。这些示例中有许多是来自于引发全球性新闻的著名黑客事件,因此是很有趣的。也可能会有热心的读者搜集所有这些示例并打包通过BitTorrent发布。如果前面这些方法都行不通,请尽管给本书作者发信。分析这些示例的时候,需要确保你是在安全的环境中,以免不小心感染了这些病毒。

另外,为了帮助读者熟悉Metasm,我们准备了两个练习脚本:symbolic-execution-lvl1.rb和symbolic-execution-lvl2.rb。这些问题的解答过程会带你进入深入了解Metasm的旅程。可以在www.wiley.com/go/practicalreverseengineering找到这些脚本。

一定要意识到,这些练习是本书至关重要的部分。本书的编写模式就是按照这种思路来的。如果你仅仅是阅读而不做练习的话,不会有深入的理解和太多收获。读者尽可以写出对这些问题的答案,或发布在自己的博客上,这样其他人可以从中学习;你也可以把答案发布在逆向工程reddit (www.reddit.com/r/ReverseEngineering),并得到社区(也许就是本书作者)的反馈。如果你成功完成了所有练习,那一定要好好奖励一下自己,然后请把你的简历发给作者。

要成为高效的逆向工程师,学习的旅程是漫长又耗时的,需要耐心和坚持。在学习的道路上你可能会多次失败(比如无法理解书中概念或者无法完成本书习题),但是不要放弃。记住,失败是成功的一部分。通过这个简介以及后续的章节,你应该已经准备好了踏上学习的征程。

作为作者,我们非常希望了解读者的学习经验,并据此进一步调整本书内容,改善本书质量。读者的反馈对于我们以及未来可能的新版本是无比宝贵的。反馈意见和问题可发送给 Bruce Dang(bruce.dang@gmail.com)、Alexandre Gazet(agazet@quarkslab.com)或Elias Bachaalany(elias.bachaalany@gmail.com)。

目录

  • 献词
  • 关于作者和技术编辑
  • 致谢
  • 简介
  • 第1章 x86与x64
  • 第2章 ARM
  • 第3章 Windows内核
  • 第4章 调试与自动化
  • 第5章 代码混淆
  • 附录 实例名称与相应的SHA1散列值