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. 【Java Spring Cloud 实战之路】添加一个SpringBootAdmin监控

    0. 前言 在之前的几章中,我们先搭建了一个项目骨架,又搭建了一个使用nacos的gateway网关项目,网关项目中并没有配置太多的东西.现在我们就接着搭建在Spring Cloud 微服务中另一个重 ...

  2. [转载]java内存工具VisualVM的简单使用以及与Idea集成

    本文来源https://blog.csdn.net/KingBoyWorld/article/details/75579606 一.idea集成 1.打开设置 windows File->Set ...

  3. Linux: ssh命令 远程登录

    1.查看SSH客户端版本 使用ssh -V命令可以得到版本号.需要注意的是,Linux一般自带的是OpenSSH; $ ssh -V ssh: SSH Secure Shell 3.2.9.1 (no ...

  4. thinkphp5集成GatewayWorker

    Workerman是一款纯PHP开发的开源高性能的PHP socket 服务器框架,而GatewayWorker则是基于Workerman开发的一个长连接框架,支持分布式部署,支持全局广播或者向任意客 ...

  5. python基础:如何使用 pip 安装第三方库

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 在这个生活中处处都是大数据和人工智能的时代,总是能在各种角落看到 Pyth ...

  6. Flask 蓝图(Blueprint)使用方式解析

    Flask蓝图提供了模块化管理程序路由的功能,使程序结构清晰.简单易懂.下面分析蓝图的使用方法 假如说我们要为某所学校的每个人建立一份档案,一个很自然的优化方式就是这些档案如果能分类管理,就是说假如分 ...

  7. linu使用x之sz下载和rz上传

    对于经常使用Linux系统的人员来说,少不了将本地的文件上传到服务器或者从服务器上下载文件到本地,rz / sz命令很方便的帮我们实现了这个功能,但是很多Linux系统初始并没有这两个命令.今天,我们 ...

  8. c常用函数-atoi 和 itoa

    atoi 和 itoa atoi的功能是把一个字符串转为整数 Action(){ int j; char *s=""; j = atoi(s); lr_output_message ...

  9. 04.开发REST 接口

    使用Django开发REST 接口 我们以在Django框架中使用的图书英雄案例来写一套支持图书数据增删改查的REST API接口,来理解REST API的开发. 在此案例中,前后端均发送JSON格式 ...

  10. springboot mybatis plus多数据源轻松搞定 (上)

    在开发中经常会遇到一个程序需要调用多个数据库的情况,总得来说分为下面的几种情况: 一个程序会调用不同结构的两个数据库. 读写分离,两个数据结构可能一样高,但是不同的操作针对不同的数据库. 混合情况,既 ...