IA-32指令解析详解

0x00 前言

这段时间忙于考试,信息论和最优化,还有算法分析,有点让人头大。期间花了几天看SEH机制,能明白个大概,但是对于VC++对于SHE的包装似乎还是不是很明白,发现逆向工程核心原理对于这段写的太简单,至于加密与解密则是模棱两可,软件加密技术内幕倒是详解了,可是太老了,代码又是汇编写的总是编译不通过。真是让人难受!本来想写一篇SEH详解,但是基于以上原因暂时搁置。这两天看了逆向核心原理关于IA-32指令解析的内容,发现还是挺有意思,遂记录下来。

0x01 何谓IA-32的指令解析

其实很简单,就是把汇编的机器码解析成汇编语言的过程。下图显示了机器码和汇编代码的关系。

0x02 解析所需知识点

  1. 汇编指令的格式

汇编指令有六部分构成,如下图:

Prefix----指令前缀(可选项)

Opand----操作指令(必选项)

Mod R/M---操作数辅助说明(可选项)

SIB----Mod R/M辅助说明(可选项,但是出现Mod R/M 这个必须有)

Displacement---操作数作为内存地址时用来表示位移(可选项)

Immediate ----表示操作数为立即数(可选项)

2.重要字段简单说明

1)指令前缀prefix大小为一个字节,用来辅助说明指令的具体功能,可选项

例如:66:81FE 4746 CMP SI,474红色字体就是指令前缀,后面跟一个:。

2)操作指令opand,这个没啥好说的,必选项,大小为1到3字节,通常为一个字节,多字节后面会有说明.例如:66:81FE 4746 CMP SI,474

3)Mod R/M 大小为一个字节,由三部分组成,分别为 Mod(字节前两位),Reg(字节中间三位),R/M(字节后三位)。Mod R/M的主要功能就是说明操作数的寻址方式,包括寄存器选择,内存操作数的偏移等等。例如:66:81FE 4746 CMP SI,474

4)SIB,大小为一个字节,也是用来辅助操作数寻址的,一般用于辅助Mod R/M,当出现基址加变址寻址或者基址寻址时要用到。898424  50020000 Mov [ESP+250],EAX.

3. 为了能够顺利解析IA-32的机器码,我们应该下载Intel的开发手册,然后打印出有关指令解析的图表。下载网址为:http://www.intel.com/products/processor/manuals

选择第一个最完整的下载,如下图:

下面是我总结的应该打印的页码数:

table 2-2 32-bit Addressing forms with the ModR/M Byte, page 510

table 2-3 32-bit Addressing forms with the SIB Bytes, page 511

APPENDIX A ,page 487

A.2.1 Codes for Addressing Method

A.2.2 Code for Operand Type

Table A-2 .one –byte Opcode Maps

Table A-3.two-bytes Opcode Maps

pages :2519-2530

Table A-6 Opcode Extension for one-and Two Opcodes by Group Number

pages:2535-2537

0x03 指令解析步骤

1) 操作码映射

首先我们解析一个长度为一的操作码,对应的表是Table A-2 .one –byte Opcode Maps

指令:41,将指令拆成4和1,4对应表的行向量,1对应表列向量,如下图:

由上图可知41对应的指令为INC ECX,我们可以使用od来印证正确性。如下图:

至于为什么用寄存器ECX,是因为IA-32默认使用32位寄存器。

2) 操作数的使用

指令68 A0B44000,我们先拆分68为6和8还是使用表Table A-2 .one –byte Opcode Maps

来查找操作指令。如下图:

上图可知是push指令,操作数的寻址方式有Iz规定,我们接下来来使用code for Addressing Method和表code for opcode type 来查看具体信息,第一个大写字符I规定了寻址方式,在code for Addressing Method查找对应含义,如下图:

表示这是一个立即数。第二个小写字符z在表code for opcode type 中查找,如下图:

z表示使用的字符大小为字或者双字,由于是在32位系统中默认使用双字(使用单字的情况是使用前缀来说明),故这里是个双字,Iz一起就是表明使用双字立即数,表明指令68 A0B44000中A0B44000就是使用的双字立即数。完整的指令翻译过来就是:

Push 0004B4A0(注意汇编中的数据存储),我们也来使用od验证一下。如下图:

3) 带有Mod R/M的指令

上面两个指令都很简单,除了操作码就是操作数本身,下面来解析带有Mod R/M的指令,现在来看指令89C1。先解析89如下图:

上图可知指令是OR指令,两个操作数的说明分别是Ev和Gv,这两个使用表A.2.1 Codes for Addressing Method和表A.2.2 Code for Operand Type来查看。Ev的查询结果如下图:

