dalvik指令集和smali文件
参开地址:https://blog.csdn.net/dd864140130/article/details/52076515
https://blog.csdn.net/YJJYXM/article/details/109054667
指令作用:https://www.jianshu.com/p/09902a087611
move(linux中mv是move的简称,为移动命令)
move-wide/from16 vAA,VBBBB:
move为基础字节码,即opcode。wide为名称后缀,标识指令操作的数据宽度为64位。from16为字节码后缀,标识源为一个16位的寄存器引用变量。vAA为目的寄存器, 它始终在源的前面,取值范围为v0v255。vBBBB为源寄存器,取值范围为v0v65535。
主要作用:
1、给寄存器赋值
2、接收值保存到寄存器
3、保存异常信息
move 基础字节码
wide 数据宽度64位
一个字母代表4位即:
vA/vB/.../vH 都为4位
vAA/vBB/.../vHH 都为8位
vAAA/vBBB/.../vHHH 都为16位
move-wide/from16 vAA,vBB
例子:
move-wide:寄存器赋值
move-object:对象赋值
move-object/from16 vAA,vBBBB
对象赋值目标位8位源寄存器为16位,frome16表示源寄存器为16位,源寄存器是后面的vBBBB
一个B代表是4位4*4=16,其实from16写不写意思一样。
move-object/16 vAA,vBBBB:表示目标和源都是16位
move-result vAA:表示接收返回值到vAA中并且是单字
move-result-wide vAA:多字
move-result-object vAA:接收 invoke的操作对象,赋值给vAA寄存器
move-exception vAA:保存运行时发生的异常信息到vAA寄存器
return (显而易见,返回指令)
return-void: 表示一个方法以void方式返回,那就是不返回呗(笑抽),返回为空
return-vAA:表示返回非对象类型,8位,(return-object为返回对象,因为有object,8位是因为AA,4*2,一个代表4位)
return-wide vAA:64位非对象类型,返回8位寄存器;
return-object vAA:对象类型,返回8位寄存器
const(变量,js中定义常量使用)
数据定义指令用来定义程序中用到的常量,字符串,类等数据。它的基础字节码为const
有/是要扩展的
默认是32位,有-wide就是64位
-string是声明字符串 -class就是类了
指令描述const/4 vA,#+B将数值符号扩展为32后赋值给寄存器vAconst-wide/16 vAA,#+BBBB将数值符号扩展为64位后赋值个寄存器对vAAconst-string vAA,string@BBBB通过字符串索引高走字符串赋值给寄存器vAAconst-class vAA,type@BBBB通过类型索引获取一个类的引用赋值给寄存器vAA
对象操作指令:
new-instance vAA,/com/shp/dev/Student (Java中有instance判断两个对象类型是否相同)创建一个对象,把对象赋值给vAA寄存器
instance-of vA,vB,/com/shp/dev/Student 判断判断vB类中对象是否是Studnet类型,如果是将V1赋值0,如果不是赋值0
check-cast vAA,/com/shp/dev/Student 将vAA转成Student类型,如果转换失败则会抛出ClassCastException(类转换异常)
指令描述new-instance vAA,type@BBBB构造一个指定类型的对象将器引用赋值给vAA寄存器.此处不包含数组对象instance-of vA,vB,type@CCCC判断vB寄存器中对象的引用是否是指定类型,如果是,将v1赋值为1,否则赋值为0check-cast vAA,type@BBBB将vAA寄存器中对象的引用转成指定类型,成功则将结果赋值给vAA,否则抛出ClassCastException异常.
数组操作指令
在实例操作指令中我们并没有发现创建对象的指令.Davilk中设置专门的指令用于数组操作.
new-array vA,vB,type :创建vB大小的数组,赋值给vA
fill-array-data vAA, :填充指定数据到数组的第一个元素,然后存到寄存器中
指令说明new-array vA,vB,type@CCCC创建指定类型与指定大小(vB寄存器指定)的数组,并将其赋值给vA寄存器fill-array-data vAA,+BBBBBBBB用指定的数据填充数组,vAA代表数组的引用(数组的第一个元素的地址)
数据运算指令
数据运算主要包括两种:算数运算和逻辑运算.
1. 算术运算指令
add-int/lit8 v0, v6, 0x1 :添加指令 int类型
sub-int/2addr v0, v1
指令说明add-type加法指令sub-type减法指令mul-type乘法指令div-type除法指令rem-type求
2. 逻辑元算指令
指令说明and-type与运算指令or-type或运算指令xor-type异或元算指令
3. 位移指令
指令说明shl-type有符号左移指令shr-type有符号右移指令ushr-type无符号右移指令
上面的-type表示操作的寄存器中数据的类型,可以是-int,-float,-long,-double等.
比较指令
cmpl比较数值,并赋值给寄存器vAA,vBB>vCC =-1 vBBvCC=0 vBB<vCC=1
cmpp vBB>vCC=1 vBBvCC=1 vBB<vCC=-1
cmp 和cmpg相同
指令说明cmpl-float vAA,vBB,vCC比较两个单精度的浮点数.如果vBB寄存器中的值大于vCC寄存器的值,则返回-1到vAA中,相等则返回0,小于返回1cmpg-float vAA,vBB,vCC比较两个单精度的浮点数,如果vBB寄存器中的值大于vCC的值,则返回1,相等返回0,小于返回-1cmpl-double vAA,vBB,vCC比较两个双精度浮点数,如果vBB寄存器中的值大于vCC的值,则返回-1,相等返回0,小于则返回1cmpg-double vAA,vBB,vCC比较双精度浮点数,和cmpl-float的语意一致cmp-double vAA,vBB,vCC等价与cmpg-double vAA,vBB,vCC指令
字段操作指令
input 输入,也就是写,get是获取也就是读,sput 就是 static put 也就是静态的写,那sget就是获取静态变量;
input 写如普通变量
iget 获取普通变量
sput 获取静态变量
sget 获取静态变量
iput-type,iget-type,sput-type,sget-type.type
方法调用指令
{parameters}中第一个参数为当前的对象,后买你几个才是方法的参数
在java中被static修饰的是静态方法,super代表父类,所以就是父类方法。
interface表示接口,那么就是接口方法,而invoke-direc是私有化的方法,invoke-virtual为公开的方法;
invoke-direct 调用普通方法
invoke-static 调用静态方法
invoke-super 调用父类方法
invoke-virtual 调用实例方法
invoke-interface 调用接口方法
指令说明:
invoke-direct{parameters},methodtocall调用实例的直接方法,即private修饰的方法.此时需要注意{}中的第一个元素代表的是当前实例对象,即this,后面接下来的才是真正的参数.比如指令invoke-virtual {v3,v1,v4},Test2.method5:(II)V中,v3表示Test2当前实例对象,而v1,v4才是方法参数invoke-static{parameters},methodtocall调用实例的静态方法,此时{}中的都是方法参数invoke-super{parameters},methodtocall调用父类方法invoke-virtual{parameters},methodtocall调用实例的虚方法,即public和protected修饰修饰的方法invoke-interface{parameters},methodtocall调用接口方法
方法返回指令
在java方法中void表示没有返回值,在这也是一样;
默认为32位非对象所以 return vAA 就是非对象32位;
-wide表示64位,也没有加-object,所以就是64位非对象类型
那没加了-object就是对象类型,所以就是返回一个对象类型
指令说明:
return-void什么也不返回return vAA返回一个32位非对象类型的值return-wide vAA返回一个64位非对象类型的值return-object vAA反会一个对象类型的引用
同步指令
锁,在java中sycharnazhide表示对象锁,目的是防止并发时发生数据错乱,但是效率不高,
所以使用的场景很少;
指令说明monitor-enter vAA为指定对象获取锁操作monitor-exit vAA为指定对象释放锁操作
跳转指令
goto 就是直接跳转,在java中表示 return ; 意思差不多;
packed-switch vAA,类似java中的switch
spare-switch vAA,同理也是java中switch
if-test 条件跳转,相当于标记跳转,标注一个点,如果满足某个需求则跳转到那个点;
指令操作goto +AA无条件跳转到指定偏移处(AA即偏移量)packed-switch vAA,+BBBBBBBB分支跳转指令.vAA寄存器中的值是switch分支中需要判断的,BBBBBBBB则是偏移表(packed-switch-payload)中的索引值,spare-switch vAA,+BBBBBBBB分支跳转指令,和packed-switch类似,只不过BBBBBBBB偏移表(spare-switch-payload)中的索引值if-test vA,vB,+CCCC条件跳转指令,用于比较vA和vB寄存器中的值,如果条件满足则跳转到指定偏移处(CCCC即偏移量),test代表比较规则,可以是eq.lt等.
if-text的例子
指令说明if-eq vA,vB,targetvA,vB寄存器中的相等,等价于java中的if(a==b),比如if-eq v3,v10,002c表示如果条件成立,则跳转到current position+002c处.其余的类似if-ne vA,vB,target等价与java中的if(a!=b)if-lt vA,vB,targetvA寄存器中的值小于vB,等价于java中的if(a<b)if-gt vA,vB,target等价于java中的if(a>b)if-ge vA,vB,target等价于java中的if(a>=b)if-le vA,vB,target等价于java中的if(a<=b)
除了以上指令之外,Davilk还提供可一个零值条件指令,该指令用于和0比较,可以理解为将上面指令中的vB寄存器的值固定为0.
很显然判断的末尾都加了z 是0英语的首字母zero缩写
指令说明if-eqz vAA,target等价于java中的if(a==0)或者if(!a)if-nez vAA,target等价于java中的if(a!=0)或者if(a)if-ltz vAA,target等价于java中的if(a<0)if-gtz vAA,target等价于java中的if(a>0)if-lez vAA,target等价于java中的if(a<=0)if-gtz vAA,target等价于java中的if(a>=0)
数据转换指令
指令说明int-to-long整形转为长整型float-to-int单精度浮点型转为整形int-to-byte整形转为字节类型neg-int求补指令,对整数求补not-int求反指令,对整数求反
详解smali文件
很好理解,就是字面意思
filed就是类中的变量名,method就是方法,.line 就是行,
paramter param都是参数的意思,annotation表示的是注解
implemenets也是java中的实现某个类的关键字
.local 是局部变量的个数 .registers是方法内寄存启动个数
关键词说明.filed定义字段.method…end method定义方法.annotation…end annotation定义注解.implements定义接口指令.local指定了方法内局部变量的个数.registers指定方法内使用寄存器的总数.prologue表示方法中代码的开始处.line表示java源文件中指定行.paramter指定了方法的参数.param和.paramter含义一致,但是表达格式不同
1. 文件头描述
.class <访问权限修饰符> [非权限修饰符] <类名>
.super <父类名>
.source <源文件名称>
.class 当前类的 例如 public class static aaa
.super 当前类的父类 如:public class static aaa extens bbb
.source 表示当前类之前的文件名称,如 aaa.java