Table of Contents:
  1. Dalvik虚拟机解释语言:Smali
    1. Smali与Baksmali介绍
      1. 什么是JVM、Dalvik、ART
        1. 类型
          1. 方法返回关键字
            1. 使用对应关系表
          2. 方法调用关键字
            1. invoke-virtual
            2. invoke-direct
            3. invoke-static
            4. invoke-super
            5. invoke-interface
          3. Smali的声明语法
            1. 类申明
            2. 字段申明
            3. 常量申明
            4. 方法/函数申明
            5. 构造方法/构造函数申明
            6. 静态代码块的申明
          4. 创建对象
            1. 数据定义
              1. 取值与赋值
                1. 条件判断与跳转
                  1. 寄存器
                    1. 常用关键字
                      1. 参考

                      Dalvik虚拟机解释语言:Smali

                      Reading Time:The full text has 2263 words, estimated reading time: 12 minutes
                      Creation Date:2023-10-14
                      Article Tags:
                       
                      BEGIN

                      Smali与Baksmali介绍

                      1. Dalvik是冰岛的一个渔村,在冰岛语中,Smali表示汇编,Baksmali表示反汇编
                      2. Smali语法大致基于Jasmin与Dedexer的语法
                      3. Smali语法用来标记Dalvik字节码,并支持dex格式的全部功能,如注释、调试信息、行信息等
                      4. Smali对应Java的smali文件转化成dex文件的汇编器
                      5. Baksmali对应Java的dex文件转化成smali文件的反汇编器

                      什么是JVM、Dalvik、ART

                      1. JVM是JAVA虚拟机,运行JAVA字节码程序
                      2. Dalvik是Google专门为Android设计的一个虚拟机,Dalvik有专属的文件执行格式dex(Dalvik executable)
                      3. Art(Android Runtime)相当于Dalvik的升级版,本质与Dalvik无异

                      类型

                      Smali类型Java类型
                      Vvoid
                      Zboolean
                      Bbyte
                      Sshort
                      Cchar
                      Iint
                      Jlong (64 bits)
                      Ffloat
                      Ddouble (64 bits)
                      L对象类型
                      [数组类型

                      方法返回关键字

                      主要有四种方法:

                      1. return-void
                      2. return-object
                      3. return
                      4. return-wide

                      使用对应关系表

                      数据类型Smali对应的方法返回关键字
                      Vreturn-void
                      Zreturn
                      Breturn
                      Sreutrn
                      Creturn
                      Ireutrn
                      Jreturn-wide
                      Freturn
                      Dreturn-wide
                      Lreturn-object
                      [return-object

                      方法调用关键字

                      1. invoke-virtual: 用于非私有实例方法的调用
                      2. invoke-direct: 用于构造方法以及私有方法的调用
                      3. invoke-static: 静态方法的调用
                      4. invoke-super: 父类方法的调用
                      5. invoke-interface: 接口方法的调用

                      invoke-virtual

                      调用方法:invoke-virtual {参数}, 方法所属类名;->方法名(参数类型)返回值类型;

                      Java代码:

                      public class Test {
                        public Test(string a) {
                          getName()
                        }
                        public String getName() {
                          return "Hello"
                        }
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public constructor <init>(Ljava/lang/String;)V
                        invoke-direct {p0}, Ljava/lang/Object;-><init>()V # 调用父类构造方法
                        invoke-virtual {p0}, LTest;->getName()Ljava/lang/String; # 调用成员方法
                        return-void
                      .end method
                      .method public getName()Ljava/lang/String;
                        const-string v0, "Hello" # 定义局部字符串常量
                        return-object v0 # 返回常量
                      .end method

                      invoke-direct

                      调用方法:invoke-direct {参数}, 方法所属类名;->方法名(参数类型)返回值类型;

                      Java代码:

                      public class Test {
                        public Test(string a) {
                          getName()
                        }
                        private String getName() {
                          return "Hello"
                        }
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public constructor <init>(Ljava/lang/String;)V
                        invoke-direct {p0}, Ljava/lang/Object;-><init>()V # 调用父类构造方法
                        invoke-direct {p0}, LTest;->getName()Ljava/lang/String; # 调用成员方法
                        return-void
                      .end method
                      .method public getName()Ljava/lang/String;
                        const-string v0, "Hello" # 定义局部字符串常量
                        return-object v0 # 返回常量
                      .end method

                      invoke-static

                      调用方法:invoke-static {参数}, 方法所属类名;->方法名(参数类型)返回值类型;

                      Java代码:

                      public class Test {
                        public Test(string a) {
                          String b = getName()
                          System.out.print(b)
                        }
                        private static String getName() {
                          return "Hello"
                        }
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public constructor <init>(Ljava/lang/String;)V
                        invoke-direct {p0}, Ljava/lang/Object;-><init>()V # 调用父类构造方法
                        invoke-static {p0}, LTest;->getName()Ljava/lang/String; # 调用成员方法
                        move-result-object v0 # 将返回值赋值给v0
                        return-void
                      .end method
                      .method public getName()Ljava/lang/String;
                        const-string v0, "Hello" # 定义局部字符串常量
                        return-object v0 # 返回常量
                      .end method

                      invoke-super

                      调用方法:invoke-super {参数}, 方法所属类名;->方法名(参数类型)返回值类型;

                      Java代码:

                      @override
                      protected void onCreate(Bundle savedInstanceState) {
                        super.onCreate(savedInstanceState);
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      .method protected onCreate(Landroid/os/Boundle;)V
                        .registers 2
                        invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Boundle;)V
                        return-void
                      .end method

                      invoke-interface

                      调用方法:invoke-interface {参数}, 方法所属类名;->方法名(参数类型)返回值类型;

                      Java代码:

                      public class Test {
                        private InterTest a = new Test2()
                        public Test(string a) {}
                        public void setAa() {
                          InterTest aa = a
                          aa.est2()
                        }
                        public class Test2 implements InterTest {
                          public Test2(){}
                          public void est2(){}
                        }
                        interface InterTest {
                          public void est2();
                        }
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      .method public constructor <init>(Ljava/lang/String;)V
                        invoke-direct {p0}, Ljava/lang/Object;-><init>()V
                        return-void
                      .end method
                      
                      .method public setAa()V
                        .registers 2
                        iget-object v0, p0, LTest;->a:LTest$InterTest;
                        invoke-interface {v0}, LTest$InterTest;->est2()V
                        return-void
                      .end method

                      Smali的声明语法

                      类申明

                      声明语法:.class 权限修饰符 类名

                      Java代码:

                      public class Test implements CharSequence {
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      .implements Ljava/lang/CharSequence; # 对应的接口代码
                      .source "Test.java" # 对应的源文件, 非必须

                      字段申明

                      声明语法:.field 权限修饰符 静态修饰符 变量名:变量全类名路径

                      Java代码:

                      public class Test {
                        private static String a;
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .field private static a:Ljava/lang/String;

                      常量申明

                      声明语法:.field 权限修饰符 静态修饰符 final 变量名:变量全类名路径 = 常量值

                      Java代码:

                      public class Test {
                        private static final String a = "hello";
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .field private static final a:Ljava/lang/String; = "Hello"

                      方法/函数申明

                      声明语法:

                      .method 权限修饰符 静态修饰符 方法名(参数)返回值类型
                        # 方法体
                      .end method # 方法结尾标识

                      不带参数不带返回值

                      Java代码:

                      public class Test {
                        public static void getName() {}
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public static getName()V
                        return-void
                      .end method

                      带参数带返回值

                      Java代码:

                      public class Test {
                        public static void getName(String a, Int b) {
                          return "Hello"
                        }
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public static getName(Ljava/lang/String; Ijava/lang/Int)V
                        const-string v0, "Hello"
                        return-object v0
                      .end method

                      构造方法/构造函数申明

                      声明语法:

                      .method 权限修饰符 constructor <init>(参数)返回值类型
                        # 方法体
                      .end method # 方法结尾标识

                      Java代码:

                      public class Test {
                        public Test() {}
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public constructor <init>(Ljava/lang/String;)V
                        invoke-direct {p0}, Ljava/lang/Object;-><init>()V # 调用父类的构造方法
                        return-void
                      .end method

                      静态代码块的申明

                      声明语法:

                      .method static constructor <clinit>()V
                        # 方法体
                      .end method # 方法结尾标识

                      Java代码:

                      public class Test {
                        static{}
                      }

                      对应Smali语法:

                      .class public LTest; # 申明类
                      .super Ljava/lang/Object; # 申明父类
                      
                      .method public static constructor <clinit>()V
                        return-void
                      .end method

                      创建对象

                      对象的创建分两步:

                      1. 声明实例:new-instance 变量名, 对象全包名路径;
                      2. 调用构造方法:invoke-direct {变量名}, 对象全包名路径;-><init>(参数)返回类型

                      Java代码:

                      class Test{}
                      new Test()

                      对应Smali语法:

                      new-instance v0, LTest;
                      invoke-direct {v0}, LTest;-><init>()V

                      数据定义

                      关键词含义示例
                      const-string | 用于定义字符串const-string v0, "Hello"
                      const-class定义字节码对象const-class v0, LGoActivity;
                      const/4定义一个容器,最大存放4字节数值const/4 v0, 0x2
                      const/16定义一个容器,最大存放16字节数值const/16 v0, 0xABCD
                      const/hight16定义一个容器,最大存放高16字节数值const v0, 0xA
                      const定义一个容器,最大存放32字节数值const v0, 0xA
                      const-wide定义两个相连容器,最大存放64字节数值-
                      const-wide/16定义两个相连容器,最大存放16字节数值-
                      const-wide/32定义两个相连容器,最大存放32字节数值-
                      const-wide/hight16定义两个相连容器,最大存放高16字节数值-

                      取值与赋值

                      取值使用iget/sget,赋值使用iput/sput,其中i表示instance(实例)用于实例属性,s表示static(静态)用于静态属性

                      Smali类型取值赋值
                      Ziget-booleaniput-boolean
                      Biget-byteiput-byte
                      Siget-shortiput-short
                      Ciget-chariput-char
                      Iigetiput
                      Jiget-wideiput-wide
                      Figetiput
                      Diget-wideiput-wide

                      条件判断与跳转

                      关键词英文助记举例含义
                      if-eqequalif-eq v0, v1, :cond_*如果v0等于v1则跳转到cond_*
                      if-nenot equalif-ne v0, v1, :cond_*如果v0不等于v1则跳转到cond_*
                      if-ltless thanif-lt v0, v1, :cond_*如果v0小于v1则跳转到cond_*
                      if-leless equalif-le v0, v1, :cond_*如果v0小于等于v1则跳转到cond_*
                      if-gtgreater thenif-gt v0, v1, :cond_*如果v0大于v1则跳转到cond_*
                      if-gegreater equalif-ge v0, v1, :cond_*如果v0大于等于v1则跳转到cond_*
                      if-eqzequal zeroif-eqz v0, :cond_*如果v0等于0则跳转到cond_*
                      if-neznot equal zeroif-nez v0, :cond_*如果v0不等于0则跳转到cond_*
                      if-ltzless than zeroif-ltz v0, :cond_*如果v0小于0则跳转到cond_*
                      if-lezless equal zeroif-lez v0, :cond_*如果v0小于等于0则跳转到cond_*
                      if-gtzgreater then zeroif-gtz v0, :cond_*如果v0大于0则跳转到cond_*
                      if-gezgreater equal zeroif-gez v0, :cond_*如果v0大于等于0则跳转到cond_*

                      寄存器

                      Dalvik 使用的寄存器是32位的,对于64位类型的变量,如double类型,它会使用两个相邻的寄存器来表示.

                      Dalvik最多支持65536个寄存器(编号从0~65535),但是ARM架构的cpu中只有37个寄存器, 每个Dalvik虚拟机维护了一个调用栈,该调用栈用来支持虚拟寄存器和真实寄存器相互映射,从而支持65536个寄存器的调用.

                      函数中必须使用.registers.locals声明寄存器数量,其中.registers表示参数寄存器和局部变量寄存器数量之和,.locals表示局部寄存器的数量.

                      申请的寄存器用于参数和局部变量的存储,一般p命名的寄存器用于参数,v命名的寄存器用于局部变量, 如果仅使用v命名法则需要注意,参数的命名需要在局部变量的命名之后命名,如假设有2个局部变量,3个参数变量:

                      声明方式第1个局部变量第2个局部变量第1个参数第2个参数第3个参数
                      .registersv0v1p0p1p2
                      .localsv0v1v2v3v4

                      常用关键字

                      关键字作用示例
                      .line表示源码中的行号
                      :cond_N条件分支配合if使用
                      :goto_Ngoto跳转分支,配合goto关键字使用
                      .prologue表示程序的开始
                      .local局部变量设置别名.local v0, "b":Ljava/lang/String;
                      .param参数变量设置别名.local p0, "b":Ljava/lang/String;

                      参考

                      1. 胖薯code的Smali语言入门到精通:https://www.bilibili.com/video/BV1Vf4y1q7gh 🔗
                      2. 正己:https://www.52pojie.cn/thread-1701353-1-1.html 🔗
                      3. CTF wiki: https://ctf-wiki.org/android/basic_operating_mechanism/java_layer/smali/smali/#smali 🔗
                      FINISH

                      Random Articles
                      Life Countdown
                      default