汇编指令简介
前言
用OD玩了几个crackme,要通过验证,就需要定位到生成序列号的代码段。基本思路有两个方向,一是顺着输入数据流走,既然验证是跟输入有关的,那么输入数据必定会参与到序列号验证过程中;二是根据软件本身存在的一些字面特征(如弹出验证通过或失败对话框之类的),再反方向顺藤摸瓜之。
内存操作
NOP (无操作)运行这条指令不会对寄存器,内存以及堆栈造成任何影响。
PUSH 将操作数压入堆栈中。
PUSHAD 指令把所有通用寄存器的内容按一定顺序压入到堆栈中
POP 出栈:它会取出堆栈顶部的第一个字母或者第一个值,然后存放到指定的目标地址内存单元中。
POPAD 该指令与PUSHAD正好相反,它从堆栈中取值,并将它们放到相应的寄存器中。
MOV 该指令将第二个操作数赋值给第一个操作数,例如: MOV EAX, EBX; EBX值赋值给EAX。
LEA 取地址指令,类似于MOV指令, 但是第一个操作数是一个通用寄存器,并且第二个操作数是一个内存单。
XCHG 交换 寄存器/内存单元 和 寄存器 该指令交换两个操作数的值,例如:XCHG EAX,ECXEAX的值将被存放到ECX中。
数学指令
INC和DEC 这两个指令分别是执行增加和减少的操作,如果是INC指令的话,就加1,如果是DEC指令的话,就减1。
ADD ADD指令有两个操作数,相加后的结果存放到第一个操作数中。ADD EAX,1等价于INC EAX。
ADC 带进位的加法,在这种情况下,两个操作数的和加上进位标志的值,结果存放到第一个操作数中。
SUB 这个指令与ADD刚好相反-它将第一个操作数减去第二个操作数的值存放到第一个操作数中。
SBB 该指令跟ADC正好相反,它计算两个操作数的差值,并且还要减去进位标志,结果存放到第一个操作数中。
MUL 无符号数的乘法,有两种乘法,第一个种是MUL,这种是无符号数乘法,只有一个操作数,另一个操作数是EAX,结果存放到EDX:EAX中。
IMUL 有符号数的乘法,IMUL指令用法类似于MUL。IMUL ECX该指令将有有符号数ECX乘以EAX,结果存放到EDX:EAX中。
DIV 除法指令。被除数和操作结果商放在EAX中,余数放在EDX中。
CDQ 本来EAX中有个值,正或负都可以,CDQ 把这个32位扩展成64位。变成EDX:EAX的形式,其中EDX中的值是EAX中的最高位,也可以说是符号位。很久前,指令集规定除数必须是被除数的一半长,就一直沿用下来。IDIV有符号除法 除数是32位,那么被除数当然需要64位了,然后就用EDX来扩展EAX的符号位,这样既不改变EAX的值,又扩展成64位。
逻辑操作
AND、OR、XOR 、NOT 与、或、异或、非
比较和条件跳转
CMP 该指令是比较两个操作数,它相当于SUB指令,但是相减的结构并不保存到第一个操作数中。只是根据相减的结果来改变零标志位的,当两个操作数相等的时候,零标志位置1。CMP EAX, ECX,EAX与ECX相减,它们本身的值并不改变,只是根据它们相减的结果来决定零标志位Z是否置1。
TEST 逻辑比较,该指令在一定程序上和CMP指令时类似的,两个数值进行与操作,结果不保存,但是会改变相应标志位(比如说,SF,ZF,PF标志位),程序可以根据结果来决定是否跳转到相应的分支。下面有几个例子:TEST EAX,EAX。你会说,如果EAX与自己做比较呢?用这个指令,可以确定EAX是否等于0。
JMP – 跳转 JE, JZ – 结果为零则跳转 JNE, JNZ – 结果不为零则跳转
JS – 结果为负则跳转 JNS – 结果不为负则跳转 JP, JPE – 结果中1的个数为偶数则跳转
JNP, JNPE – 结果为1的个数为奇数则跳转 JO – 结果溢出了则跳转 JNO – 结果没有溢出则跳转 JB, JNAE – 小于则跳转 (无符号数)
JNB, JAE – 大于等于则跳转 (无符号数) JBE, JNA – 小于等于则跳转 (无符号数) JNBE, JA – 大于则跳转(无符号数)
JL, JNGE – 小于则跳转 (有符号数) JNL, JGE – 大于等于则跳转 (有符号数) JLE, JNG – 小于等于则跳转 (有符号数)
JNLE, JG – 大于则跳转(有符号数)
转移指令
CALL 转移到指定的子程序,操作数即为目标地址。将当前的EIP压入栈中并转移,相当于PUSH EIP, JMP [] 。
RET 返回调用程序,相当于POP EIP。