NOP
运行该指令不会对寄存器、内存以及堆栈造成任何影响,英文意思是”无操作”,它没有特殊的用途
例如,你用一个短指令来替换一个长指令的话,如果处理器没有错误多余的空间将会被NOP填充
适当数目的nop指令可以将其他指令完全替换掉
PUSH(入栈)
将操作数压入堆栈,PUSH操作后会更新ESP指向新的栈顶地址,可操作数值、寄存器和内存地址
堆栈保存数据窗口中颠倒过来的值,即倒序放置,读/写的内容在内存中倒序是处理器的特点之一
如data(CA 20 40 00)则stack(00 40 20 CA)
PUSH 401000 将数据401000压入栈
PUSH [401000] 取内存地址为401000中的数据压入栈
POP(出栈)
它会取出堆栈顶部的第一个字母或者第一个值,然后存放到指定的目标地址内存单元中
POP操作后会更新ESP指向新的栈顶地址
如,POP EAX从栈顶中取出第一个值存放到EAX中,随后的一个值随即变成栈顶
PUSHAD
指令把所有通用寄存器的内容按一定顺序压入到堆栈中,相当于
"PUSH EAX,PUSH ECX,PUSH EDX,PUSH EBX,PUSH ESP,PUSH EBP,PUSH ESI,PUSH EDI"
PUSHA 等价于 "PUSH AX, CX, DX, BX, SP, BP, SI, DI"
POPAD
与PUSHAD正好相反,它从堆栈中取值,并将它们放到相应的寄存器中,相当于
"POP EDI,POP ESI,POP ESP,POP ESP,POP EBX,POP EDX,POP ECX,POP EAX"
POPA 等价于 "pop DI, SI, BP, SP, BX, DX, CX, AX"
PUSHA,POPA/PUSHAD,POPAD在16位程序中使用,我们不感兴趣,OllyDbg是一个32位调试器
MOV
该指令将第二个操作数赋值给第一个操作数,如: MOV EAX, EBX
MOVSX(带符号扩展的传送指令) p1 = 第一操作数/p2 = 第而操作数
p2是寄存器也可能是内存单元,p1的位数比p2多,p2的符号位填充p1剩余部分
如:
EAX = 00000000,BX = F000
MOVSX EAX,BX
执行后EAX = FFFFF000,因为F000是负数,所以EAX的高位用F填充
EAX = 00000000,BX = 7FFF
MOVSX EAX,BX
执行后EAX = 00007FFFF,因为7FFF是正数,所以EAX的高位用0填充
16位范围0000~FFFF, 正 0000~7FFF, 负8000~FFFF
32位范围00000000~FFFFFFFF, 正 00000000~7FFFFFFF, 负80000000~FFFFFFFF
MOVZX(带0扩展的传送指令)
MOVZX类似于MOVSX,但是这种情况下,剩余的部分不根据第二个操作数的正负来进行填充
剩余的部分总是被填充为0
LEA(取地址指令)
类似于MOV指令, 但是第一个操作数是一个通用寄存器,并且第二个操作数是一个内存单元。
当计算的时候要依赖于之前的结果的话,那么这个指令就非常有用。
如:
LEA EAX, DWORD PTR DS:[ECX+38]
在这个例子中,LEA指令就计算ECX + 38的值,然后将计算的结果赋值给EAX
因为完成的是赋值操作,所以我们会认为操作数是内存单元中的值,
但实际上,操作数仅仅是内存单元的地址,而不是里面的内容
XCHG (交换 寄存器/内存单元 和 寄存器)
该指令交换两个操作数的值
如:
XCHG EAX,ECX
EAX的值将被存放到ECX中,反之亦然,也可以交换寄存器和内存单元的值