1、普通指令
mov:传送字或字节
mov eax,1 -- 将1存入寄存器eax中
lea: 将内存编号存入寄存器
lea左操作数必须是16位或者32位寄存器,右操作数必须是一个内存地址
lea和mov区别在于,mov除了不能从内存到内存,并且左操作数不能是立即数其他都可以
例如:
mov:
lea:
add:加法
add eax,2 -- 将eax中的值加2再放到eax中
sub:减法
sub eax,2 -- 将eax中的值减2再存入eax中
**inc:加1 dec:减1 **
and:与运算,都为1才为1
假设eax=0x1 ebx=0x2
eax:0001 ebx:0010
0001
0010
0000 因为上下都为1才为1,所以结果为0
or:或运算,都为0才为0
or eax,ebx
eax=0x1=0001 ebx=0x2=0010
0001
0010
0011 上下都为0才为0,所以这里结果为3
xor:异或运算,多用于加密解密,相同为0不同为1
** **假设eax=0x1=0001 ebx=0x2=0010
0001
0010
0011 结果为3
not:按位取反,单目运算符(只有一个操作数)
假设eax=0x1=0001
not eax
0001
1110 结果为14
**在这里我使用的是32位的寄存器,所以发生了以下情况**
因为我们上面的not eax
** eax=0x1=0001 我们是按四位半个字节来看的,但是这里最低操作就是一个字节,所以这里结果是不能等于14的,但是大家知道14是怎么来的就行了**
** 下面我们操作一个字节试试(0x是十六进制前缀)**
** **假设eax=0x11223344 四个字节--两个字
那么后面的0x3344就是ax中的内容,ax是十六位寄存器
ax又可以分为ah(高八位)和al(低八位) (high与low)
**ah和al都是一个字节的,这里我们操作al方便观看**
** **假设al=0x1=0000 0001
not al
0000 0001
1111 1110 结果是FE
SAL:算术左移、SHL:逻辑左移
算术左移和逻辑左移一样都是右边补0: 比如 00101011
算术左移一位:01010110
逻辑左移一位:01010110
对于二进制的数值来说左移n位等于原来的数值乘以2的n次方
比如00011010十进制是26,左移两位后是01101000转成十进制是104恰好是26的4倍。
这种倍数关系只适用于左移后被舍弃的高位不含1的情况,否则会溢出。
这里就不测试了。
SAR:算术右移、SHR:逻辑右移
逻辑右移很简单,只要将二进制数整体右移,左边补0即可
如10101101逻辑右移一位为01010110
算术右移符号位要一起移动,并且在左边补上符号位,也就是如果符号位是1就补1符号位是0就补0
负数的符号位是1、正数的符号位是0
所以算术右移就需要先判断是有符号类型的数值还是无符号类型的
例如:
**有符号的情况下:**
SAR 10101101,1
结果:01010110
SHR 10101101,1
结果:01010110
**有符号的情况下:**
SAR 10101101,1
结果:11010110
SHR 10101101,1
结果:01010110
这里就不测试了。
2、JMP指令
JMP指令就是用来修改EIP的值的,我们知道寄存器EIP中存放着下一次将会执行指令的地址,所以我们可以通过JMP指令修改程序下一次执行的内容。
![](https://img-blog.csdnimg.cn/612f29062fa0491eaafb793bbed7691b.png)
结果如下:
3、MOVS指令
**movs通过移动字节数分为movsb、movsd、movsw 分别是byte、dword(双字)、word(字)的缩写。**
** movs操作到的寄存器就是ESI和EDI**
** ESI:src 源寄存器**
** EDI:dst 目标寄存器**
** movs根据字节大小将源寄存器中的内容对应地址中的内容赋值给目标寄存器中的内容对应地址中的内容**
** **movs byte ptr es:[EDI],byte ptr ds:[ESI] 简称:movsb
movs word ptr es:[EDI],word ptr ds:[ESI] 简称:movsw
movs dword ptr es:[EDI],dword ptr ds:[ESI] 简称:movsd
**注意看上面移动的是地址中的值!!!**
例如:
**我们下面测试中,ESI对应地址中的值始终是0x11223344,EDI对应地址中的值是0**
movsb:复制一个字节
执行:
movsw:复制一个字
执行:
movsd:复制双字
执行:
我们可以看到每次操作完esi和edi之后,esi和edi的值都往上加了
这是因为这时候我们的EFL标志寄存器中的DF位是0,如果改成1,那么操作完esi和edi之后,esi和edi中的值就会减,这里就不测试了,知道有这么回事就行。
4、STOS指令
**根据字节大小将al/ax/eax中的值存入到[edi]指定的内存单元**
** **STOS BYTE PTR ES:[EDI] 简写为:STOSB
STOS WORD PTR ES:[EDI] 简写为:STOSW
STOS DWORD PTR ES:[EDI] 简写为:STOSD
下面的测试中,我们的eax中始终存放0x11223344:
STOSB:
![](https://img-blog.csdnimg.cn/bc445ac332384983a8d6216f2778b9a8.png)
执行:
![](https://img-blog.csdnimg.cn/e5aa1c80c14c427ab4816fbfcdb799b3.png)
** STOSW:这里我们修改以下DF位,让EDI被操作之后值减1 **
执行:
STOSD:
执行:
5、PUSH、POP指令
PUSH是入栈指令,将后方内容压入堆栈中
POP是出栈指令,将后方内容从堆栈中取出
**PUSH后面的操作数可以是立即数也可以是寄存器也可以是内存**
** POP后面的操作数可以是寄存器可以是内存,但不能是立即数,因为数字无法存放内容**
例子:
** PUSH eax:将eax压入当前堆栈,然后esp栈顶指针-4**
执行:
**所以一个push将相当于**
** mov dword ptr ds:[esp-4],eax**
** sub esp,4**
** 这两个指令 **
** pop ecx**
** 将当前栈顶的内容取出放在ecx里并且栈顶指针+4**
如下:
执行:
**一个pop就相当于**
** mov ecx,dword ptr ds:[esp]**
** add esp,4 **
6、REP指令
** rep指令就是重复执行这个指令多少次,重复的次数次数就是ecx寄存器中的内容**
** **例如:
**(这里图片中写错了,ecx中的0x10是16次)**
执行:
7、CALL与RETN指令
**call指令会跳到对应的地址,并把当前指令下一行的地址压入堆栈**
** retn会将跳转到当前对战中的地址**
** call:**
注意:这里执行必须F7,至于为什么请观看我另一篇文章《Fake F8》
** 执行:**
** 一个call相当于:**
** JMP 401230**
** mov dword ptr ds:[esp-4],401217**
** sub esp,4**
**这三个指令 **
** retn:**
** **
执行:
** 一个retn相当于 **
** jmp dword ptr ds:[esp]**
** add esp,4**
** 也可以理解为:**
** pop eax**
** JMP eax**
** 关于RETN后面加参数的方法可以观看我的另一篇文章《堆栈平衡、外平栈与内平栈》**
总结:以上便是整篇文章的全部内容,整理的这里都是一些常用的汇编指令,并不是所有的,另外当前我也在学习中,还有一些原因导致这篇文章是我赶时间做出来的,如果有错误,希望大佬指正,非常感谢!
版权归原作者 是星星鸭 所有, 如有侵权,请联系我们删除。