文档章节

X64汇编之指令格式解析

老汉-憨憨
 老汉-憨憨
发布于 2017/07/20 10:40
字数 1770
阅读 41
收藏 1

最近由于项目组内要做特征码搜索的东西,便于去Hook一些未导出函数,你懂得...于是就闲着学习了一下x86/x64的汇编指令格式。x86的汇编指令格式请参照http://bbs.pediy.com/showthread.php?t=191802。总要有人来完成剩下的工作吧,这里我就把研究一天的x64汇编指令格式共享给大家。

一.首先打开Inter手册,看到x64汇编指令格式有多大改动,不多说,看图。

很明显,比x86多出了一点东西,Legacy Prefix
按功能组别,我将这个指令序列分为 4 个部分:
  Prefix
  Opcode
  ModRM 与 SIB
  Displacement 与 Immediate
其中,只有 opcode 是必须的,其它组成部分都可选!
好好看一下这些结构
1.Prefix前缀
AMD推出 x86 扩展 64 位技术时,增加了一个用于访问扩展的 64 位数据 prefix,它是:REX prefix,而 x86 原有的 prefix 则变为了指令格式中的:Legacy prefix。REX prefix 仅存在于 x64 的 64-bit 模式中,在 legacy x86 模式下,REX prefix 是无效的,但是在 x64 的 64-bit 模式下 Legacy prefix 是有效的。
REX prefix 的取值范围是:40H - 4FH。
在非 64 位模式下,它们是 inc 与 dec 指令,也就是说这些指令在 64 位模式下被重定义为 REX prefix
关于Prefix的介绍真的是少之又少,不过我在x86/x64 指令编码内幕(适用于 AMD/Intel)学到很多,链接如下:
http://www.mouseos.com/x64/index.html。
我这里就简单说一下吧,一个Legacy prefix还有一个REX prefix。这些修饰符是为了改变缺省的寄存器,比如说在32位下mov ax,bx。那么就要有Legacy prefix 0x66修饰,前者还有个作用就是改变当前段寄存器,不多这在目前已经显得不怎么重要了。到了x64的时候,由于通用寄存器的扩展(主要原因),原本的8个通用寄存器只要3个位来标识,但是现在多了r8~r15,16个通用寄存器怎么办呢,很明显加上一位就能完全标识了。那么就是REX prefix的作用,看一下这个家伙的结构喽...



他有取值范围,前4位一定是4,后四位可选,W,R,X,B。W标识改变默认操作数大小,比如现在x64有个汇编代码mov r8,r10。一般很多指令都是默认32位操作数的,只有在CS.L==1&&CS.D==0的时候才会是64位操作数(我没见过)。所以一般都要去改变默认操作数大小,那就是0x48 (Inter手册上常说是 REX.W 懂了要感谢我哦);其次就是R位,用来扩展 ModRM.reg 域,000 ~ 111 ---> 0 000 ~ 1 111 ,
于是现在寄存器的情况变成了如下



X: 用来扩展 SIB.index 域;
B: 用来扩展 SIB.base, ModRM.r/m 以及 Opcode.reg。

2.Opcode(操作码)
大多数通用指令的 Opcode 是单字节,最多是 2 字节。但是对 x87 FPU 指令和 SSEx 等 SMID 指令来说可以有 3 个字节的,Opcode 码代表着指令是做什么操作。
这里的Opcode并不是完整的,因为他还有扩展位,就是ModR/M里面的reg/opcode这一项,3位。比如说一个简单的例子,x64下的绝对跳转0xFF25 + 0x0000 + [8字节绝对地址]。我们去搜索Inter手册的jump指令看一下:
    FF /4 JMP r/m32 M N.S. Valid.(Jump near, absolute indirect, address given in
r/m32. Not supported in 64-bit mode.)
    FF /4 JMP r/m64 M Valid N.E.(Jump near, absolute indirect, RIP = 64-Bit
offset from register or memory)

其实很多人不明白0xFF25 为什么后面要加4个0x00.现在工作机上没x64内联汇编环境验证不了,我理解这个其实是一个偏移指示这条指令之后多远的地方存放着一个64位地址,然后再jump到这个64位地址上去。这个指令相信大家经常在调导入表函数的时候能够看到。好,闲话不多说,我们看一下,后面的这个ModR/M怎么来的,由于是/4,因此 扩展Opcode为 100,而且这个jump后面跟一个立即数地址,查表可以看到ModRM= 00 101 ---> ModR/M ---> 00 100 101。这个是多少,我不知道啦。

3.ModR/M,这个就不多说了,x86的那张指令到机器码映射表表适用于x64。至于怎么玩待会用例子来说明。

4.SIB & displacement。这里我要补充下,SIB不仅是当基址加变址寻址(base-plus-index)和比例寻址(scale-plus-index)的时候需要用到SIB.而且涉及到esp/rsp寄存器的时候也很大可能需要用到SIB,我们看下x86的指令图就知道了,没有任何一项是涉及到esp寄存器的,我们再看x86,SIB的图,来自Inter手册,看了就明白

这里在纵行找到了ESP,可见ESP这个东西,不走寻常路!!!
displacement就不用多说了吧,比如说[rsp+0x8],那就是一个字节的8,可以为负数

5.immediate,这个最好理解啦,就是立即数,比如mov eax, 0x12345678.那它这个部分就是0x78 0x56 0x34 0x12 倒着写。。。

