222222222222
这六个域分别是:
prefixes (1 Byte)
code (1/2/3 Bytes;2字节指令是第一个指令码为0x0f,而一般3字节指令的第3字节是ModR/M的一部分)
ModR/M (1 Byte)
SIB (1 Byte)
displacement (1/2/4 Bytes)偏移量
immediate (1/2/4 Bytes)立即数
在任何一条指令中code域必须出现,其他的域都是可选的。
由于这六个域在指令中的排列顺序是固定的,所以反汇编机器码,就是一个对它们的依次识别过程。
1、 对prefixes的识别
x86体系结构CPU的4类prefixes,它们分别为:
lock/repeat prefix :F0/F2,F3 (LOCK和REP)
segment override prefixes :2E,36,3E,26,64,65 (忽略段的前缀)
operand-size override prefix :66 (忽略操作数大小的前缀)
address-size override prefix :67 (忽略地址大小的前缀)
指令的prefixes可以由这几类prefixes组成,但是每类prefixes只能在指令中出现一次,至于每类prefixes在指令的出项顺序是没有要求的,这点和指令的六个域是不同的。当某类prefixes在同一指令中出现多次的时候,CPU在执行过程中,可能会出现不可预料的结果,至于会不会出现异常,Intel的官方手册中只用了这句话来说明:such use may cause unpredictable behavior.鬼知道会出项什么情况,因此算法必须对这类机器码具有识别能力。但是也可能异常情况不会发生,在反汇编过程,遇到同一类prefixes出现多次的情况,以最后出现的prefix为准,进行机器码识别。
总结:
(1)Prefixes是唯一的一个可能出现在code之前的域。
(2)所有的Prefixes都只有1个字节。
(3)在一个OpCode中可能会有多个Prefixes。
(4)如果有多个Prefixes,那么它们的顺序可以打乱,不会有任何问题。
(5)如果Prefixes不能对随它之后的OpCode起作用,那么它就会被忽略。
2、对code和operand的识别
CPU在设计时,为了提高比特位的利用率,也为了保证一个code不是另一个code的前缀(否则CPU也无法译码),code的编码采用的是哈夫曼算法。code的最大长度是3个字节,当然可以是1个字节,也可以是2个字节,另外,对于某些特定的code,还有3个比特的信息也会用来表示code.这3比特在ModR/M的3、4和5位。当然每个code也最多只能有三个operand。
对code的识别一般都是采用二维表格来驱动的。二维表格中记录了给各code的详细信息。
ModR/M字节:这个字节指示了后面跟随的操作数的形式,它分成3个部分:第7-6位是Mod部分,第5-3位是Reg部分,第2-0位是R/M部分,其中Mod和R/M部分结合指示了指令操作数的寻址方式,而Reg部分主要是指示用到的寄存器,这个字节的解释要和主操作码结合起来。
SIB字节:除了上面这个ModR/M字节外,有时候指令还需要一个字节来补充指操作数的寻址方式,这个字节也分成3个部分:第7-6位是scale部分,第5-3位是index部分,第2-0位是base部分;
在翻译过程中,以指令的操作码为索引从相应的数组来输出对应的指令字符串,而接下来最主要的就是对操作数的翻译,所有的操作数都可以用:【寻址方式 + 操作数类型】来表示,寻址方式有A(直接地址),C(ModR/M字节的REG部分指示一个控制寄存器),D( ModR/M字节的REG部分指示一个调试寄存器),E(ModR/M字节指示的操作数是一个通用寄存器或一个内存地址),F(EFLAGS寄存器),G(ModR/M字节的REG部分指示一个通用寄存器),I(立即数),J(指令包含一个相对地址),M(ModR/M字节指示一个内存地址),O(没有ModR/M字节,后面的字或双字为偏移地址),P(ModR/M字节的REG部分指示一个4字节MMX寄存器),Q(ModR/M字节指示的操作数是一个MMX寄存器或一个内存地址),R(ModR/M字节的Mod部分指示一个通用寄存器),S(ModR/M字节的REG部分指示一个段寄存器),T(ModR/M字节的REG部分指示一个测试寄存器),V(ModR/M字节的REG部分指示一个128位XMM寄存器),W(ModR/M字节指示的操作数是一个128位XMM寄存器或一个内存地址),X(内存地址由DS:SI寄存器对表示),Y(内存地址由ES:DI寄存器对表示);操作数类型主要有b(字节),d(双字节),w(字),v(字或双字,根据操作数大小定)。
3、现在就可以根据下面的两个表来进行机器码识别了。例如,如果二进制序列是0x03,0x70,0xe8,则操作码是0x03,查指令表Table A-2是"add Gv,Ev",第2个字节0x70是ModR/M字节,二进制是01110000,则Mod部分是1,REG部分是6,R/M部分是0,查ModR/M字节表Table 2-2得到Gv操作数是esi,Ev操作数是[eax+disp8],disp8是8位的偏移量,则读下一个字节0xe8,由于这个字节是负数,取相反值是0x18,则Ev操作数是[eax-0x18],所以输出的最终指令是"add esi,[eax-0x18]"。
4、扩展指令
除了单字节指令和二字节指令外还有一部分指令是三字节的,这些指令称作扩展指令,扩展指令是把ModR/M字节当作操作码的一部分,根据指令属于的不同group和REG部分的值来查Intel Manual中表Table A-4翻译指令的,如操作码为0x80-0x83的指令就是属于group 1,然后根据REG的值来确定操作码的字符串,如REG为5则是"sub"指令。
5、浮点数指令
浮点数指令又叫逃逸码指令(escape opcode instructions。它是主操作码为0xd8-0xdf的指令,并且用这个主操作码分成几组,每组指令中又根据ModR/M字节的值分成值在0x00-0xbf范围中和不在这个范围中两部分,在这个范围中的指令根据ModR/M字节字节中的REG部分进行索引,得到相应的指令;不在这个范围中的指令则按照ModR/M字节的值查找相应的表得到指令,ModR/M字节中的高4位是行号,低4位是列号。
- » x86结构机器码识别及其反汇编
222222222222相关推荐
- 36 张图详解 ARP :网络世界没有我,你哪也别想去
上帝视角 初识 ARP 从网络分层上看,我们知道二层网络中,使用 MAC 地址进行传输,MAC 地址做为数据链路层的设备标识符. 二层网络 三层网络中,使用 IP 地址进行传输,IP 地址做为网络层的 ...
- 区块链相关论文研读5:分布式隐私保护可审计的账本,zkLedger
这篇文章首发于知乎专栏:https://zhuanlan.zhihu.com/p/87900715 这篇论文在2018年发表在顶会NSDI上面,题目为<zkLedger: Privacy-Pre ...
- some learning
一.windows下迁移access到mysql Windows下 Access 数据 迁移到 Mysql(5.5)数据库1. 具体做法1. 在access的表中选择,文件->导出->保存 ...
- python 杀死一个线程
"不要试图用强制方法杀掉一个python线程,这从服务设计上就存在不合理性. 多线程本用来任务的协作并发,如果你使用强制手段干掉线程,那么很大几率出现意想不到的bug." 话虽然这 ...
- 理解 OpenStack Swift (2):架构、原理及功能 [Architecture, Implementation and Features]...
本系列文章着重学习和研究OpenStack Swift,包括环境搭建.原理.架构.监控和性能等. (1)OpenStack + 三节点Swift 集群+ HAProxy + UCARP 安装和配置 ( ...
- TC SRM 562 div2 B 题
题意: 给你一个矩形的画布,此画布由'B'和'.'组成,画T次每次画的时候他的左上角的起始点是确定的几位(1,1),(2,2),(3,3)......(T,T); 在画的过程中可能会出现相互覆盖求画完 ...
- docker如何将运行中的容器保存为docker镜像?
答: 使用docker commit和docker save保存镜像 $ sudo docker commit <当前运行的container id> <仓库名称>:<t ...
- 解决jmeter测试报告不显示后面的断言错误失败信息
一.问题描述 使用jmeter进行自动测试了两个接口,该接口测试有4个断言,其中有3个断言是失败的,并且有相应的断言错误信息: 请求失败11111111111111 请求失败222222222222 ...
- Android Hander机制的理解
总以为自己对Handler比较了解,但今天发现还是不了解,以后写代码得好好的看看android doc了,这样才能理解的更深. 一直以为Handler.post(Runnable)为开启一个线程,所以 ...
最新文章
- mysql5.7多实例安装_MySQL数据库5.7多实例安装
- 计算机上开发和运行应用程序与操作系统无关,计算机期中测验理论部分和答案-C.doc...
- python链接mysql系统结构设计_MySQLpython交互
- 多重继承java_Java中的多重继承与组合vs继承
- linux里工作目录的字体变蓝,netterm访问Linux时字体和背景颜色随目录发生改变的问题解决...
- C下的全局变量和指针 - C/C++ / C语言
- hibernate中主键的生成策略
- 友好的免抠图片素材| PNG设计元素集海量来袭
- Jupyter Notebook——如何显示目录的导航栏(安装 Jupyter Notebook extension)
- python上下文管理关键字_理解 Python 的上下文管理器
- php原生判断,JavaScript
- svn客户端(Windows版本)
- Python 修改图片的时候抗锯齿
- G729调用方法及使用wavlib播放出现颤音的解决方法
- 第九届“图灵杯”NEUQ-ACM部分汇总
- 基于springboot的生鲜门店配送管理系统(idea+springboot+html+thymeleaf)
- 花滑三周连跳_三周半+四周跳来势汹汹 花滑女单将迎难度巨变?
- 添加msg文件找不到目录add_message_files() directory not found:
- 三星I9220刷机包 新蜂ROM V4.1 高级设置 全透明天气插件
- 17岁高中生证明著名数学难题,因此被MIT录取
热门文章
- python list[list] or list[list, list, list]
- 频率与听感的对应关系
- 声音频率分类(二十一)
- marked.js讲解
- Java项目如何查找各种jar包
- 阿里云服务器 之 mqtt服务器搭建及使用
- PHP上传图片到服务器
- JavaPoet动态生成代码,高薪程序员必会
- idea Dmaven.multiModuleProjectDirectory=$M2_HOME报错!!!
- SpringMVC超详细入门