装载有效地址指令,也就是lea,计算源操作数指定的地址,存储在目的操作数中(见表2.9)。它也可不修改源操作数的值,用在多个寄存器进行算术计算。
表2.9 lea指令
源操作数 目的操作数
reg8 mem8
reg16 mem16
reg32 mem32
jmp指令将控制转移至其操作数指定的地址。这个执行可以执行4种不同的跳转:近跳转、短跳转、远跳转和任务切换(见表2.10)。近跳转是发生在当前代码段内的跳转。短跳转是与当前地址相距-128 ~127地址内的跳转。远跳转是将控制转移到地址空间内具有与当前代码段相同优先级的段内。最后,任务切换跳转到不同的任务中的一条指令上。
表2.10 jmp指令
源操作数 目的操作数
rel8 N/A
rel16 N/A
rel32 N/A
reg16/mem16 N/A
reg32/mem32 N/A
ptr16:16 N/A
ptr16:32 N/A
mem16:16 N/A
mem16:32 N/A
jcc指令不是一个特定的指令,而是一系列条件跳转指令。根据使用的指令不同,条件也不同,但经常和test、cmp指令一起使用。表2.11显示了jcc使用的目的操作数。在表2.12中,你可以发现条件跳转列表和检查一个条件为真或假的标识。不必担心不明白这些标识,EFLAGS寄存器的说明将在指令说明后给出。
表2.11 jcc指令
源操作数 目的操作数
rel8 N/A
rel16 N/A
rel32 N/A
表2.12 条件跳转指令
指令 EFLAGS条件 描述
ja CF = 0 && ZF = 0 Jump if above
jae CF = 0 Jump if above or equal
jb CF = 1 Jump if below
jbe CF = 1 || ZF = 1 Jump if below or equal
jc CF = 1 Jump if carry
jcxz CX = 0 Jump if CX is zero
jecxz ECX = 0 Jump is ECX is zero
je ZF = 1 Jump if equal
jg ZF = 0 && SF = OF Jump if greater than
jge SF = OF Jump if greater than or equal to
jl SF != OF Jump if less than
jle ZF = 1 || SF != OF Jump if less than or equal to
jna CF = 1 || ZF = 1 Jump if not above
jnae CF = 1 Jump if not above or equal
jnb CF = 0 Jump if not below
jnbe CF = 0 && ZF = 0 Jump if not below or equal
jnc CF = 0 Jump if not carry
jne ZF = 0 Jump not equal
jng ZF = 1 || SF != OF Jump not greater
jnge SF != OF Jump not greater or equal
jnl SF = OF Jump not less
jnle ZF = 0 && SF = OF Jump not less or equal
jno OF = 0 Jump if not overfl ow
jnp PF = 0 Jump not parity
jns SF = 0 Jump not signed
jnz ZF = 0 Jump not zero
jo OF = 1 Jump if overfl ow
p PF = 1 Jump if parity
jpe PF = 1 Jump if parity even
jpo PF = 0 Jump if parity odd
js SF = 1 Jump if signed
jz ZF = 1 Jump if zero
从表2.12你可以看到非常多的条件跳转寄存器,它们都依赖于EFLAGS寄存器的的不同状态,现在我们就对这个先前没描述的内容探讨一番。EFLAGS寄存器是32位寄存器,包含一组状态和系统标识及一个控制标识。每个标识都由寄存器的一位表示,从位0到31,分别代表如下标识:
CF 进位标识,指明在算术操作中,寄存器的最高有效位是否有进位或借位。这个标识位用于无符号数算术。
PF 奇偶位,当结果的最低有效位个数为偶数个是置位
AF 调整位,如果操作结果有从第3位上借位或进位时置位
ZF 零标志位,操作结果为0时置位
SF 符号位,设为与结果最高有效位一样(带符号数的最高有效位是符号位)
TF 陷井位,当允许单步调试时,置位
IF 中断使能位,当标记的中断使能时置位,当清除中断标记时复位
DF 检测位,用于字符串操作中决定指令增还是减
OF 如果执行有符号数算术运算时有溢出则置位
IOPL(位12,13) I/O优先级位,指出当前运行任务的当前I/O优先级
NF 嵌套任务位,如果当前任务是与先前执行的任务关联时置位
恢复标志 控制处理器对调试异常的响应
VM 虚拟-8086标志,置位时启用虚拟8086模式
AC 对齐检查位,置位以启用内存引用的对齐检查
VIF 虚拟中断位,是IF标志位的虚拟映像,同VIP标志一起使用
VIP 虚拟中断位,用来决定中断是否被挂起
ID 标记位,用来决定CPU是否支持CPUID指令
位22到31当前被保留。
Call指令更像一个正式的跳转指令,它按本文前面所述的方式设置栈,当被执行的函数完成后,允许处理器在调用点恢复执行。
表2.13 call指令
源操作数 目的操作数
rel16 N/A
rel32 N/A
reg16/mem16 N/A
reg32/mem32 N/A
ptr16:16 N/A
ptr16:32 N/A
mem16:16 N/A
mem16:32 N/A
ret指令与call相反。它将元数据存储在栈上,弹出它并返回到那个地址(见表2.14)。可选的立即数指定执行返回后,弹出多少个字节的栈数据。
表2.14 ret指令
源操作数 目的操作数
N/A N/A
imm16 N/A
就像你看到的,现在我们已经熟悉很多指令了,它们中的绝大多数有很多不同的操作数,这又导致同一个指令会有不同的形式(因此操作码也不同)。这不是一个完整的指令参考――实际上,它只涉及皮毛。尽管如此,我们希望对很多平常使用的指令有点基础,并让你熟悉它们。如果读者不熟悉指令集的话,强烈鼓励你们查阅Intel开发者手册,特别是卷3A和3B。
总结
现在你至少熟悉了汇编语言和Intel体系。在一定程度上知道内存模型和工作模式如何工作,还获得了适当的基本知识,在此基础上可以继续理解其它内容。尽管如此,你可能还是在暗自想,“的确,我理解了一些汇编知识,但,逆向工程是什么?”好的,逆向工程是一个宽泛的定义,对不同的人,代表不同的含义。通常,它是把一个对人来说不可读或不可分析的应用程序变为可读或可分析的过程。有的人这么做是为了得到丢失的源代码,其它人这么做是为了复制专属产品,另一些人逆向恶意软件,以知道它们在做什么,最后,还有一些人是为了发现软件里面的漏洞或者脆弱点。
从本书的写作目的出发,可简单总结为,逆向工程是处理计算机可读的二进制文件,使用操作码来产生汇编语句,然后理解这些汇编语句,以帮助你完成你想达到的目的。从这个意义上,也可以说是,对逆向工程师,没有闭源软件。处理器看到每一个指令,逆向工程师亦是如此。
术语:
Malware 恶意软件
Packer 加壳器 见http://bbs.pediy.com/showthread.php?t=46907&page=2&highlight=packer
Binary files 二进制文件
Assemble 有时候译成汇编代码,视上下文
Opcode (operation code) 操作码
Operation mode 工作模式
Exploit 不译
Stack frame 栈帧(stack frame is created by assembly code,and it's a an area of memory that temporarily holds the arguments to the function as well as any variables that are defined local to the function.When the procedure is called, the stack frame is pushed onto stack.)栈帧是汇编代创建的一个临时内存区别,它与一个函数相关,存储函数参数或其它函数中的本地变量。当过程被调用时,栈帧就被弹入栈内。
--我自己的理解,栈帧就是当一个函数或过程调用时,与些过程或函数相关的所有存储在栈上的东西的集合(也就是一帧),比如函数参数,本地变量等等。上面的英文不是关于栈帧的英文权威解释,只是我在查询这个词意思是搜到的,但我觉得很确切。
Procedure prologue 过程序言
Procedure epilogue 过程结尾
At any rate, this chapter serves as an introduction to the physical layout of the Ý les, and
details aspects of the Ý les that a reverse engineer would Ý nd interesting and/or important.
Both of these Ý le formats have open documentation and, in places where readers Ý nd this
chapter lacking, they are strongly encouraged to read the speciÝ cations themselves