x86汇编与逆向工程:软件破解与防护的艺术
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.3.2 汇编

计算机运行的是二进制的数字逻辑。所有的东西要么是打开的(1),要么是关闭的(0)。这也包括在计算机上运行的程序。所有高级语言最终都会被转换成一系列称为机器码(machine code)的二进制比特(bit)。机器码定义了计算机为了完成期望功能所要执行的一系列指令。

1.机器码

每个程序员都从“Hello World”程序开始学习编程语言。在x86中,“Hello World”的机器码如下:

为了便于阅读,这段机器码是以十六进制编写的,但它真正的值是一个由1和0组成的二进制字符串。这个二进制字符串包含了很多指令:翻转晶体管以计算信息、从内存中提取数据、通过系统总线发送信号、与显卡交互,以及输出“Hello World”文本。如果你觉得这串字符似乎有点短,无法完成所有这些工作,那是因为这些指令会触发操作系统(在这个例子中是Linux)来协助其完成。

机器码可以非常精细地控制处理器。机器码能完成的功能包括:

• 数据的内存读取与写入。

• 向寄存器中传输数据和从寄存器中读取数据。

• 控制系统总线。

• 控制算术逻辑单元(ALU)、控制单元和其他组件。

这种低级别的控制意味着用机器码编写的应用程序可以非常强大和高效。然而,虽然记住并输入各种比特序列来执行特定任务很炫酷,但这种方式效率低下且容易出错。

2.从机器码到汇编代码

在机器码中,一系列的比特代表特定的操作。例如,0x81或10000001是一个指令,它将两个值相加并将结果存储在特定的位置。

汇编代码是对于人类而言可读的机器码。程序员可以使用add,而不是必须记住像0x81或10000001这样的十六进制或二进制字符串。add助记符已被映射到0x81,所以这个简略写法使得编程变得更容易,同时也不会失去使用机器码编程的任何优点。

将机器码翻译成汇编代码会使其更易于理解。例如,前面的“Hello World”示例机器码可以被转化为一系列易于理解的指令。

如果你对机器码有所了解,那么直接用它来编程可能很有趣,而且它有自己特定的适用场合。但在大部分时间里,这种做法既不高效也不实际。相比之下,使用汇编语言编程不仅能带来与直接使用机器码同等的好处,更重要的是,它更加实用。

一旦代码用汇编语言写好了,就能通过一个称为“汇编”的过程由汇编器转化为机器码。而已经是机器码的程序则可以通过反汇编器转换回汇编代码。

许多程序员并不直接使用机器码或汇编语言编写程序。相反,他们更喜欢使用更高级别的语言,这些语言能隐藏更多的细节。例如,以下伪代码就类似于许多高级过程式语言代码。

在编译过程中,这些高级语言会被转化成类似于下面的汇编代码:

然后,我们可以使用汇编器将汇编代码转换成计算机可以使用的机器码:

3.指令集架构和微架构

“计算机”这个词覆盖了广泛的系统。智能手表和台式计算机在工作方式上有许多相似之处。然而,它们的内部组件可能有很大的不同。

指令集架构(Instruction Set Architecture,ISA)描述的是运行程序的生态系统。ISA定义的因素包括:

• 寄存器:ISA规定了处理器是拥有单个寄存器还是拥有上百个寄存器。它还定义了这些寄存器的大小,即它们是包含8位还是128位。

• 地址和数据格式:ISA规定了用于访问内存中数据的地址格式。它还定义了系统一次可以从内存中获取多少字节的数据。

• 机器指令:不同的ISA可能支持不同的指令集合。它还定义了是否支持加法、减法、等于、停止等指令。

通过定义物理系统的功能,ISA也间接地定义了汇编语言。ISA规定了哪些低级指令可用,以及这些指令的功能。

微架构(microarchitecture)描述了特定的ISA如何在处理器上实现。图1.4给出了Intel Core 2架构的一个示例。

ISA和微架构共同定义了计算机架构。成千上万的ISA和成千上万的微架构意味着也存在成千上万的计算机架构。

定义

指令集架构(ISA)定义了寄存器、地址、数据格式和机器指令的工作方式。微架构则负责在处理器上实现ISA。ISA和微架构共同定义了计算机架构。

4.RISC与CISC计算机架构之比较

虽然存在成千上万的计算机架构,但它们大体上可以分为两大类。精简指令集计算(Reduced Instruction Set Computing,RISC)架构定义了一小部分比较简洁的指令。一般来说,RISC架构更便宜、更容易创建,而且硬件体积更小,功耗更小。

图1.4 Intel Core 2架构

相对而言,复杂指令集计算(Complex Instruction Set Computing,CISC)架构定义了更多的强大指令。CISC处理器的造价更高,创造难度更大,一般体积更大,功耗也更大。

虽然从客观角度来看,CISC架构似乎比RISC架构要差,但它的主要优势在于编程的简便性和高效性。让我们来看一个假想的例子:一个程序希望在RISC和CISC系统中将一个值乘以5。

在这个例子中,如果CISC处理器有一个能从内存中加载值并对其执行乘法运算,然后将结果存储在相同内存位置的乘法操作,那么它可以通过一条指令完成计算。但是,因为乘法运算太复杂,RISC处理器可能没有直接的乘法操作。相反,RISC可以从内存中加载值,将它和自身相加四次,然后将结果存储在同一内存位置。

RISC和CISC架构各有优点、缺点和使用场景。例如,一个CISC操作一条指令能够执行的任务,一个RISC操作可能需要100条指令才能达成。然而,一个CISC操作可能需要100倍的时间,或者需要100倍的功率。

现今,RISC和CISC架构均被广泛使用。常见的RISC架构实例包括:

• ARM(用于手机和平板计算机)。

• MIPS(用于嵌入式系统和网络设备)。

• PowerPC(用于原始Mac和Xbox360)。

在本书中,我们专注于研究x86汇编语言,这是一种CISC架构。目前,所有现代个人计算机以及服务器都在使用这种架构,并且它得到了所有主流操作系统(如Windows、Mac以及Linux)甚至游戏系统(比如Xbox One)的支持,这使其成为软件破解学习中最有力的一种。