X86-64汇编
机器码格式
基本结构
该图说明:主操作码一定有,由于其它内容不一定在一条指令中,所以指令长度不固定
符号说明:
G:寄存器
E:寄存器/内存
b:单字节
v:根据操作系统判断位数,一般数默认32位,地址默认64位
MOV Gv Ev:意思是把一个内存或寄存器的值放到一个寄存器中,大小根据操作系统决定
指令前缀
前缀分为4类,使用时,不区分前后顺序,且每组最多出现一个:
1.锁定和重复前缀
2.段重载
3.操作数大小重载
4.操作地址大小重载
REX 前缀
REX 用来扩展指令从 32 位到 64 位,这一部分的内容需要先看后面的几个部分才能看懂
占一字节,可以没有
将对应域置 1 就可以使目标扩展
其中经常使用的就是 48,让操作数变为 64 位大小
操作码
一般来说,主操作码长度为 1 到 3 字节,ModR/M 可能编码附加的 3 位操作码
双字节:0F+第二个操作码字节 或 一个前缀(66H, F2H, 或 F3H)+0F+第二个操作码字节三字节:0F+后两个操作码字节 或 一个前缀(66H, F2H, 或 F3H)+0F+后两个操作码字节
部分内容需要先看后面的
下面为 1 到 3 字节指令的查表
以上截取自 IA32 手册 2024-12 版的 2929 页至 2938 页
除了上面的查表方式,x86-64 指令还有另一种方式:通过组来查询,这种方式使用了一张新表,叫做单双字节操作码的操作码扩展
先附表
这里是 2940 到 2950
考虑 80 C0 05
80 在表 A-6 中是 Group 1,然后看 ModR/M 字段的 5,4,3 位C0:11000000,5,4,3 位为 000,即 0,查纵列得 ADD,根据之后的内容可以知道 ModR/M 指定了对应的内存和寄存器,所以得到 add al,5,这和第一种直接查表得到的 0405 的指令相同
ModR/M
如果一个操作码涉及内存,后面一般就会有一个寻址格式说明字节即 ModR/M,而如果 ModR/M 中提到了需要内存寻址,那么就需要 SIB 字节去进一步解释
ModR/M和SIB各涉及三个域:
1.Mod寻址模式
指明操作码中的E是寄存器还是内存,11是内存,其它都是寄存器
前三个为内存,后一个为数
2.Reg/Opcode寄存器或操作码扩展
指定使用的reg或opcode扩展:
3.R/M寄存器或内存
内存索引的标准格式:
base+index*scale+disp
SIB
SIB用来确定具体的地址格式如果ModR/M中Mod不为11,且R/M的值为100,则后一个字节为SIB
ModR/M和SIB各涉及三个域:
1.Scale比例因子
决定索引寄存器值的倍数
2.Index索引寄存器
3.Base基址寄存器
练习
8B 41 10
8B对应MOV Gv Ev
Gv说明目标操作数是寄存器,Ev表示源操作数为寄存器或地址41是ModR/M01 000 00101说明这个指令的地址Ev为内存地址且有8bit偏移,000说明Gv为AX类,001说明目标操作数为CX类由于没有SIB,10为立即数
所以指令为:MOV EAX, [RCX+0x10]
04 FF
04对应ADD AL,Lb
已经指定寄存器,后面直接跟立即数,Lb表明是一个byte,所以是ADD AL ,0xff
67 FF 34 88
67为指令前缀,表明把之后的地址值转为32位FF表明要去Grp 51A34为ModR/M:00 110 100得到指令是PUSH Ev00表明为使用地址无偏移,100表示根据SIB确定地址的值
SIB:10 001 000
10表明比例因子为4,001表明索引寄存器为RCX,000表明基址寄存器为RAX
根据指令前缀,将地址相关寄存器大小转为32位:push qword ptr [eax+ecx*4]
参考链接
https://www.pri87.vip/posts/47eb1508.html
道格安全|D0g3
原文始发于微信公众号(道格安全):X86-64汇编机器码格式 | 48期
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论