第61章 可疑的代码模型

61.1 XOR异或指令

像XOR op,op或者XOR EAX,EAX这样的指令通常用来将某个寄存器清零。只有当XOR指令的两个操作数不同的时候,它才进行真正的“异或”运算。这种实际意义上的异或运算,在常规应用程序很少见到,反而在加密算法中比较常见,即使是业余人员编写的程序也是如此。而如果XOR的第二个操作数是一个很大的数,那么这个程序就显得特别可疑。这种情况往往意味着它会进行加密或者解密、校验和等类型的复杂计算。

需要说明的是,18.3 节介绍的编译器采用的“百灵鸟”技术同样会生成大量的XOR指令。不过这些XOR指令和加/解密等科学运算无关。

我们可以利用下述AWK脚本处理IDA生成的指令清单文件(.lst),检索其中的xor指令:

gawk -e '$2=="xor" { tmp=substr($3, 0, length($3)-1); if (tmp!=$4) if($4!="esp") if ($4!="ebp")↙
    ↘ { print $1, $2, tmp, ",", $4 } }' filename.lst

值得注意的是,这种类型的脚本也适用于适配不正确的反汇编代码(可以参考本书第49章)。

61.2 手写汇编代码

当前的编译器都不会分配循环指令LOOP和位移循环指令RCL。从另外一方面来讲,喜欢直接手写汇编语言的编程人员非常熟悉这些指令。因此,如果你看到了这些指令的话,那么这部分代码十有八九由编程人员手工编写而来。本书附录A.6都将这些指令添加了“(M)”标记。

手写的汇编程序很少会具备完整的函数开头和函数结尾。

通常来说,人工手写的程序没有固定的参数传递方法。

举一个例子:Windows 2003操作系统的内核文件ntoskrnl.exe。

MultiplyTest proc near                    ; CODE XREF: Get386Stepping
             xor     cx, cx
loc_620555:                               ; CODE XREF: MultiplyTest+E
             push    cx
             call    Multiply
             pop     cx
             jb      short locret_620563
             loop    loc_620555
             clc
locret_620563:                            ; CODE XREF: MultiplyTest+C
             retn
MultiplyTest endp

Multiply     proc near                    ; CODE XREF: MultiplyTest+5
             mov     ecx, 81h
             mov     eax, 417A000h
             mul     ecx
             cmp     edx, 2
             stc
             jnz short locret_62057F
             cmp eax, 0FE7A000h
             stc
             jnz short locret_62057F
             clc
locret_62057F:                            ; CODE XREF: Multiply+10
                                          ; Multiply+18
             retn
Multiply     endp

实际上,只要查看WRK[1]v1.2的源代码就会发现:这部分指令确实来自于手写的汇编语言源文件WRK-v1.2\base\ntos\ke\i386\cpu.asm。


[1] WRK是Windows Research Kernel(Windows研究内核)的缩写。