[翻译]The IDA Pro Book(第一章)-外文翻译-看雪-安全社区|安全招聘|kanxue.com
加入看雪很久了,一直只是在汲取营养。
最近正在学习加密与解密,刚好看到组织翻译《The IDA Pro Book》,因此领养第一章。
第一次翻译,请多指教。第一章 反汇编简介
你可能想知道在一本致力于IDA Pro的书中会介绍些什么。很明显,此书是以IDA为中心,但此书并不打算作为IDA Pro用户手册。取而代之,我们打算把IDA作为讨论逆向工程技术的有利工具(the enabling tool)来用。你将发现这些逆向工程技术在分析多种软件(从漏洞应用程序(vulnerable application)到恶意软件)时很有用。为完成和我们手头任务相关的某些动作,在IDA中要遵循一定的步骤,我们将在合适的时候详细提供。因此,从在最初查看文件时你想执行的基本任务开始,到针对更具挑战的逆向工程问题的IDA高级应用和定制为止,我们将对IDA的能力有个间接的了解。我们不会介绍IDA的所有特性。但你将发现我们介绍的这些特性在应对逆向工程挑战时非常有用,正是这些功能让IDA成为你工具箱中最有效的工具。
在开始介绍IDA的细节之前,介绍一些反汇编过程的基础和回顾其它对编译代码进行逆向工程的有用工具很有用。虽然这些工具中没有一个提供IDA的全部功能,但是它们专注于IDA全部功能的特定部分,并提供了对特定IDA特性的有用领悟(and offer valuable insight into specific IDA features)。这章接下来的部分将讲解反汇编的过程。
反汇编理论
任何一个花过时间学习编程语言的人可能都学习过编程语言的多种阶段。下面将为在学习这些时打瞌睡的人再总结一下。
第一代语言
这些语言是语言的最低级形式,一般由0和1或某些简写形式,如十六进制组成。只有像Skape[1]这样的超人才能读懂它们。由于看起来都差不多,因此很难区分数据和代码,所以在这一级别事情令人很困惑。第一代语言也称为机器语言,在某些情况下叫字节码。机器语言程序通常称为二进制文件。
第二代语言
也叫汇编语言,第二代语言仅仅是一个脱离了机器语言的表查找。通常,第二代语言映射特定的位模式或操作码到短小并容易记忆的字符序列,这种序列叫做助记符。事实上,这些助记符有时候帮助程序员记住了和它们相关的指令。汇编器是程序员用来把他们的汇编语言程序翻译成适合运行的机器语言的工具。
第三代语言
这些语言通过引入关键字和结构与自然语言的表达能力更近了一步。程序员使用结构作为他们的程序的构建块。尽管使用第三代语言编写的程序由于使用了特定操作系统的独特特性而使得程序平台相关了,但是第三代语言通常是平台无关的。FORTRAN,COBOL,C和JAVA是通常引用的例子。程序员通常使用编译器把他们的程序翻译成汇编语言或者一步到位地翻译成机器语言(或者某些大致的等价形式如字节码)。
第四代语言
这些语言虽然存在但是和本书无关,不做讨论。
什么是反汇编
在传统的软件开发模型中,编译器,汇编器和链接器单独或者联合到一起创建可执行程序。为了向后追溯(或者逆向程序),我们使用工具来撤销汇编和编译过程。一点也不奇怪,这些工具叫做反汇编器和反编译器,它们所做的几乎就是它们的名字所暗示的。反汇编器撤销汇编过程,因此我们可以得到汇编语言输出(因此机器语言是输入)。反编译器旨在以汇编或者甚至是机器语言为输入产生高级语言形式的输出。
在充满竞争的软件市场中,“源代码恢复”的许诺总是很诱人,因此在计算机科学中,开发合用的反编译器仍然是一个活跃的研究领域。如下只是反编译比较困难的少数原因。
编译过程是有损的
在机器语言级别没有变量或函数名,变量类型信息只能通过数据怎样被使用而不是明确的类型声明来确定。当你观察到一个32位的数据被传送时,你需要做一些研究工作来确定这32位数据表示的是一个整数,一个32位浮点值还是一个32位指针。
编译是多对多的操作
这意味着源程序可以用多种不同的方式翻译成汇编语言,而机器语言也可以用多种不同的方式翻译回来。因此,编译一个文件并立即将它反编译的结果将和源文件有很大的不同。
反编译器严重依赖语言和库
用设计用来产生C代码的反编译器处理一个Delphi编译器产生的二进制文件将会产生非常奇怪的结果。同样地,用对Windows 编程API毫无所知的反编译器处理Windows二进制文件也不会产生有用的信息。
为了正确地反编译一个二进制文件需要几乎完美的反编译能力
任何反编译阶段的错误或遗漏一定都会影响全部反编译代码。
然而,在反编译前端,慢但是可靠的过程建立了。我将在第23章回顾当今市场上最久经考验的反编译器Hex-Rays。
为什么要反汇编
反汇编工具的目的是在没有源代码时帮助理解程序。通常,需要使用反汇编的情况包括这些:
分析恶意软件
分析闭源软件的脆弱性
分析闭源软件的互操作性
分析编译器产生的代码来验证编译器的性能和正确性
在debug时显示程序指令
接下来的章节将更详细的介绍每一种情况。
恶意软件分析
除非你处理的是基于脚本的蠕虫病毒,恶意软件的作者很少会提供他们的创作的源代码来帮助你。缺乏源代码,你只有非常有限的选择可以用来发现恶意软件到底是怎样运作的。恶意软件分析的两种重要技术是动态分析和静态分析。动态分析就是让恶意软件在一个被小心控制地环境(sandbox)中执行并用系统工具来记录它行为的每一个可观察的方面。相反,静态分析试图简单地通过读程序代码来理解程序的行为,而对恶意软件,程序代码通常由反汇编列表组成。
脆弱性分析(vulnerability analysis)
为简单化,我们把整个安全审计过程分为三步:发现脆弱性(vulnerability),分析脆弱性(vulnerability),exploit开发。不管你是否有源代码,都可以使用相同的步骤,但是,如果你仅仅有二进制文件,需要付出的努力将更多。过程中的第一步是发现程序中潜在的可exploit条件。这通常是通过动态技术如Fuzzing[2]来达成的,但是也可以通过静态分析来完成(通常需要更多的工夫)。一旦发现问题,就需要进一步的分析来确定问题是否可exploit,如果可以,是在什么条件下。
编译器要选择究竟怎样分配程序变量,反汇编列表提供了理解这些需要的细节。例如,程序员声明70个字节的字符数组,当编译器分配空间时,该数组被扩大到80字节,知道这些很有用。编译器究竟是怎样排序全局变量或局部变量的呢?反汇编列表提供了确定这些的唯一方式。在开发exploit时,有必要了解变量的空间关系通常。最终,通过联合使用反汇编器和调试器,就可以开发exploit了。
软件互操作性
当一个软件仅仅以二进制发布时,竞争者要创建可以和它互操作的软件或者为该软件提供插件(plug-in replacement)是非常困难的。一个普遍的例子就是,硬件驱动代码仅仅支持一种平台。当厂商慢于支持或者更糟,拒绝支持在可选的平台上使用他们的硬件时,为了开发支持该硬件的软件驱动,通常可能需要很多的逆向工程努力。在这些情况下,静态代码分析几乎是唯一的方法。通常,为了理解嵌入式固件,分析需要超越软件驱动的范畴。
编译器验证
由于编译器(或汇编器)的目的是产生机器语言,通常需要好的反汇编工具来验证编译器在按照设计规范完成它的工作。除了正确性,分析者对定位优化编译器输出的额外机会感兴趣,立足于安全方面,他们对确定编译器是否使自身妥协而可能在产生的代码中插入后门也感兴趣(ascertaining whether the compiler itself has been compromised to the extent that it may be inserting back doors into generated code)。
调试显示
反汇编器的一个最普遍的应用可能是在调试器中产生代码列表。不幸的是,调试器内嵌的反汇编器相当简单(OllyDbg是一个显著例外)。它们通常不能批量反汇编,在不能确定函数的边界时,它们有时候会回避反汇编。一个好的反汇编器在调试中提供更好的环境语义和上下文,上述是为什么最好联合这样的反汇编器来使用调试器的原因之一。
怎样反汇编
你已经知道反汇编的目的,但反汇编过程到底怎样进行的呢?现在是介绍这些的时候了。考虑一个反汇编器所面对的任务:这有100KB数据,区分代码和数据,把代码转换成显示给用户的汇编语言,并且在该过程中没有遗漏任何信息。这个任务很典型,很困难。在这个任务的结尾,我们可以附加许多特定需求,例如要求反汇编器定位函数,认出跳转表并识别局部变量,这使得反汇编器的工作更加困难。
为了实现我们的所有需求,任何反汇编器都需要在处理我们提供的文件时从大量的算法中进行选取。产生的反汇编列表的质量直接和使用的算法的质量以及算法实现的质量相关。在这一节,我们将讨论当今反汇编机器代码使用的基本算法中的两个。当讲述这些算法的时候,我会指出它们的缺陷。这样你对反汇编器看起来是失败了的情况就有所准备。通过理解反汇编器的局限,你就可以通过手动干预来提升反汇编输出的整体质量。
一个基本反汇编算法
首先,让我们来开发一个简单的算法,该算法以机器语言为输入产生汇编语言输出。在这样做的时候,我们就可以理解自动反汇编过程中的挑战,假设和折中。
第一步
反汇编的第一步是识别出一段被反汇编的代码。这并不像看起来的那么简单。通常,代码和数据混在一起,而区分它们很重要。在最普遍的情况中,一个被反汇编文件符合可执行文件的共同格式如Windows使用的Portable Executable (PE)格式或在许多基于Unix的系统中常见的Executable and linking format(ELF)格式。典型地,这些格式包括定位文件中包含代码的段和代码入口点[3]的机制(通常以十六进制文件头的形式)。
第二步
已经知道一条指令的起始地址,下一步就是读该地址(或文件偏移)包含的值并执行一个表查找来匹配二进制操作码的值和它的汇编语言助记符。依赖于被反汇编的指令集的复杂性,这可能是一个简单的过程,也可能包括几个额外的操作,如弄清楚可能修改指令行为的任何前缀和确定指令需要的操作数。对指令长度可变的指令集,如Intel X86,可能需要取得额外的指令子节来完全地反汇编一条单独指令。
第三步
一旦取得一条指令并译码了需要的操作数,接下来就是格式化它的汇编语言等价形式并作为反汇编列表的一部分输出。可以从不止一种汇编语言输出格式中选择。例如,X86汇编的两种主要的格式是Intel格式和AT&T格式。
X86汇编语法:AT&T VS INTEL
汇编语言源代码有两种主要的语法:AT&T和Intel。尽管它们都是第二代语言,但是它们的语法(从变量,常量和寄存器访问,到段和指令大小覆盖,到间接访问和偏移地址)有很大的不同。AT&T汇编语法用%作为所有寄存器名称的前缀,用$作为文字常量的前缀(也叫做立即数),它的源操作数出现在左边,目的操作数在右边。使用AT&T语法,加4到eax寄存器的指令是:add $0x4,
栏目分类
- Helium IOT中文网
- Helium IOT中文网
你的位置:yearn.finance 中文站 > Helium IOT中文网 > [翻译]The IDA Pro Book(第一章)-外文翻译-看雪-安全社区|安全招聘|kanxue.com