这里应该主义的是,E中已经说明了要使用通用寄存器或者内存操作数,并且要使用Mod R/M来进行辅助说明,所以在操作码89后的C1就是ModR/M,Ev统一起来就是可以使用双子寄存器操作数或者双子内存操作数,具体的要使用ModR/M字段来辅助说明。我们把ModR/M字段的内容c1(1100,0001)拆成三部分:Mod:11,Reg:000,R/M:001,下面根据这个信息来查询表table 2-2 32-bit Addressing forms with the ModR/M Byte,如下图:

使用三个字段分别找到Ev对应的寄存器是ECX,Gv使用的寄存器是EAX,因此完整指令应该为89C1 OR ECX,EAX,用od验证如下图:

4) 带有Group指令解析

Group指令与ModR/M结合使用。Group给指令带来了更为丰富的变化,也是的指令解析更为复杂。例如:83C3 12,先解析83,如下图:

上图可以看出该指令带group指令。对于group指令我们还需查询表Table A-6 Opcode Extension for one-and Two Opcodes by Group Number。我们使用ModR/M(C3=1100,0011)的第二个字段Reg(000)来查询,如下图:

对应的指令为ADD,结合来看指令大致为ADD Ev,Ib,再根据ModR/M字段值C3得出指令为ADD EBX,12。

5) 指令前缀的使用

指令前缀主要来辅助说明操作码的,比如前缀66就会规定指令为16位形式。前缀的形式一般都是:前缀:操作码(这里是显示形式,其实在od中编写不用写符号:但是显示会出现符号:)。

接下来来示范解析带有前缀的指令 66:81FE 3412。前缀66的信息查询也是在表

Table A-2 .one –byte Opcode Maps(单字节操作码查询表)中如下图:

上图表示操作码的size位16位,接下来继续解析81,如下图:

说明还要使用ModR/M(FE=1111,1110)的字段Reg(111)表Table A-6 Opcode Extension for one-and Two Opcodes by Group Number来查询Group信息。如下图:

因此指令的形式是CMP Ev,Ib,由于前缀规定使用16位操作数,所以指令解析为:

66:81FE 3412 CMP SI,1234(指令为16位的)。

6) 双字节操作码的解析

双字节操作码很好分辨,指令的第一个字节为0F,指令映射参考表Table A-3.two-bytes Opcode Maps。接下来我们来解析指令0F85 FA1F0000。先解析0F,查询表Table A-2 .one –byte Opcode Maps可得下图:

可知这是一个双字节操作数,其实双操作数的第一个字节都是0F,再来查询85,我们使用表Table A-3.two-bytes Opcode Maps。如下图:

由上图可知这是一个条件跳转指令,而且是长跳转,JCC +NE/NZ=JNE指令。Long型表明跳转地址为四个字节。这里还需特别注意的是:机器码0F85 FA1F0000的四个字节是相对地址,要正确解析出指令还需算出实际的跳转地址。公式为:实际地址=当前地址+指令大小+相对地址。我们用OD实际的运算一下:选定当前的地址是010073ee,则解析后的实际跳转地址=010073ee+6(指令大小为五个字节)+00001FFA= 01008EEE,所以完整的指令解析为:

JNZ 01008EEE。如下图:

7) 同时含有位移值和立即数的情况

例如指令:C705 00CF4000 01000100

首先解析C7,如下图:

这是一个含有group的指令,ModR/M为05(0000,0101),其中Reg值为:000,根据Reg值查询group表,如下图:

由此可见指令的形式为MOV  Ev,Iz,Ev表示使用ModR/M规定的寄存器双字或者内存双字。Iz表示立即数双字。下面使用ModR/M来确定具体的寻址方式,查询ModR/M表,如下图:

因此第一个操作数使用的32位内存操作数,默认的段寄存器是DS,第二个操作数是立即数。完整解析指令为:Mov DWORD DS:[40CF00],10001.

8) 使用SIB的情况

SIB也是用来辅助寻址的,主要针对基址寻址和基址加变址寻址。

那如何来判断指令是否使用了SIB呢?

且看指令8B0C01 ,先解析8B,如下图:

指令形式为MOV Gv,Ev。Gv表示ModR/M规定的双字寄存器数,Ev表示使用ModR/M规定的双子寄存器数或者双字内存数。接下俩解析ModR/M,字段值为0C(00001100),查询ModR/M表可得下图:

由上图可得指令的基本结构为MOV ECX,[Reg.A+Reg.B]。对于这种结构的寻址方式就要用到SIB辅助寻址,指令中的SIB=01,拆成三个字段scale=00,Index=000,base=001,查询表table 2-3 32-bit Addressing forms with the SIB Bytes如下图:

