Smali语法与Java语法对比

2019-04-07  本文已影响0人  尔林

注意: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数据定义指令、字段操作指令:

指令 描述
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
指令 描述
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
指令 描述
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 <clinit>()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 <init>()V
    .registers 3 #.registers指令表示有3个寄存器可用

    .prologue
    const/4 v0, 0x0 #将0赋值给v0

    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()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返回指令

类指令 描述
.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 <init>()V
    .registers 1

    .prologue
    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()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 <init>()V
    .registers 1

    .prologue
    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()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 <init>()V
    .registers 1

    .prologue
    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()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 <init>(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;-><init>()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 <init>(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;-><init>()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 <init>(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;-><init>()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 <init>(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;-><init>(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 <init>(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;-><init>(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

指令 描述
.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
指令 描述
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或<init>方法;
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;-><init>()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;-><init>(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数据运算指令

指令 描述
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
指令 描述
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);
    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-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(a<b){
        a+=b;
    }else if(a>b){
        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-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
上一篇下一篇

猜你喜欢

热点阅读