在这个 IDA 系列教程中,会由浅入深地讲解包括:IDA基本操作、静态及动态逆向分析、脱壳破解、漏洞开发等。
以 windows 程序为例(x86汇编)。
将会比较少的介绍基础知识,如果遇到不能理解的可看前一个系列与《CSAPP》。

MOV

以 VEViewer.exe 为例。
看第一行与最后一行的 mov 指令的区别。
是将 0x46FC50 地址上储存的内容放入 eax。
是将 0x46FC50 放入 ecx。
因此在 IDA 中,地址前面有 OFFSET 这个词时,指代的是这个地址本身的数值,而没有 OFFSET 这个词时,指代的是这个地址上存储的内容。
mov edx, [eax+8] 这种有方括号的也是表示取地址内容的意思(将地址为 eax+8 处的内容放到 edx 里面)。

XCHG

XCHG A, B 指令将 A 与 B 的值互换。
 

栈指令

PUSH 将一个对象保存在栈的顶部(压栈)。
notion image
POP 将最后存入栈顶的对象取出。
notion image
 
看 CRACKME.EXE 程序。
aCrackmeV10 以 a 开头,说明它是一个 ASCII 字符串。
双击字符串名称可以跳转到下面地方:
在一般 C 语言源代码中,字符数组是这样定义的:
IDA 用了 2 行对这个字符数组进行描述,第一行说明这个字符串是 char[] 类型,第二行说明改字符串内容是“Crackme v1.0”,最后的 0 表示字符串的结尾。
D键会改变 windowname 变量的数据类型,强制 IDA 不将它视作字符数组而作为 db 或者说字节。
改变之后,虽然字符串内容不变,但是引用该字符串的地方会发生变化,比如:
将字符串类型改成 byte 数据类型后,这里会变成 push offset byte_4020E7
A键将其转换为 ASCII 字符串,恢复原状。
当发现其他作为单独字节显示的字符串时,都可以进行该操作。找到字符串的起点按A键,使显示更加易读。
一般在向函数传递参数的时候,都会使用 PUSH offset xxxxx 指令,将字符串的地址传递给函数。如果没有 offset 关键词,传递进去的就是 0x402110 地址上存储的内容,就是字符串的具体字节 55 4E 45 4D。但是 API 函数不是这样运行的,他们一般接受指针或者字符串的起始地址作为参数。
 

数据段/代码段

在以上的指令中,DS:这个标记表示程序将在数据区块(DS=DATA)的内存上写入。在讨论结构体的章节将会研究相应内容。而现在只要明白程序将把这个字符串起始的地址存储在数据区块上。
 

LEA

LEA 即 LOAD EFFECTIVE ADDRESS。
LEA A, B指令将 B 的地址传递给 A。
该指令不会获取 B 存储的内容,只会传递地址或者后一个操作数的运算结果。这种方法普遍运用于获取变量参数的地址。
看 VEViewer.exe:
这条指令使用了 LEA ,将这个栈上的地址传递出来,如果是 MOV 指令,传递出来的则是保存在这个地址的内容。
LEA 指令尽管使用了中括号,但它只计算中括号中的表达式然后传递地址而不读取其中的内容。
通常 EBP 寄存器用来存储的栈的基础地址,通过在 EBP 值加上或者减去一个常量来获得每一个函数参数和局部变量的地址。
[ebp+var_C]处右键单击,可以查看这个变量地址计算的表达式,按Q键可以在反汇编窗口中显示为[EBP-0Ch]。
在程序运行时 LEA 在获取这个函数栈的基础地址,减去 0Ch 计算出 EBP-0Ch 的取值,得出这个变量的实际地址。
LEA 也可以用于将中括号中的运算结果传递到目标寄存器,而不会读取结果地址上存储的内容。
例如: LEA EAX,[4+5]指令将运算结果 9 传给 EAX,而不会像 MOV EAX,[4+5] 指令那样将地址 0x9 上存储的内容传给 EAX。
掌握 LEA 的用法,并掌握和 MOV 用法之间的区别是很重要的。LEA 获取变量地址,MOV 获取变量地址上存储的值(OFFSET 除外)。
 

整数运算指令

ADD

ADD A,B 指令将 B 的值与 A 相加,并将结果保存到 A。
A 可以是一个寄存器或者内存值。
B 可以是一个寄存器、一个常量或者内存值。
在同一条指令中,A 和 B 不能同时是内存值。
如果 ECX = 10000,加上常数 4,结果是 10004,结果重新保存到 ECX 当中。
假设 ECX = 0x10000 那么加上 30 就是 0x10030 ,如果这个地址保存的数是 100,加上常数 0xffffffff 也就是-1,结果是 99, 并且保存到 0x10030 地址上。
dword 表示 ecx+30h 处储存的是一个 dword 类型的值。
 

SUB

SUB A,B 这个指令和 ADD 指令一致,只不过它是对两个操作数相减,最后结果保存到 A。SUB 允许的操作数组合和 ADD 是一样的。
 

