2.2、二进制审计
现在你已经深入到原生层,这是你撕扯下所有遮掩后的软件。今天我们所关注的原生代码形式是Intel X86下的32位代码。Intel处理器从上世纪80年代开始在个人计算机市场有着强劲的表现,现在支配着桌面和服务器市场。理解这些指令集可以帮助你以内部视角看到程序每天是如何运行的,也可以在你遇到诸如ARM、MIPS、PowerPC和SPARC等其他指令集时提供一种参考。
这部分内容我们将要逐渐熟悉原生层和开发策略,以理解、分析和解释本地代码。在该部分结束时你应该能够完成一项“逆向编译”——从汇编分段到高级语言状态——以及处理过程、派生意义和程序员意图。
课程
学习X86初看起来令人生畏且需要一些专业性的学习才能掌握。我们建议阅读《深入理解计算机系统》的第三章学习C程序是怎样编译成机器指令的。当你有了一些基础的、这种过程的应用知识,就在手边随时备着像弗吉尼亚大学x86汇编指南这样的参考指南。我们还发现了来自Quinn Liu的系列视频作为快速介绍。
《深入理解计算机系统》第三章: Machine-Level Representation of Programs
挑战工坊
下面的程序都是“二进制炸弹”。逆向工程这些Linux程序并确定输入序列就可以“拆除“炸弹。炸弹的每个连接层关注于原生代码的不同层面。例如,CMU实验室中的程序(CMU Binary Bomb Lab)中你会看到不同数据结构(链表、树)以及控制流结构(切换、循环)在原生代码层面怎样表现的。在逆向这些程序时你可以发现将程序执行流程转换为C或者其他高级语言的有用之处。
你应该将目标聚焦于解决这两个实验室程序的八个段。CMU炸弹程序有一个隐藏段,RPI炸弹程序有一个段包含有内存错误,你能找到并解决么?
工具
处理原生代码的两个至关重要的工具是调试器和反汇编器。我们建议你熟悉下行业标准反汇编工具:IDA Pro。IDA会分割代码为独立的块以对应程序源码的定义函数。每个函数进一步被分割为修改控制流的指令定义的“基础块”。这样很容易一眼识别循环、条件和其他控制流指令。
调试器允许你与设置了断点的运行中代码进行交互和状态检查,以及内存检查和寄存器内容查看。你会发现如果你的输入没有产生预期的结果,这些查看功能是很有用的,但是一些程序会使用反调试技术在调试时改变程序行为。对于大多数Linux系统来说GNU调试器(gdb)是标准的调试工具。gdb可以通过你所用Linux版本的软件包管理器获得。
资源
已经有许多好的资源用来学习x86汇编和CTF题目中的技巧。除了以上资源,x86维基手册和AMD指令集帮助都是更加完整的参考供你参考(我们发现AMD帮助手册没有Intel帮助手册那么吓人)。
AMD64程序员帮助手册: General-Purpose and System Instructions
Computer Systems: A Programmer's Perspective (《深入理解计算机系统》)
一些逆向工程工具使用起来和汇编语言自身一样复杂。下面列出的是常用的命令行工具的命令表单:
最后,许多CTF挑战会使用反调试技术和反汇编技术隐藏或混淆目标。上面的炸弹程序就使用了其中的几种技术,但是你可能想要更全面的参考资料。