java将不规律的文字放在数组_java层逆向分析方Dalvik指令集

点击蓝字默默关注

Dalvik的指令格式:

基础字节码 - 名称后缀/字节码后缀 目的寄存器 源寄存器

(连接符号“- ”在有的指令里是可以不存在的)

名称后缀是wide,表示数据宽度为64位

字节码后缀是from16,表示源寄存器为16位

例如:move-wide/from16 vAA,VBBBB:

  • move为基础字节码:即opcode。 

  • wide为名称后缀:标识指令操作的数据宽度为64位。

  • from16为字节码后缀:标识源为一个16位的寄存器引用变量。

  • vAA为目的寄存器: 它始终在源的前面,取值范围为v0~v255。

  • vBBBB为源寄存器:取值范围为v0~v65535。

Dalvik 指令集中大多数指令用到了寄存器作为目的操作数或源操作数,其中 A/B/C/D/E/F/G/H 代表一个4位的数值,AA/BB/.../HH代表一个8位的数值,AAAA/BBBB/.../HHHH 代表一个16位的数值。

一:空操作指令

空操作指令的助记符为nop。它的值为00,通常nop指令被用来做对齐代码之用,无实际操作。

二:数据操作指令

数据操作指令为move。move 指令根据字节码大小与类型不同,后面会跟上不同的后缀,表达的意义也就不同。

  • “move vA, vB”:将vB寄存器的值赋给vA寄存器,源寄存器与目的寄存器都为4位。

  • “move/from16 vAA, vBBBB”:将vBBBB寄存器的值赋给vAA寄存器,寄存器为16位,目的寄存器为8位。

  • “move/16 vAAAA, vBBBB”:将vBBBB寄存器的值赋给vAAAA寄存器,源寄存器与目的寄存器都为16位。

  • “move-wide vA, vB”:为4位的寄存器对赋值。源寄存器与目的寄存器都为4位。

  • “move-object vA, vB”:object是对象的意思,出现这个词即表示为对象赋值。源寄存器与目的寄存器都为4位。

  • “move-object/from16 vAA, vBBBB”:为对象赋值。源寄存器为16位,目的寄存器为8位。

  • “move-object/16 vAA, vBBBB”:为对象赋值。源寄存器与目的寄存器都为16位。

  • “move-result vAA”:将上一个invoke类型指令操作的单字非对象结果赋给vAA寄存器。

  • “move-result-wide vAA”:将上一个invoke类型指令操作的双字非对象结果赋给vAA寄存器。

  • “move-result-object vAA":将上一个invoke类型指令操作的对象结果赋给vAA寄存器。

  • “move-exception vAA”:保存运行时发生的异常到vAA寄存器。这条指令必须是异常发生时的异常处理器的一条指令,否则指令无效。

总结起来move指令有三种作用:

第一种作用:进行赋值操作。

第二种作用:move-result 接收返回值操作。

第三种作用:处理异常的操作。

三:返回指令

返回指令即return指令,指的是函数结尾时运行的最后一条指令。共有以下四条返回指令:

  • “return-void”:表示函数从一个void方法返回,返回值为空。

  • “return vAA”:表示函数返回一个32位非对象类型的值,返回值寄存器为8位的寄存器vAA。

  • “return-wide vAA”:表示函数返回一个64位非对象类型的值,返回值为8位的寄存器对vAA。

  • “return-object vAA”:表示函数返回一个对象类型的值,返回值为8位的寄存器vAA。

四:数据定义指令

