购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 数据表示

不同于人类,计算机运行在二进制上,因此,大部分逆向工程工具并不以十进制系统显示数字。理解一款应用程序正在做什么,需要理解它正在处理的数据以及这些数据可能的表示方式。

2.3.1 数字系统的基数

计数系统中的基数定义了用于表示数字的符号数量。大多数人都在基数为10的系统下进行数学计算,这个系统的符号是0、1、2、3、4、5、6、7、8和9。

然而,这并不是唯一的选择。只要有足够的符号来表示值,就可以使用任何基数。例如,五进制(基数为5)使用0~4的符号,而八进制(基数为8)使用0~7的符号。

提示: 数字的基数可以用下标表示。例如,10 10 是写成十进制(基数为10)的数字,而10 2 则是写成二进制(基数为2)的数字。

对于大于10的基数,我们也会使用字母作为符号。例如,十一进制就会增加字母a,那么就会有以下这些符号:0、1、2、3、4、5、6、7、8、9和a。十六进制则会用到这些符号:0、1、2、3、4、5、6、7、8、9、a、b、c、d、e和f。

提示: 在十六进制中,字母的大小写无关紧要,所以a和A都代表十进制数值10。

在每个进制中,我们都需要有能力表示比基数更大的数值。为了做到这一点,我们使用多位数。

计算机是二进制系统,它们利用1和0进行所有的数据存储和处理操作。但是,这种方式效率不高,写起来很麻烦。例如,2014 10 的值等同于11111011110 2

虽然计算机使用的是二进制,但为了方便阅读,工具经常会用十六进制来显示数值。十六进制的数值可能以以下几种方式表示:下标方式(1d 16 )、前缀方式(0x1d)或后缀方式(1dh)。

十六进制的一个优点是,它的数值是2的幂。这意味着可以通过字符替换便捷地将值在二进制和十六进制之间转换。图2.1展示了每个十六进制符号如何映射到十进制和二进制。

图2.1 十六进制符号与十进制和二进制的映射

例如,我们来看一下二进制数值11111011110 2 。每一个十六进制位都表示四个二进制位,因此,这个数值可以从右向左分成三组:111、1101和1110。根据图2.1,我们可以看出这三组分别等于十六进制的数字7、d和e,所以,整个数值可以用0x7de来表示。

虽然这些进制转换可以手动完成,但使用工具通常更快且更准确。图2.2展示了使用Windows计算器进行进制转换的示例。

2.3.2 位、字节和字

位(bit)是计算机使用的基本单位。但是,位太小,提供的应用空间有限。因此,计算机并不操作和处理单一的位,而是将字节(byte)作为最小的内存单元来运作。在所有现代系统中,一个字节由8位组成。

尽管字节比位大,但它们对于很多操作来说仍然太小。计算机被设计为一次最佳地访问某一确定数量的字节。这个数量的字节被称为字(word),通常是2的幂,并且在不同的计算机之间可能会有所不同。例如,微控制器的字比较小,通常使用包含1个或2个字节(8位或16位)的字。通用计算机的字通常为4个或8个字节(32位或64位)。

图2.2 Windows计算器中的进制转换

位、字节和字是处理内存时最重要的术语,但并非唯一的。以下是一些常用术语:

●位:取0或1。

●字节:8位。

●半字节(nibble):4位。

●双字节:16位。

●四字节(quad-byte):32位。

●字:取决于架构,一定数量的字节。

●半字(halfword):一半的字。

●双字(doubleword,简称DWORD):两个字。

●四字(quadword,简称QWORD):包含四个字的单位。

●八字(octoword)、双四字(double quadword,简称DQWORD):由八个字组成。

本书主要研究32位架构。在传统的32位架构中,一个字是32位。但这是x86架构的一个独特之处。由于x86保持了与原始16位架构的向后兼容性,因此在x86架构中,一个字是16位,而一个双字则是32位。

提示: 在32位x86架构中,一个字节是8位,一个双字是32位。

2.3.3 处理二进制数

逆向工程通常涉及处理跨越多个字节的大二进制数。在处理这些数时,正确解释二进制字符串所代表的数需要理解零扩展(zero-extension)、位和字节的重要性,以及字节序(endianness)等概念。

1.零扩展与可读性

二进制数值通常会按照架构的字长进行零填充或零扩展。在32位架构中,这意味着要在数值左侧添加0,直到它的长度达到32位。例如,数值11001 2 会被零填充为00000000000000000000000000011001 2

注意,为了提高可读性,这些位被分成四位一组或八位一组。这就像在十进制中每三位数之间添加逗号(比如1,000)一样。当数值被写成十六进制时,它们也被按字节分组,每个字节有两个字符。例如,数值4D2 16 (等同于十进制的1234 10 )可以被写作04 16 D2 16

2.位和字节的重要性

在二进制数中,位和字节可以根据它们在数字中的相对权重进行标记。图2.3展示了一些常见的标签。

图2.3 位和字节的重要性标签

在00000000000000000000000000011001 2 中,最低有效位(Least Significant Bit,LSB)是最右边的位,其值为1。最高有效位(Most Significant Bit,MSB)是最左边的位,其值是0。当我们从二进制转换为十进制时,最高有效位会被乘以2的31次方,而最低有效位则会被乘以2的0次方。

除了最高有效位和最低有效位,还有最高有效字节和最低有效字节的概念。在00000000000000000000000000011001 2 中,最低有效字节值为00011001 2 ,而最高有效字节值为00000000 2

位和字节也可以根据其相对于值两端的接近程度来标定。例如,邻近最低有效位(LSB)的位和字节被称为低阶位或低阶字节,而靠近最高有效位(MSB)的位和字节是高阶位或低阶字节。

3.字节序

在计算机内存中,数据是以字节的形式储存的。多数数据类型需要占用多个字节,例如,整型(int)就是32位或4字节。

字节序描述了这些字节在内存中的存储顺序。在小端序(little-endian)系统中,最低有效字节先被存储(在最低地址处)。在大端序(big-endian)系统中,最高有效字节先被存储(在最低地址处)。

例如,我们需要理解数值1337 10 。这个数值在二进制中表示为00000000000000000000 0101 0011 1001 2 ,在十六进制中表示为0x00000539。图2.4展示了这些数值是如何存储在内存中的。

图2.4 字节序

无论系统的字节序如何,与变量相关的地址都是使用的最低地址或基地址。在小端序和大端序系统中,这在本例中都是地址1828。

定义

在小端序系统中,最低有效字节位于最低地址。在大端序系统中,最高有效字节位于最低地址。

本书主要研究的是x86架构,它是小端序系统。因此,一块数据的最低有效字节将位于基地址偏移0处。这对人类来说看起来是“反向”的,因为我们按照大端序进行阅读和写作。

提示: x86是一个小端序架构,所以最低地址包含最低有效位。 CekKfIIorjw3MPsBfTBwOMEFmfBQTbFeO7lkys9sm3atvj62nzZVx9mHpiGZkY4C

点击中间区域
呼出菜单
上一章
目录
下一章
×