人类在现实生活中喜欢使用整数。编程人员也是人,他们同样喜欢用10、100、1000这样的整数。
熟悉的反编译工程师都会明白,与之对应的十六进制数的关系是:10=0xA;100=0x64;1000=0x3E8而10000=0x2710。然而,在二进制层面这些数字都不算太“整”。
从二进制层面来看,更为常用的整数则是0xAAAAAAAA(1010101010101010)和0x55555555 (0101010101010101)这类特征明显的常量。以常数0x55AA为例:引导扇区、主引导扇区MBR以及IBM兼容扩展卡的ROM(只读存储单元)等关键数据都会使用这个常量。
一些算法,特别是某些加密算法,常常使用某些特殊的常数,如果我们使用调试工具IDA就能很容易发现这一点。
以MD5算法为例,其内部变量初始值分别是:
var int h0 := 0x67452301
var int h1 := 0xEFCDAB89
var int h2 := 0x98BADCFE
var int h3 := 0x10325476
也就是说,如果某段代码连续出现了上述四个常量,那么这段代码很可能就与MD5的算法相关。
而另外的例子则是CRC16/32的算法,其预置的常数表经常如下所示。
指令清单59.1 Linux/Lib/crc16.c
/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
u16 const crc16_table[256] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
…
如需详细了解 CRC32算法,请参考本书的第37章。
很多文件在文件头使用特定的魔数来表示其文件格式,这些魔数可以是一个字节或者多个字节的组合(https://en.wikipedia.org/wiki/Magic_number_(programming)
)。
比如,我们熟知的,所有的Win32以及MS-DOS格式的可执行文件的开始处总是“MZ”这两个字符。
而在标准的MIDI文件则必须以“MThd”这4个字符开头。因此,那些需要使用MIDI文件的程序,基本上都会检测目标文件的头4个字符是不是“MThd”。如果用程序来表示,则可能是下面这个样子的:(注意:buf是内存缓冲区的起始地址)
cmp [buf], 0x6468544D ; "MThd"
jnz _error_not_a_MIDI_file
当然,数据比较函数同样可以用来验证文件头中的魔数。常用的函数有:比较内存块的memcmp()函数,或者CMPSB一类的比较指令(可以参考本书附录A.6.3)。
一旦发现某个程序开始检测其他文件的魔数标识,我们就可以确信它已经加载了某种类型的目标文件。不止如此,我们还可以解读出文件操作的缓冲区以及它使用缓冲区的方式方法等信息。
网络协议同样使用了魔术。比如,DHCP协议的网络数据就会用到魔数0x63538263—这个魔数叫做magic cookie。所有符合DHCP协议的数据包都必须使用这个魔数。如果我们找到了这个魔数,我们就可能确定此处代码可能用于实现DHCP协议。不仅如此,能接受DHCP包的程序都必须验证这个魔数,也就是与它做比对。
比如说,我们以Windows 7操作系统(64位操作系统)中的文件dhcpcore.dll文件为例,我们可以在这个文件中搜索这个魔数。结果发现了2次,出现在两个函数中,其名称分别是DhcpExtractOptionsForValidation()和and DhcpExtractFullOptions()。
指令清单59.2 dhcpcore.dll (Windows 7 x64)
.rdata:000007FF6483CBE8 dword_7FF6483CBE8 dd 63538263h ; DATA XREF:↙
↘ DhcpExtractOptionsForValidation+79
.rdata:000007FF6483CBEC dword_7FF6483CBEC dd 63538263h ; DATA XREF:↙
↘ DhcpExtractFullOptions+97
以下列出在该程序文件中是如何使用这个魔数的:
指令清单59.3 dhcpcore.dll (Windows 7 x64)
.text:000007FF6480875F mov eax, [rsi]
.text:000007FF64808761 cmp eax, cs:dword_7FF6483CBE8
.text:000007FF64808767 jnz loc_7FF64817179
指令清单59.4 dhcpcore.dll (Windows 7 x64)
.text:000007FF648082C7 mov eax, [r12]
.text:000007FF648082CB cmp eax, cs:dword_7FF6483CBEC
.text:000007FF648082D1 jnz loc_7FF648173AF
在单个文件里搜索常数时,可以使用IDA的搜索功能。其快捷键是ALT-B或ALT-I。
在海量文件检索常量时,可以使用笔者开发的小工具—binary grep (https://github.com/yurichev/ bgrep
)。它同样可以检索非可执行文件中的特定信息。