数据定义指令用来定义程序中用到的常量,字符串,类等数据。它的基础字节码为const

  • “const/4 vA, #+B”:将数值符号扩展为32位后赋给寄存器vA。

  • “const/16 vAA, #+BBBB”:将数据符号扩展为32位后赋给寄存器vAA。

  • “const vAA, #+BBBBBBBB”:将数值赋给寄存器vAA。

  • “const/high16 vAA, #+BBBB0000”:将数值右边零扩展为32位后赋给寄存器vAA。

  • “const-wide/16 vAA, #+BBBB”:将数值符号扩展为64位后赋给寄存器对vAA。

  • “const-wide/32 vAA, #+BBBBBBBB”:将数值符号扩展为64位后赋给寄存器vAA。

  • “const-wide vAA, #+BBBBBBBBBBBBBBBB”:将数值赋给寄存器vAA。

  • “const-wide/high16 vAA, #+BBBB000000000000”:将数值右边零扩展为64位后赋给寄存器vAA。

  • “const-string vAA, string@BBBB”:通过字符串索引构造一个字符串并赋给寄存器vAA。

  • “const-string/jumbo vAA, string@BBBBBBBB”:通过字符串索引(较大)构造一个字符串并赋给寄存器vAA。

  • “const-class vAA, type@BBBB”:通过类型索引获取一个类引用并赋给寄存器vAA。

  • “const-class/jumbo vAAAA, type@BBBBBBBB”:通过给定的类型索引获取一个类引用并赋给寄存器vAAAA。

五: 实例操作指令

“check-cast vAA, type@BBBB”:将vAA寄存器中的对象引用转换成指定的类型。如果失败会抛出ClassCastException异常。如果类型B指定的是基本类型,对于非基本类型的A来说,运行时始终会失败。

  • “instance-of vA, vB, type@CCCC”:判断vB寄存器中的对象引用是否可以转换成指定的类型。如果可以vA寄存器赋值为1,否则vA寄存器赋值为0。

  • “new-instance vAA, type@BBBB”:构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器。类型符type指定的类型不能是数组类。

六:数组操作指令

数组操作包括获取数组长度,新建数组,数组赋值,数组元素取值与赋值等操作。

  • “array-length vA, vB”:获取给定vB寄存器中数组的长度并将值赋给vA寄存器。数组长度指的是数组的条目个数。

  • “new-arrayvA,vB,type@CCCC”:构造指定类型(type@CCCC)与大小(vB)的数组,并将值赋给vA寄存器。

  • “filled-new-array {vC, vD, vE, vF, vG},type@BBBB”:构造指定类型(type@BBBB)与大小(vA)的数组并填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还指定了参数的个数,vC~vG是使用到的参数寄存序列。

  • “filled-new-array/range{vCCCC..vNNNN}, type@BBBB”:指令功能与“filled-new-array {vC,vD,vE,vF,vG},type@BBBB”相同,只是参数寄存器使用range字节码后缀指定了取值范围 ,vC是第一个参数寄存器,N = A +C -1。

  • “fill-array-data vAA, +BBBBBBBB”:用指定的数据来填充数组,vAA寄存器为数组引用,引用必须为基础类型的数组,在指令后面会紧跟一个数据表。

七:异常指令

Dalvik指令集有一条指令用来抛出异常。“throw vAA”抛出vAA寄存器中指定类型的异常。

八:跳转指令

跳转指令用于从当前地址跳转到指定的偏移处。

Dalvik指令集中有三种跳转指令:

1.goto:无条件跳转

2.switch:分支跳转

packed-switch:有规律跳转

sparse-switch: 无规律跳转

3.if:条件跳转    

0d6d8563fd8c3787b441026619f2760d.png

  • goto +AA :无条件跳转到指定偏移处,偏移量AA不能为0。

  • packed-switch vAA,+BBBBBBBB: 分支跳转指令。vAA寄存器为switch分支中需要判断的值,BBBBBBBB指向一个packed-switch-payload格式的偏移表,表中的值是有规律递增的。

  • sparse-switch vAA,+BBBBBBBB :分支跳转指令。vAA寄存器为switch分支中需要判断的值,BBBBBBBB指向一个sparse-switch-payload格式的偏移表,表中的值是无规律的偏移表,表中的值是无规律的偏移量。

  • if-eq :如果vA不等于vB则跳转。Java语法表示为 if(vA == vB)

  • if-ne :如果vA不等于vB则跳转。Java语法表示为 if(vA != vB)

  • if-lt: 如果vA小于vB则跳转。Java语法表示为 if(vA < vB)

  • if-le :如果vA小于等于vB则跳转。Java语法表示为 if(vA <= vB)

  • if-gt: 如果vA大于vB则跳转。Java语法表示为 if(vA > vB)

  • if-ge: 如果vA大于等于vB则跳转。Java语法表示为 if(vA >= vB)

  • if-nez :如果vAA为 0 则跳转。Java语法表示为 if(vAA == 0)

  • if-eqz: 如果vAA不为 0 则跳转。Java语法表示为 if(vAA != 0)

  • if-ltz :如果vAA小于 0 则跳转。Java语法表示为 if(vAA < 0)

  • if-lez: 如果vAA小于等于 0 则跳转。Java语法表示为 if(vAA <= 0)

  • if-gtz :如果vAA大于 0 则跳转。Java语法表示为 if(vAA > 0)

  • if-gez: 如果vAA大于等于 0 则跳转。Java语法表示为 if(vAA >= 0)