因此完整的解析指令为:8B0C01 MOV ECX,DWORD PTR DS:[ECX,EAX],使用OD验证一下,如下图:

以上就是解析IA-32机器码时会遇到的所有情况,掌握了这些解析机器码不成问题。

0x04 感想

IA-32指令解析本身不是很难,只要多多练习就能提高。还有就是解析是碰到内存操作数最好还是使用PTR说明符,虽然有些情况下可以不适用,但是OD默认的情况是碰到内存操作数就是用PTR。这点需要注意。

IA-32指令解析详解的更多相关文章

  1. SSI指令使用详解(转)

    什么是 SHTML使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为“服务器端嵌入”或者叫“服务器端包含”,是一种类似 ...

  2. MySQL-5.5.32 配置文件优化详解

    目录 MySQL-5.5.32 配置文件优化详解 一.配置文件说明 2.my-medium.cnf 3.my-large.cnf 4.my-huge.cnf 5.my-innodb-heavy-4G. ...

  3. ng-repeat指令使用详解

    ng-repeat指令使用详解 link: function(scope,element,attr) scope.$index: if(scope.$last == true){} attr['mng ...

  4. Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置

    一个例子 public class TestString{ public static void main(String[] args){ String a = "a"; Stri ...

  5. android Json解析详解

    JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语 言的支持),从而可以在不同平台间进行数 ...

  6. android Json解析详解(详细代码)

    JSON的定义: 一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性.业内主流技术为其提供了完整的解决方案(有点类似于正则表达式 ,获得了当今大部分语言的支持),从而可以在不同平台间进行数据 ...

  7. Spring IoC componet-scan 节点解析详解

    前言 我们在了解 Spring 容器的扩展功能 (ApplicationContext) 之前,先介绍下 context:componet-scan 标签的解析过程,其作用很大是注解能生效的关键所在. ...

  8. vue自定义指令VNode详解(转)

    1.自定义指令钩子函数 Vue.directive('my-directive', {bind: function () {// 做绑定的准备工作// 比如添加事件监听器,或是其他只需要执行一次的复杂 ...

  9. AngularJS指令的详解

    指令作为AngularJS中最为重要的部分,所以这个框架本身也是自带了比较多的的指令,但是在开发中,这些指令通常不能满足我们的需要,所以我们也是需要自定义一些指令的.指令是我们用来扩展浏览器能力的技术 ...

随机推荐

  1. 汇编指令:push、pop

    8086CPU出栈入栈都是以字为单位进行的. push ax 由一下两步完成 1.SP=SP-2 2.将ax中的内容送入SS:SP指向的内存单元 pop ax 1.将SS:SP指向的内存单元中的内容送 ...

  2. 实现saas多租户方案比较

    看到一篇比较多租户数据隔离方案的文章,总结挺不错.其实大部分内容在我前几年写的文章都有. 文章翻译自: https://blog.arkency.com/comparison-of-approache ...

  3. [Web][学习随笔]Session&cookie

    Session 从登录建立连接到退出就是一次会话.Session数据就会在会话期间用户存在服务器端的数据.这样,当用户在Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会 ...

  4. 君荣 TS--8200 消费机显示说明

     Err 001——不在消费时段内Err 002——非本系统卡Err 003——余额不足Err 004——级别未开放Err 005——卡已挂失Err 006——有效期未生效Err 007——已过有效期 ...

  5. python2.7 函数的参数学习

    1.默认参数 默认参数可以简化函数的调用. 设置默认参数时,有几点要注意: 一.必选参数在前,默认参数在后,否则Python的解释器会报错. 二.当函数有多个参数时,把变化大的参数放前面,变化小的参数 ...

  6. [转] 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)

    点击阅读原译文 原文见:http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/ ...

  7. 多应用下 Swagger 的使用,这可能是最好的方式!

    问题 微服务化的时代,我们整个项目工程下面都会有很多的子系统,对于每个应用都有暴露 Api 接口文档需要,这个时候我们就会想到 Swagger 这个优秀 jar 包.但是我们会遇到这样的问题,假如说我 ...

  8. CentOS7.5搭建spark2.3.1集群

    一 下载安装包 1 官方下载 官方下载地址:http://spark.apache.org/downloads.html 2  安装前提 Java8         安装成功 zookeeper  安 ...

  9. 使用java实现单链表(转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html)

    使用java实现单链表----(java中的引用就是指针)转载自:https://www.cnblogs.com/zhongyimeng/p/9945332.html ? 1 2 3 4 5 6 7 ...

  10. opencv视频教程分享

    opencv视频教程分享-在线与网盘 https://pan.baidu.com/s/1oAcctlS 密码:i5rd 链接:https://pan.baidu.com/s/1kVJ3iSJ  密码: ...