注意:Dalvik虚拟机使用的寄存器都是32位,对于64位类型,采用两个相邻的寄存器来表示。以下语法以baksmali为准
一:Smali类型指令:
Smali语法 | Java语法 |
---|---|
B | byte |
S | short |
I | int |
J | long |
F | float |
D | double |
Z | boolean |
C | char |
v | 返回值类型 |
L | Java类类型 |
[ | 数组类型 |
二:Smali字段声明指令:
smali文件中字段的声明使用“.field”指令,字段有静态字段与实例字段两种:
静态字段:
# static fields
.field <访问权限> static [修饰关键字] <字段名>:<字段类型>
实例字段:
# instance fields
.field <访问权限> [修饰关键字] <字段名>:<字段类型>
Java代码:
//实例字段
private byte byteType=0;
private short shortType=0;
private int intType=0;
private long longType=8L;
private final int[] intArray = {0,1,2,3,4};
//静态字段
private static float floatType=0F;
private static double doubleType=6D;
private static boolean booleanType=Boolean.TRUE;
private static char charType='a';
private static final String stringObject = "ABC";
Smali代码:
# static fields
.field private static booleanType:Z = false
.field private static charType:C = '\u0000'
.field private static doubleType:D = 0.0
.field private static floatType:F = 0.0f
.field private static final stringObject:Ljava/lang/String; = "ABC"
# instance fields
.field private byteType:B
.field private final intArray:[I
.field private intType:I
.field private longType:J
.field private shortType:S
三、Smali数据定义指令、字段操作指令:
- Smali数据定义指令
指令 | 描述 |
---|---|
const/4 vA,#+B | 将数值符号扩展为32后赋值给寄存器vA |
const-wide/16 vAA,#+BBBB | 将数值符号扩展为64位后赋值个寄存器对vAA |
const-string vAA,string@BBBB | 通过字符串索引高走字符串赋值给寄存器vAA |
const-class vAA,type@BBBB | 通过类型索引获取一个类的引用赋值给寄存器vAA |
- Smali字段操作指令-实例字段
指令 | 描述 |
---|---|
iget vX,pY,filed_id | 取值,读取pY寄存器中的对象中的filed_id字段值赋值给vX寄存器 |
iput vX,pY,filed_id | 赋值,设置pY寄存器中的对象中filed_id字段的值为vX寄存器的值 |
iget-wide vX,pY,filed_id | 64位,解释见 iget |
iput-wide vX,pY,filed_id | 64位,解释见 iput |
iget-object vX,pY,filed_id | 解释见 iget |
iput-object vX,pY,filed_id | 解释见 iput |
iget-bype、iget-short、iget-long、iget-float、iget-double、iget-boolean、iget-char | |
iput-bype、iput-short、iput-long、iput-float、iput-double、iput-boolean、iput-char |
- Smali字段操作指令-静态字段
指令 | 描述 |
---|---|
sget vX,pY,filed_id | 取值,读取pY寄存器中的对象中的filed_id字段值赋值给vX寄存器 |
sput vX,pY,filed_id | 赋值,设置pY寄存器中的对象中filed_id字段的值为vX寄存器的值 |
sget-wide vX,pY,filed_id | 64位,解释见 sget |
sput-wide vX,pY,filed_id | 64位,解释见 sput |
sget-object vX,pY,filed_id | 解释见 sget |
sput-object vX,pY,filed_id | 解释见 sput |
sget-bype、sget-short、sget-long、sget-float、sget-double、sget-boolean、sget-char | |
sput-bype、sput-short、sput-long、sput-float、sput-double、sput-boolean、sput-char |
Java代码:
//实例字段
private byte byteType=0;
private short shortType=0;
private int intType=0;
private long longType=8L;
private final int[] intArray = {0,1,2,3,4};
//静态字段
private static float floatType=0F;
private static double doubleType=6D;
private static boolean booleanType=Boolean.TRUE;
private static char charType='a';
private static final String stringObject = "ABC";
Smali代码:
# direct methods 静态字段赋值
.method static constructor ()V
.registers 2 #.registers指令表示有2个寄存器可用
.prologue #.prologue 方法开始
.line 10 #行号
const/4 v0, 0x0 #
sput v0, Lcom/erlin/smali/SmaliParse;->floatType:F
.line 11
const-wide/16 v0, 0x0
sput-wide v0, Lcom/erlin/smali/SmaliParse;->doubleType:D
.line 12
sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean; #取Boolean对象实例,赋值给v0
invoke-virtual {v0}, Ljava/lang/Boolean;->booleanValue()Z
move-result v0 #将Boolean.TRUE值赋于v0寄存器
sput-boolean v0, Lcom/erlin/smali/SmaliParse;->booleanType:Z #将v0寄存器的值赋于booleanType字段
.line 13
const/16 v0, 0x61
sput-char v0, Lcom/erlin/smali/SmaliParse;->charType:C
return-void
.end method
# direct methods 实例字段赋值
.method public constructor ()V
.registers 3 #.registers指令表示有3个寄存器可用
.prologue
const/4 v0, 0x0 #将0赋值给v0
.line 3
invoke-direct {p0}, Ljava/lang/Object;->()V
.line 4
iput-byte v0, p0, Lcom/erlin/smali/SmaliParse;->byteType:B #p0代表this,将v0的值赋值给byteType字段
.line 5
iput-short v0, p0, Lcom/erlin/smali/SmaliParse;->shortType:S
.line 6
iput v0, p0, Lcom/erlin/smali/SmaliParse;->intType:I
.line 7
const-wide/16 v0, 0x0
iput-wide v0, p0, Lcom/erlin/smali/SmaliParse;->longType:J
.line 8
const/4 v0, 0x5 #数组长度赋值给v0寄存器
new-array v0, v0, [I #创建指定类型[I即int数组,长度为v0即5,并将数组引用赋值于v0寄存器
fill-array-data v0, :array_18 #用指定标记array_18处的数据填充数组
iput-object v0, p0, Lcom/erlin/smali/SmaliParse;->intArray:[I #为数组赋值
return-void
nop #空 指令
:array_18
.array-data 4
0x0
0x1
0x2
0x3
0x4
.end array-data
.end method
四、Smali空指令
指令 | 描述 |
---|---|
nop | 空操作指令,通常用于代码对齐,不进行实际操作,值为00 |
五、Smali数组操作指令
数组操作指令包括读取数组长度、新建数组、数组赋值、数组元素取值与赋值等操作。
指令 | 描述 |
---|---|
array-length vA,vB | 获取给定vB寄存器中数组的长度并将值赋给vA寄存器 |
new-array vA,vB,type@CCCC | 构造指定类型(type@CCCC)与大小(vB)的数组,并将值赋给vA寄存器 |
new-array/jumbo vAAAA,vBBBB,type@CCCCCCCC | 指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大 |
filled-new-array {vC,vD,vE,vF,vG},type@BBBB | 构造指定类型(type@BBBB)与大小(vA)的数组并填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还制订了参数的个数,vC~vG是使用到的参数寄存器序列 |
filled-new-array/range {vCCCC, … ,vNNNN},type@BBBB | 指定功能与上一条指令相同,只是参数寄存器使用range字节码后缀指定了取值范围,vC是第一个参数寄存器, N=A+C-1。 |
filled-new-array/jumbo {vCCCC, … ,vNNNN},type@BBBBBBBB | 指令功能与上一条指令相同,只是寄存器与指令的索引取值范围更大 |
arrayop vAA,vBB,vCC | 对vBB寄存器指定的数组元素进入取值与赋值。vCC寄存器指定数组元素索引,vAA寄存器用来寄放读取的或需要设置的数组元素的值。读取元素使用 aget类指令,元素赋值使用aput指令,元素赋值使用aput类指令,根据数组中存储的类型指令后面会紧跟不同的指令后缀,指令列表有aget、 aget-wide、aget-object、aget-boolean、aget-byte、aget-char、aget-short、aput、 aput-wide、aput-boolean、aput-byte、aput-char、aput-short。 |
java代码:
public void array() {
int[] intArray = {10, -1, 9};
int len = intArray.length;
String[] stringArray = new String[len];
stringArray[0] = "A";
stringArray[1] = "B";
stringArray[2] = "C";
}
Smali代码:
.method public array()V
.registers 6 #.registers 声明6个寄存器
.prologue
.line 5
const/4 v3, 0x3 #将0x3寄存给v3寄存器
new-array v0, v3, [I #创建[I类型长度为v3寄存器数组,引用赋值给v0寄存器
fill-array-data v0, :array_1a #用array_1a标记处数据,赋值于v0寄存器
.line 6
.local v0, "intArray":[I #创建指定类型数组,并用v0寄存器中的值填充数据,赋于寄存器v0
array-length v1, v0 #获取v0寄存器长度,赋值给v1寄存器
.line 8
.local v1, "len":I
new-array v2, v1, [Ljava/lang/String;
.line 9
.local v2, "stringArray":[Ljava/lang/String;
const/4 v3, 0x0
const-string v4, "A"
aput-object v4, v2, v3 #v4寄存器值,赋值给v2寄存器数组,数组索引为v3
.line 10
const/4 v3, 0x1
const-string v4, "B"
aput-object v4, v2, v3
.line 11
const/4 v3, 0x2
const-string v4, "C"
aput-object v4, v2, v3
.line 12
return-void
.line 5
nop
:array_1a
.array-data 4
0xa
-0x1
0x9
.end array-data
.end method
六、Smali类指令,Smali方法指令,Smali返回指令
- Smali类指令
类指令 | 描述 |
---|---|
.class <访问权限> [修饰关键字] L<完整类名>; | 表示类 |
.super L<父类完整类名>; | 父类 |
.source "Java类名" | java文件名 |
注解指令 | |
.annotation | [注解属性] <注解类名> |
value = {值列表} | |
.end annotation | 注解结束 |
接口指令 | |
.implements<接口名> | 接口名 |
例1 Java类:
//java
package com.erlin.smali;
public class SmaliParse {//基类Object
//类
}
//Smali
.class public Lcom/erlin/smali/SmaliParse;
.super Ljava/lang/Object;
.source "SmaliParse.java"
例2 Java final类:
//Java
package com.erlin.smali;
public final class SmaliParse {//基类Object
//类
}
//Smali
.class public final Lcom/erlin/smali/SmaliParse;
.super Ljava/lang/Object;
.source "SmaliParse.java"
例3 Java Interface类
//Java
package com.erlin.smali;
public interface Interface {
void interfaceMethod();
}
//Smali
.class public interface abstract Lcom/erlin/smali/Interface;
.super Ljava/lang/Object;
.source "Interface.java"
# virtual methods
.method public abstract interfaceMethod()V
.end method
例4 Java Interface类实现
//Java
package com.erlin.smali;
public class InterfaceImpl implements Interface{
@Override
public void interfaceMethod() {
}
}
//Smali
.class public Lcom/erlin/smali/InterfaceImpl;
.super Ljava/lang/Object;
.source "InterfaceImpl.java"
# interfaces
.implements Lcom/erlin/smali/Interface;
# direct methods
.method public constructor ()V
.registers 1
.prologue
.line 3
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
# virtual methods
.method public interfaceMethod()V
.registers 1
.prologue
.line 7
return-void
.end method
例5 抽象类
//Java
package com.erlin.smali;
public abstract class AbstractClass {
abstract void abstractMethod();
public void method(){
}
}
//Smali
.class public abstract Lcom/erlin/smali/AbstractClass;
.super Ljava/lang/Object;
.source "AbstractClass.java"
# direct methods
.method public constructor ()V
.registers 1
.prologue
.line 3
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
# virtual methods
.method abstract abstractMethod()V
.end method
.method public method()V
.registers 1
.prologue
.line 8
return-void
.end method
例6 内部类、内部接口、内部抽象类
SmaliParse.java
//Java
package com.erlin.smali;
public final class SmaliParse {
//内部类
public class InnerClass{
public void method(){}
}
//内部接口
public interface InnerInterface{
void interfaceMethod();
}
//内部抽象类
public abstract class InnerAbstractClass{
abstract void interfaceMethod();
public void method(){}
}
//内部类继承
public class InnerClassExtends extends InnerClass{
public void method(){}
}
//内部接口实现
class InnerInterfaceImpl implements InnerInterface{
public void method(){}
@Override
public void interfaceMethod() {
}
}
//内部抽象类继承
class InnerAbstractClassExtends extends InnerAbstractClass{
public void method(){}
@Override
void interfaceMethod() {
}
}
}
SmaliParse.Smali文件
.class public final Lcom/erlin/smali/SmaliParse;
.super Ljava/lang/Object;
.source "SmaliParse.java"
# annotations
.annotation system Ldalvik/annotation/MemberClasses;
value = {
Lcom/erlin/smali/SmaliParse$InnerAbstractClassExtends;,
Lcom/erlin/smali/SmaliParse$InnerInterfaceImpl;,
Lcom/erlin/smali/SmaliParse$InnerClassExtends;,
Lcom/erlin/smali/SmaliParse$InnerAbstractClass;,
Lcom/erlin/smali/SmaliParse$InnerInterface1;,
Lcom/erlin/smali/SmaliParse$InnerInterface;,
Lcom/erlin/smali/SmaliParse$InnerClass;
}
.end annotation
# direct methods
.method public constructor ()V
.registers 1
.prologue
.line 3
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
SmaliParse$InnerClass.smali文件
.class public Lcom/erlin/smali/SmaliParse$InnerClass;
.super Ljava/lang/Object;
.source "SmaliParse.java"
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/erlin/smali/SmaliParse;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x1
name = "InnerClass"
.end annotation
# instance fields
.field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
# direct methods
.method public constructor (Lcom/erlin/smali/SmaliParse;)V
.registers 2
.param p1, "this$0" # Lcom/erlin/smali/SmaliParse;
.prologue
.line 4
iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerClass;->this$0:Lcom/erlin/smali/SmaliParse;
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
# virtual methods
.method public method()V
.registers 1
.prologue
.line 5
return-void
.end method
SmaliParse$InnerInterface.smali
.class public interface abstract Lcom/erlin/smali/SmaliParse$InnerInterface;
.super Ljava/lang/Object;
.source "SmaliParse.java"
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/erlin/smali/SmaliParse;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x609
name = "InnerInterface"
.end annotation
# virtual methods
.method public abstract interfaceMethod()V
.end method
SmaliParse$InnerAbstractClass.smali
.class public abstract Lcom/erlin/smali/SmaliParse$InnerAbstractClass;
.super Ljava/lang/Object;
.source "SmaliParse.java"
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/erlin/smali/SmaliParse;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x401
name = "InnerAbstractClass"
.end annotation
# instance fields
.field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
# direct methods
.method public constructor (Lcom/erlin/smali/SmaliParse;)V
.registers 2
.param p1, "this$0" # Lcom/erlin/smali/SmaliParse;
.prologue
.line 15
iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerAbstractClass;->this$0:Lcom/erlin/smali/SmaliParse;
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
# virtual methods
.method abstract interfaceMethod()V
.end method
.method public method()V
.registers 1
.prologue
.line 17
return-void
.end method
SmaliParse$InnerInterfaceImpl.smali
.class Lcom/erlin/smali/SmaliParse$InnerInterfaceImpl;
.super Ljava/lang/Object;
.source "SmaliParse.java"
# interfaces
.implements Lcom/erlin/smali/SmaliParse$InnerInterface;
.implements Lcom/erlin/smali/SmaliParse$InnerInterface1;
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/erlin/smali/SmaliParse;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = "InnerInterfaceImpl"
.end annotation
# instance fields
.field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
# direct methods
.method constructor (Lcom/erlin/smali/SmaliParse;)V
.registers 2
.param p1, "this$0" # Lcom/erlin/smali/SmaliParse;
.prologue
.line 24
iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerInterfaceImpl;->this$0:Lcom/erlin/smali/SmaliParse;
invoke-direct {p0}, Ljava/lang/Object;->()V
return-void
.end method
# virtual methods
.method public interfaceMethod()V
.registers 1
.prologue
.line 29
return-void
.end method
.method public interfaceMethod1()V
.registers 1
.prologue
.line 34
return-void
.end method
.method public method()V
.registers 1
.prologue
.line 25
return-void
.end method
SmaliParse$InnerClassExtends.smali
.class public Lcom/erlin/smali/SmaliParse$InnerClassExtends;
.super Lcom/erlin/smali/SmaliParse$InnerClass;
.source "SmaliParse.java"
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/erlin/smali/SmaliParse;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x1
name = "InnerClassExtends"
.end annotation
# instance fields
.field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
# direct methods
.method public constructor (Lcom/erlin/smali/SmaliParse;)V
.registers 2
.param p1, "this$0" # Lcom/erlin/smali/SmaliParse;
.prologue
.line 20
iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerClassExtends;->this$0:Lcom/erlin/smali/SmaliParse;
invoke-direct {p0, p1}, Lcom/erlin/smali/SmaliParse$InnerClass;->(Lcom/erlin/smali/SmaliParse;)V
return-void
.end method
# virtual methods
.method public method()V
.registers 1
.prologue
.line 21
return-void
.end method
SmaliParse$InnerAbstractClassExtends.smali
.class Lcom/erlin/smali/SmaliParse$InnerAbstractClassExtends;
.super Lcom/erlin/smali/SmaliParse$InnerAbstractClass;
.source "SmaliParse.java"
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/erlin/smali/SmaliParse;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = "InnerAbstractClassExtends"
.end annotation
# instance fields
.field final synthetic this$0:Lcom/erlin/smali/SmaliParse;
# direct methods
.method constructor (Lcom/erlin/smali/SmaliParse;)V
.registers 2
.param p1, "this$0" # Lcom/erlin/smali/SmaliParse;
.prologue
.line 37
iput-object p1, p0, Lcom/erlin/smali/SmaliParse$InnerAbstractClassExtends;->this$0:Lcom/erlin/smali/SmaliParse;
invoke-direct {p0, p1}, Lcom/erlin/smali/SmaliParse$InnerAbstractClass;->(Lcom/erlin/smali/SmaliParse;)V
return-void
.end method
# virtual methods
.method interfaceMethod()V
.registers 1
.prologue
.line 42
return-void
.end method
.method public method()V
.registers 1
.prologue
.line 38
return-void
.end method
- Smali方法指令-静态方法
指令 | 描述 |
---|---|
.method <访问权限> static [修饰关键字] methodName()<类型> | |
.registers count | 方法内使用寄存器数量 |
.prologue | 方法开始 |
return-void | 方法返回数据类型 |
.end method | 方法结束 |
例1:
//Java
public static void methodStaticSmali(){
//静态方法
}
//Smali
.method public static methodStaticSmali()V
.registers 0
.prologue
return-void
.end method
例2:
//Java
public final static void methodStaticFinalSmali() {
//静态方法
}
//Smail
.method public static final methodStaticFinalSmali()V
.registers 0
.prologue
return-void
.end method
- Smali返回指令
指令 | 描述 |
---|---|
return-void | 返回Void类型 |
return vAA | 返回非32位对象类型值,返回值为8位寄存器vAA |
return-wide vAA | 返回非64位对象类型值,返回值为8位寄存器对vAA |
return-object vAA | 返回对象类型,返回值为8位寄存器对vAA |
代码对比:例1
// Java
public void methodSmali() {
}
//Smali
.method public methodSmali()V
.registers 1
.prologue
.line 6
return-void
.end method
代码对比:例2
//Java
public int methodSmaliInt(){
return Integer.MAX_VALUE;
}
//Smali
.method public methodSmaliInt()I
.registers 2
.prologue
.line 9
const v0, 0x7fffffff
return v0
.end method
代码对比:例3
//Java
public long methodSmaliLong(){
return Long.MAX_VALUE;
}
//Smali
.method public methodSmaliLong()J
.registers 3
.prologue
.line 13
const-wide v0, 0x7fffffffffffffffL
return-wide v0
.end method
代码对比:例4
//Java
public String methodSmaliString(){
return "String";
}
//Smali
.method public methodSmaliString()Ljava/lang/String;
.registers 2
.prologue
.line 17
const-string v0, "String"
return-object v0
.end method
七、方法操作指令
方法调用指令负责调用类实例的方法,基础指令为invoke。
指令 | 描述 |
---|---|
invoke-virtual{parameters}, methodtocall | 虚方法调用,调用的方法运行时确认实际调用,和实例引用的实际对象有关,动态确认的,一般是带有修饰符protected或public的方法. |
invoke-super {parameter},methodtocall | 直接调用父类的虚方法,编译时,静态确认的。 |
invoke-direct { parameters }, methodtocall | 没有被覆盖方法的调用,即不用动态根据实例所引用的调用,编译时,静态确认的,一般是private或 |
invoke-static {parameters}, methodtocall | 是类静态方法的调用,编译时,静态确定的 |
invoke-interface {parameters},methodtocall | 调用接口方法,调用的方法运行时确认实际调用,即会在运行时才确定一个实现此接口的对象 |
举例:
//Java
public void invokeMethod(){
BaseClassImpl baseClassImpl = new BaseClassImpl();
baseClassImpl.baseFinalMethod();
super.baseFinalMethod();
baseClassImpl.staticMethod();
((Interface)baseClassImpl).interfaceMethod();
baseClassImpl.method();
}
//Smali
.method public invokeMethod()V
.registers 2
.prologue
.line 17
new-instance v0, Lcom/erlin/smali/BaseClassImpl;
invoke-direct {v0}, Lcom/erlin/smali/BaseClassImpl;->()V
.line 18
.local v0, "baseClassImpl":Lcom/erlin/smali/BaseClassImpl;
invoke-virtual {v0}, Lcom/erlin/smali/BaseClassImpl;->baseFinalMethod()V
.line 19
invoke-super {p0}, Lcom/erlin/smali/BaseClass;->baseFinalMethod()V
.line 20
invoke-static {}, Lcom/erlin/smali/BaseClassImpl;->staticMethod()V
.line 21
invoke-interface {v0}, Lcom/erlin/smali/Interface;->interfaceMethod()V
.line 22
invoke-virtual {v0}, Lcom/erlin/smali/BaseClassImpl;->method()V
.line 23
return-void
.end method
八、实例操作指令
指令 | 描述 |
---|---|
instance-of vA, vB, type@CCCC | 用于判断vB寄存器中对象引用是否可以转换成指定的类型,如果可以转换vA寄存器值为1,否则vA寄存器值为0 例:if(innerClassExtends instanceof InnerClass){ } |
check-cast vAA, type@BBBB | 将vAA寄存器中的对象引用转换成指定的类型,如果不能转换则抛出ClassCatException异常。如果type@BBBB指定的是基本类型,那么对非基本类型的类型vAA来说,运行将会失败。 |
new-instance vAA,type@CCCC | 用于构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器。 |
举例:
//Java
public void instanceOperationMethod(){
InnerClass innerClass = new InnerClass();
InnerClassExtends innerClassExtends = (InnerClassExtends)innerClass;
if(innerClass instanceof InnerClassExtends){
}
}
//Smali
# virtual methods
.method public instanceOperationMethod()V
.registers 4
.prologue
.line 41
new-instance v0, Lcom/erlin/smali/SmaliParse$InnerClass;
invoke-direct {v0, p0}, Lcom/erlin/smali/SmaliParse$InnerClass;->(Lcom/erlin/smali/SmaliParse;)V
.local v0, "innerClass":Lcom/erlin/smali/SmaliParse$InnerClass;
move-object v1, v0
.line 42
check-cast v1, Lcom/erlin/smali/SmaliParse$InnerClassExtends;
.line 44
.local v1, "innerClassExtends":Lcom/erlin/smali/SmaliParse$InnerClassExtends;
instance-of v2, v0, Lcom/erlin/smali/SmaliParse$InnerClassExtends;
if-eqz v2, :cond_c
.line 47
:cond_c
return-void
.end method
九、Smali数据运算指令
- Smali算数运算:加、减、乘、除、模(取余)
指令 | 描述 |
---|---|
add-type vAA, vBB, vCC | 加:type 类型后缀包括 int、long、float、double,vAA=(vBB+vCC) |
sub-type vAA, vBB, vCC | 减:type 类型后缀包括 int、long、float、double,vAA=(vBB-vCC) |
mul-type vAA, vBB, vCC | 乘:type 类型后缀包括 int、long、float、double,vAA=(vBB*vCC) |
div-type vAA, vBB, vCC | 除:type 类型后缀包括 int、long、float、double,vAA=(vBB/vCC) |
rem-type vAA, vBB, vCC | 模:type 类型后缀包括 int、long、float、double,vAA=(vBB%vCC) |
Java代码:
public void number(){
int a = 3;
int b = 7;
int add = a+b;
int sub = b-a;
int mul = a*b;
int div = b/a;
int rem = a%b;
a++;
b--;
a+=b;
b+=a;
a*=b;
b*=a;
a/=b;
b/=a;
a%=b;
b%=a;
}
Smali代码:
.method public number()V
.registers 8
.prologue
.line 5
const/4 v0, 0x3
.line 6
.local v0, "a":I
const/4 v2, 0x7
.line 8
.local v2, "b":I
add-int v1, v0, v2 #v1 = v0+v2
.line 9
.local v1, "add":I
sub-int v6, v2, v0 #v6=v2-v0
.line 10
.local v6, "sub":I
mul-int v4, v0, v2 #v4=v0*v2
.line 11
.local v4, "mul":I
div-int v3, v2, v0 #v3=v2/v0
.line 12
.local v3, "div":I
rem-int v5, v0, v2 #v5=v0%v2
.line 14
.local v5, "rem":I
add-int/lit8 v0, v0, 0x1 #v0=v0+0x1即 ++ 运算符
.line 15
add-int/lit8 v2, v2, -0x1 #v2=v2-0x1即 -- 运算符
.line 17
add-int/lit8 v0, v0, 0x6 #v0=v0+0x6
.line 18
add-int/lit8 v2, v2, 0xa #v2=v2+0xa
.line 20
mul-int/lit8 v0, v0, 0x10
.line 21
mul-int/lit16 v2, v2, 0xa0
.line 23
div-int/2addr v0, v2 #v0=v0/v2
.line 24
div-int/2addr v2, v0
.line 26
rem-int/2addr v0, v2 #v0=v0%v2
.line 27
rem-int/2addr v2, v0
.line 28
return-void
.end method
- Smali位运算符:&、|、^、<<、>>
指令 | 描述 |
---|---|
and-type vAA, vBB, vCC | and:type类型后缀包括 int、long、float、double,vAA=(vBB and vCC) |
or-type vAA, vBB, vCC | or:type类型后缀包括 int、long、float、double,vAA=(vBB or vCC) |
xor-type vAA, vBB, vCC | xor:type类型后缀包括 int、long、float、double,vAA=(vBB xor vCC) |
shl-type vAA, vBB, vCC | 有符号左移:type类型后缀包括 int、long、float、double,vAA=(vBB << vCC) |
shr-type vAA, vBB, vCC | 有符号右移:type类型后缀包括 int、long、float、double,vAA=(vBB >> vCC) |
ushr-type vAA, vBB, vCC | 无符号右移:type类型后缀包括 int、long、float、double,vAA=(vBB >> vCC) |
Java代码:
public void number(){
int a = 3;
int b = 7;
int c = (a&b);
c = (a|b);
c = (a^b);
c=(a<>b);
}
Smali代码:
.method public number()V
.registers 4
.prologue
.line 5
const/4 v0, 0x3
.line 6
.local v0, "a":I
const/4 v1, 0x7
.line 8
.local v1, "b":I
and-int v2, v0, v1
.line 9
.local v2, "c":I
or-int v2, v0, v1
.line 10
xor-int v2, v0, v1
.line 11
shl-int v2, v0, v1
.line 12
shr-int v2, v0, v1
.line 13
return-void
.end method
十、goto跳转指令
- 无条件跳转
指令 | 描述 |
---|---|
goto +AA | 无条件跳转到指定偏移处,偏移量不能为0,偏移宽度为8位 |
goto/16 +AAAA | 无条件跳转到指定偏移处,偏移量不能为0,偏移宽度为16位 |
goto/32 +AAAAAAAA | 无条件跳转到指定偏移处,偏移量不能为0,偏移宽度为32位 |
代码参见 十一、for/whlie 循环
十一、if跳转指令
- if-test vA, vB, +CCCC:
指令 | 描述 |
---|---|
if-ne vA, vB, +CCCC | 如果vA!=vB,则跳转到CCCC位置 |
if-eq vA, vB, +CCCC | 如果vA==vB,则跳转到CCCC位置 |
if-lt vA, vB, +CCCC | 如果vA < vB,则跳转到CCCC位置 |
if-le vA, vB, +CCCC | 如果vA <= vB,则跳转到CCCC位置 |
if-gt vA, vB, +CCCC | 如果vA > vB,则跳转到CCCC位置 |
if-ge vA, vB, :CCCC | 如果vA >= vB,则跳转到CCCC位置 |
Java代码:
public void ifSmali(){
int a = 8;
int b = 8;
if(a == b){
a+=a;
}else if(a!=b){
b+=b;
}else if(ab){
b+=a;
}else if(a>=b){
a+=1;
}else if(a<=b){
b+=1;
}else{
a+=2;
}
}
Smali代码:
.method public ifSmali()V
.registers 3
.prologue
.line 19
const/16 v0, 0x8
.line 20
.local v0, "a":I
const/16 v1, 0x8
.line 21
.local v1, "b":I
if-ne v0, v1, :cond_8
.line 22
add-int/2addr v0, v0
.line 36
:goto_7
return-void
.line 23
:cond_8
if-eq v0, v1, :cond_c
.line 24
add-int/2addr v1, v1
goto :goto_7
.line 25
:cond_c
if-ge v0, v1, :cond_10
.line 26
add-int/2addr v0, v1
goto :goto_7
.line 27
:cond_10
if-le v0, v1, :cond_14
.line 28
add-int/2addr v1, v0
goto :goto_7
.line 29
:cond_14
if-lt v0, v1, :cond_19
.line 30
add-int/lit8 v0, v0, 0x1
goto :goto_7
.line 31
:cond_19
if-gt v0, v1, :cond_1e
.line 32
add-int/lit8 v1, v1, 0x1
goto :goto_7
.line 34
:cond_1e
add-int/lit8 v0, v0, 0x2
goto :goto_7
.end method
- if-testz vAA, +BBBB
指令 | 描述 |
---|---|
if-eqz vAA,+BBBB | 如果vAA==0,则跳转到BBBB |
if-nez vAA,+BBBB | 如果vAA!=0,则跳转到BBBB |
if-ltz vAA,+BBBB | 如果vAA<0,则跳转到BBBB |
if-lez vAA,+BBBB | 如果vAA<=0,则跳转到BBBB |
if-gtz vAA,+BBBB | 如果vAA>0,则跳转到BBBB |
if-gez vAA,+BBBB | 如果vAA>=0,则跳转到BBBB |
Java代码
public void ifSmali(){
int a = 0;
boolean b = false;
if(b){
a++;
}else if(!b){
b=!b;
}else if(a<0){
a++;
}else if(a>0){
a++;
}else if(a>=0){
a+=1;
}else if(a<=0){
a++;
}else{
a+=2;
}
}
Smali代码
.method public ifSmali()V
.registers 3
.prologue
.line 39
const/4 v0, 0x0
.line 40
.local v0, "a":I
const/4 v1, 0x0
.line 41
.local v1, "b":Z
if-eqz v1, :cond_7
.line 42
add-int/lit8 v0, v0, 0x1
.line 56
:goto_6
return-void
.line 43
:cond_7
if-nez v1, :cond_f
.line 44
if-nez v1, :cond_d
const/4 v1, 0x1
:goto_c
goto :goto_6
:cond_d
const/4 v1, 0x0
goto :goto_c
.line 45
:cond_f
if-gez v0, :cond_14
.line 46
add-int/lit8 v0, v0, 0x1
goto :goto_6
.line 47
:cond_14
if-lez v0, :cond_19
.line 48
add-int/lit8 v0, v0, 0x1
goto :goto_6
.line 49
:cond_19
if-ltz v0, :cond_1e
.line 50
add-int/lit8 v0, v0, 0x1
goto :goto_6
.line 51
:cond_1e
if-gtz v0, :cond_23
.line 52
add-int/lit8 v0, v0, 0x1
goto :goto_6
.line 54
:cond_23
add-int/lit8 v0, v0, 0x2
goto :goto_6
.end method
十二、switch跳转指令
指令 | 描述 |
---|---|
sparse-switch vAA, +BBBBBBBB | 分支跳转指令:vAA寄存器为switch分支中需要判断的值,BBBBBBBB指向一个sparse-switch-payload格式的偏移表,表中的值是无规律的偏移量。 |
Smali偏移表-整形顺序结构:
packed-switch p1, :pswitch_data_c #偏移表pswitch_data_c
add-int/lit8 p1, p1, 0x1 #如果 switch 表没有命中case,则顺序执行代码,即default
:pswitch_6
add-int/lit8 p1, p1, 0x1
:pswitch_9
add-int/lit8 p1, p1, -0x1
:pswitch_data_c #偏移表位置
.packed-switch 0x0 #指定头偏移为0x0
:pswitch_6 #case 0
:pswitch_9 #case 1
.end packed-switch
Smali偏移表-整形非顺序结构:
sparse-switch p1, :sswitch_data_c
add-int/lit8 p1, p1, 0x1 #如果 switch 表没有命中case,则顺序执行代码,即default
:sswitch_6
add-int/lit8 p1, p1, 0x1
:sswitch_9
add-int/lit8 p1, p1, -0x1
:sswitch_data_c
.sparse-switch
0x50 -> :sswitch_6 #case 80
0x3f1 -> :sswitch_9 #case 1009
.end sparse-switch
Java代码:
public void switchSmali(int value) {
switch (value) {
case 0:
value++;
break;
case 1:
value--;
break;
default:
++value;
break;
}
}
Smali顺序结构代码:
.method public switchSmali(I)V
.registers 2
.param p1, "value" # I
.prologue
.line 5
packed-switch p1, :pswitch_data_c
.line 13
add-int/lit8 p1, p1, 0x1
.line 16
:goto_5
return-void
.line 7
:pswitch_6
add-int/lit8 p1, p1, 0x1
.line 8
goto :goto_5
.line 10
:pswitch_9
add-int/lit8 p1, p1, -0x1
.line 11
goto :goto_5
.line 5
:pswitch_data_c
.packed-switch 0x0
:pswitch_6
:pswitch_9
.end packed-switch
.end method
Java代码
public void switchSmali(int value) {
switch (value) {
case 80:
value++;
break;
case 1009:
value--;
break;
default:
++value;
break;
}
}
Smali非顺序结构代码:
.method public switchSmali(I)V
.registers 2
.param p1, "value" # I
.prologue
.line 7
sparse-switch p1, :sswitch_data_c
.line 15
add-int/lit8 p1, p1, 0x1
.line 18
:goto_5
return-void
.line 9
:sswitch_6
add-int/lit8 p1, p1, 0x1
.line 10
goto :goto_5
.line 12
:sswitch_9
add-int/lit8 p1, p1, -0x1
.line 13
goto :goto_5
.line 7
:sswitch_data_c
.sparse-switch
0x50 -> :sswitch_6
0x3f1 -> :sswitch_9
.end sparse-switch
.end method
十三、for/whlie 循环
for/whlie循环最终表现的Smali指令形式是goto指令,参见 八、goto跳转指令
Smali循环基础代码:
:goto_1 #goto标签
if-ge vAA, vBB, :+CCCCCCCC #vAA寄存器>=vBB寄存器,跳至+CCCCCCCC即循环体外
add-int/lit8 vAA, vAA, 0x1 #条件递增或递减
goto :goto_1 #goto跳转到goto_1标签
:+CCCCCCCC
#for循环之外的代码
for循环代码:
//Java代码
public void forSmali(){
for(int i=0;i<100;i++){
}
}
//Smail代码
.method public forSmali()V
.registers 3
.prologue
.line 66
const/4 v0, 0x0
.local v0, "i":I
:goto_1
const/16 v1, 0x64
if-ge v0, v1, :cond_8
add-int/lit8 v0, v0, 0x1
goto :goto_1
.line 70
:cond_8
return-void
.end method
while循环代码:
//Java
public void whileSmali(){
int i = 0;
while (i<100){
i++;
}
}
//Smali
.method public whileSmali()V
.registers 3
.prologue
.line 73
const/4 v0, 0x0
.line 74
.local v0, "i":I
:goto_1
const/16 v1, 0x64
if-ge v0, v1, :cond_8
.line 75
add-int/lit8 v0, v0, 0x1
goto :goto_1
.line 77
:cond_8
return-void
.end method
十四、try/catch
指令 | 描述 |
---|---|
:try_start_标号 | try的开始 |
:try_end_标号 | try的结束 |
.catch <异常类型> {< try_start_标号> .. < try_end_标号>} < catch_标号> | .catch指令:catch指令指明异常类型,指明try块的开始和结束,如果异常捕获成功,则会跳转到catch_标号处,如果捕获不成功,则顺序执行代码 |
try/catch Smali基础代码:
:try_start_0
const-string v0, "a"
invoke-static {v0}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
:try_end_5
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_5} :catch_6
:goto_5
return-void
:catch_6
move-exception v0
goto :goto_5
try/catch代码
//Java
public void tryCatchSmali() {
try {
Integer.valueOf("a");
} catch (Exception e) {
}
}
//Smali
.method public tryCatchSmali()V
.registers 2
.prologue
.line 81
:try_start_0
const-string v0, "a"
invoke-static {v0}, Ljava/lang/Integer;->valueOf(Ljava/lang/String;)Ljava/lang/Integer;
:try_end_5
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_5} :catch_6
.line 85
:goto_5
return-void
.line 82
:catch_6
move-exception v0
goto :goto_5
.end method