美文网首页
Smali语法与Java语法对比

Smali语法与Java语法对比

作者: 尔林 | 来源:发表于2019-04-07 14:47 被阅读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数据定义指令、字段操作指令:

    • 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 <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返回指令

    • 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
    
    
    • 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或<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数据运算指令

    • 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);
        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(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-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
    

    相关文章

      网友评论

          本文标题:Smali语法与Java语法对比

          本文链接:https://www.haomeiwen.com/subject/fpshiqtx.html