九:比较指令

比较指令用于对两个寄存器的值(浮点型或长整型)进行比较。

大于(1)/等于(0)/小于(-1)=>cmpg、cmp

大于(-1)/等于(0)/小于(1)=>cmpl

  • cmp-long vAA, vBB, vCC :比较两个长整型数。如果vBB寄存器大于vCC寄存器,则结果为1,相等则结果为0,小于则结果为-1。

  • cmpl-float vAA, vBB, vCC:比较两个单精度浮点数。如果vBB寄存器大于vCC寄存器,结果为-1,相等则结果为0,小于的话结果为1。

  • cmpl-double vAA, vBB, vCC:比较两个双精度浮点数。如果vBB寄存器大于vCC寄存器,结果为-1,相等则结果为0,小于的话结果为1。

  • cmpg-float vAA, vBB, vCC:

    比较两个单精度浮点数。如果vBB寄存器大于vCC寄存器,结果为1,相等则结果为0,小于的话结果为-1。

  • cmpg-double vAA, vBB, vCC:比较两个双精度浮点数。如果vBB寄存器大于vCC寄存器,结果为1,相等则结果为0,小于的话结果为-1。

十:字段操作指令

字段操作指令用来对对象实例的字段进入读写操作。字段的类型可以是Java中有效的数据类型,对普通字段与静态字段操作有两中指令集。

普通字段 => iget读 / iput 写

静态字段 => sget读 / sput 写

十一:方法调用指令

方法调用指令负责调用类实例的方法,它的基础指令为invoke。

根据方法类型不同,共有5条方法调用指令

  • invoke-virtual或invoke-virtual/range :调用实例的虚方法

  • invoke-super或invoke-super/range :调用实例的父类/基类方法

  • invoke-direct或invoke-direct/range :调用实例的直接方法

  • invoke-static或invoke-static/range :调用实例的静态方法

  • invoke-interface或invoke-interface/range :调用实例的接口方法

十二:数据转换指令

数据转换指令用于将一种类型的数值转换成另一种类型。它的格式为“opcode vA, vB”,vB寄存器存放需要转换的数据,转换后的结果保存在vA寄存器中。

neg-数据类型:求补

not-数据类型: 求反

数据类型1-to-数据类型2: 将数据类型1转换为数据类型2

十三:数据运算指令

数据运算指令包括算术运算指令与逻辑运算指令。算术运算指令主要进行数值间如加、减、乘、除、模、移位等运算,逻辑运算主要进行数值间与、或、非、异或等运算。

add/sub/mul/div/rem;加/减/乘/除/模

and/or/xor;与/或/异或

shl/shr/ushr;有符号左移/有符号右移/无符号右移

小结

初步了解了Dalvik的13种指令的使用,包括空操作指令,它的助记符为nop,数据操作指令move,返回指令return,数据定义指令,它是用来定义程序中用到的常量,字符串,类等数据的指令,实例操作指令、数组操作指令、异常指令,“throw vAA”抛出vAA寄存器中指定类型的异常;跳转指令,它是用于从当前地址跳转到指定的偏移处,有三种;比较指令cmp、字段操作指令、方法调用指令、数据转换指令以及运算指令。

END

3e039c2ef28f3d09b7b38ed6b3461448.png

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值