二.实验
用windbg随便打开一个64位进程,找几条汇编指令,推一下。搞简单的吧,汗直冒撒.....



这个是32位指令,mov ebx, eax。首先去查MOV表...这里甩出来一个带x64的MOV指令表



then , we see ...
8B /r MOV r32,r/m32 RM Valid Valid Move r/m32 to r32.
默认是32位操作数所以不用加Prefix了,/r 标识ModR/M里面的reg/opcode代表的是reg
从表里看到ModR/M的值为 11 011 000 == 0xd8(第二个寄存器优先做横行).不带SIB 所以最终指令为 8B D8。



同样是mov指令,但是是64位,mov r8,r12。首先去查MOV表... then we see...
REX.W + 8B /r MOV r64,r/m64 RM Valid N.E. Move r/m64 to r64.
其实Inter手册已经告诉你了要加REX Prefix。而且是0x48(为什么去看上面),这里注意了,由于开启了寄存器扩展位,所以这得从原来的3位变成4位(从汇编往机器码上推的时候就没多大必要了)
r8,r12分别为1000和1100把第四位去掉,再从x86指令表中去找就行了。于是我们看到ModR/M为0xC4。因此最终结果为 48 8B C4 。发现跟结果不一样,为什么呢,REX Prefix没写对,其实这是因为 /r 指示ModR/M中存在扩展寄存器,所以REX.R = 1,这条指令的 ModRM.reg 提供源操作数寻址,而 ModRM.r/m 提供目标操作数寻址,目标寄存器 r8 需要 REX.B 进行扩展,它的指令编码是:



目标操作数 r12 寄存器的编码经过 REX.B 扩展为 1100
所以REX Prefix为0x4d而不是0x48。这个一定要注意...
作者:UltraCopy
*转载请注明来自看雪论坛@PEdiy.com

本文转载自:http://bbs.pediy.com/thread-206780.htm

共有 人打赏支持
老汉-憨憨
粉丝 19
博文 322
码字总数 68382
作品 0
深圳
程序员
私信 提问
VS2012下X64平台嵌入汇编程序

VS2012在win32平台编译的时候可以很好的支持汇编语言的嵌入。建立一个控制台应用程序,选择空项目。项目建立好之后添加一个.cpp文件。在cpp文件中写入如下代码: [cpp] view plain copy prin...

simpower
2018/06/26
0
0
嵌入在 Python 的 x86-64 汇编器--PeachPy

PeachPy 是一个用于编写高性能汇编内核的 Python 框架,可在汇编中编写模块。 它自动化了一些细节,并允许使用 Python 生成重复的汇编代码序列。 PeachPy 旨在简化编写优化的汇编内核,同时保...

匿名
2016/12/05
736
0
MinHook - 最小化的 x86/x64 API 钩子库

下载: 下载文件 - 828.88KB 下载源码 - 795.73KB (编译源码需要Boost 1.40.0) RaMMicHaeL已经为项目建立了分支并取得了很大的进展。我认为他在GitHub上的库是MinHook开发的主力。我推荐你从...

oschina
2014/04/23
9.1K
15
char* 和 char[] 的区别

一、代码 有关下面代码,p和q的区别是什么: 二、区别和解释 p和q的区别是: p 是一个指针,指向程序 只读数据段 的”Hello World”,不可以通过p[x] = x 来赋值,因为不能改变只读数据段的内...

yangbodong22011
2018/03/18
0
0
各种开源汇编、反汇编引擎的非专业比较

由于平时业余兴趣和工作需要,研究过并使用过时下流行的各种开源的x86/64汇编和反汇编引擎。如果要对汇编指令进行分析和操作,要么自己研究Intel指令集写一个,要么就用现成的开源引擎。自己...

simpower
2018/10/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Git 分布式版本管理系统

Git特点: 每个Git节点都保存完整的文件历史提交记录,可=在不联网的情况下将代码提交到本地仓库,联网的情况下将本地的Patch push到远程仓库,而远程公共仓库只是整个项目的一个公用的备份仓...

ZeroneLove
22分钟前
2
0
免费节假日API 开源了,可以离线调用, 可以集成到自己系统中

免费节假日API 注:原百度节假日API即为本人提供,后百度apistore禁止个人开发者所以才有此独立接口. 鉴于免费版访问量过大对于服务器压力过大现将免费版开源供大家离线调用. 开源的功能为最核...

xiaogg
23分钟前
1
0
手机主宰了你的生活,这不是乔布斯想看到的

简评:当年乔布斯的原话是「今天,苹果将重塑手机」而不是「重塑你的生活」。 智能手机是我们忠实的伴侣。对于我们中的很多人来说,它亮着光的屏幕无处不在,无休止地转移我们的注意力,比如...

极光推送
25分钟前
2
0
PyCharm入门教程——查看当前插入符号位置

PyCharm最新版本下载 JetBrains PyCharm是一种Python IDE,其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外,该IDE提供了一些高级功能,以用于Django框架下的专业Web...

电池盒
26分钟前
2
0
Ubuntu 2018 回顾:从内存泄露到 LTS 版本

Ubuntu 从 2018 年开始就一直十分活跃 —— 因为在 2018 年到来前的两个月发布的 Ubuntu 17.10 ‘Artful Aardvark’ 带来了一波接着一波的讨论。但随着一个新的长期支持版本迫在眉睫、对重新...

linux-tao
30分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部