INC/DEC

对一个寄存器或者内存值±1 。这是加减操作的一个特例。一般这两个指令用来对计数器±1。
 

IMUL

IMUL 是带符号整数乘法指令,这里介绍两种使用方式。
IMUL A,BIMUL A,B,C
第一种对 A 和 B 相乘,结果返回给 A。
第二种方式对 B 和 C 相乘,将结果返回给 A。
在这两种方式下,A 只能是一个寄存器,B 可以是寄存器或者内存值(第一种方式下可以是常数),而 C 只能是个常数。
例如:
 

IDIV

指令中,仅仅指定了除法的除数。被除数没有指定,因为存放的地方是固定的。
在 32 位运算中,EDX 和 EAX 组成一个 64 位数,EDX 在高位,EAX 在低位。这个 64 位数除以 A 后,商返回给 EAX,余数返回给 EDX。
假如 EAX = 5,EDX = 0,ECX = 2,那么 5÷2 的结果是 2,保存到 EAX,余数 1 保存到 EDX。
 

逻辑运算指令

AND/OR/XOR

AND A,B 对 A 和 B 进行与运算,将最终结果保存到 A 。对于 OR 和 XOR 运算也是一样的。
A 和 B 可以是寄存器或者内存值,但同一条指令中 A 和 B 都是内存值是不允许的。
最常用的例子对同一个寄存器 XOR(异或)运算,将它的值清零。例如,XOR EAX,EAX

NOT

将 A 所有的位取反然后保存到 A。

NEG

将 A 转变成 -A。NEG 运算和按位取反不一样,按位取反多减了 1。

SHL/SHR

SHL A,BSHR A,B 中 A 是一个寄存器或内存值,B 是一个常数或者一个 8位寄存器。这两个指令将操作数按位向左或向右偏移,缺少的位用 0 来填补。这是逻辑左移与右移,算术左移与右移是 SALSAR
还有 2 个类似的指令 ROL 和 ROR,指令会将每个比特偏移一定的位置,但是一端超出的字节会重新返回给另一端。
 

JMP

这个指令经常会用于 patch 执行流程,很重要。
EIP 寄存器指向下一条将要执行的命令,执行完毕后,EIP 指向再下一条。
但是程序本身也有一些指令可以控制执行的路径,跳转到一些预期的位置。
JMP SHORT 指令是一个两字节的短程跳转指令,只能向前或者往回跳转。
第一个字节 EB 是跳转操作码(OPCODE)。跳转的方向由第二个字节的值确定。
这种跳转是有距离限制的。
这里的 EB 是 JMP 的操作码,这条指令将会向前跳转到指令结束位置后的 5 个字节。
指令的起始地址加上指令本身的长度(2 字节)在加上第二个字节中的跳转距离(5 字节):
在IDA的视图左侧,也可以看到跳转箭头指向了 0x40132b 的位置。
显然,这个跳转距离用一个字节表示的话不是一个很大的范围。最大的正向跳转距离是 0x7f。
使用短跳转只能在当前地址的附近跳转,无法跳转到所有的地址。所以程序会使用长跳转。
notion image
图上显示了一些长跳转,图中 loc_ 表示那一条指令是一般指令。
长跳转的计算公式(E9 是 opcode):
终点指令起始地址 - 起点指令起始地址 - 5
说明操作数占据4个字节。
 

有条件跳转

一般来说,程序需要对一些值的比较来决定程序执行的路径。
例如:CMP A,B 对 A 和 B 进行比较,根据比较的结果程序将会进行某些操作。如果是另一种结果则进行不同的操作。
一般来说,比较会改变标志寄存器 EFLAGS 的状态,根据这个状态条件跳转指令会决定接下来如何执行。
notion image
图中是一个 JZ 条件跳转的例子。如果比较触发标志寄存器 EFLAGS中的 Z 或者说 Zero 标记,将执行跳转。例子中,如果 EAX 和 EBX 相等将执行跳转。CMP 指令类似于 SUB 指令,只不过不保存计算结果。
CMP 对这两个寄存器相减,如果它们相等,那么结果就是 0,就触发了标志寄存器中 Z 标记,JZ 指令检测到这个标记然后进行跳转。
如果触发 Z 标记,就会执行图中的绿色箭头路径,如果没有触发,那么就执行红色箭头路径。
条件跳转指令有很多种,但是都很好理解,找个图看看即可。
 

CALL/RET

CALL 指令用来调用一个函数。RET 指令用来返回调用这个函数的指令的下面一条指令处。
图中有一个 CALL 调用指令,程序将跳转到 0x4013d8 去执行这个函数。 在 0x4013d8 这个地址前面的sub_表示这里是一个函数。
CALL 指令会将返回的地址 0x40123d 保存到栈上,有兴趣去看看栈帧结构。
sub_4013D8函数最后会执行 RET 指令,跳转到栈上保存的返回地址 0x40123d 处,就是调用这个函数指令的下一条。
Loading...