smali语法
本文由 Luzhuo 编写,转发请保留该信息.
原文: https://blog.csdn.net/Rozol/article/details/88368358
smali是什么, 官方的简介
smali/baksmali is an assembler/disassembler for the dex format used by dalvik, Android’s Java VM implementation. The syntax is loosely based on Jasmin’s/dedexer’s syntax, and supports the full functionality of the dex format (annotations, debug info, line info, etc.)
smali / baksmali是Android的Java VM实现dalvik使用的dex格式的汇编程序/反汇编程序。语法松散地基于Jasmin的/ dedexer的语法,并支持dex格式的全部功能(注释,调试信息,行信息等)
Java代码
public int show(String str){
return 1;
}
smali代码
# virtual methods
.method public show(Ljava/lang/String;)I
.locals 1
.param p1, "str" # Ljava/lang/String;
.line 22
const/4 v0, 0x1
return v0
.end method
数据类型 / 对象 / 数组 的写法, 对于经常JNI开发的童鞋肯定非常熟悉, 没错, 跟javap
生成签名类型是一样的.
数据类型
smali类型 | java类型 | Description |
---|---|---|
V | void (用于返回类型) | - |
Z | boolean | 不同 |
B | byte | - |
S | short | - |
C | char | - |
I | int | - |
J | long (64 bits) | 不同 |
F | float | - |
D | double (64 bits) | - |
运算
smali
mul-int v0, p1, p2
add-int / add-long / add-float / add-double / add-int/lit16 / add-int/lit8
smali运算符 | Description | int | long | float | double |
---|---|---|---|---|---|
add-int v0, p1, p2 | v0 = p1 + p2 | √ | √ | √ | √ |
sub-int v0, p1, p2 | v0 = p1 - p2 | √ | √ | √ | √ |
mul-int v0, p1, p2 | v0 = p1 * p2 | √ | √ | √ | √ |
div-int v0, p1, p2 | v0 = p1 / p2 | √ | √ | √ | √ |
rem-int v0, p1, p2 | v0 = p1 % p2 | √ | √ | √ | √ |
and-int v0, p1, p2 | v0 = p1 & p2 | √ | √ | × | × |
or-int v0, p1, p2 | v0 = p1 │ p2 | √ | √ | × | × |
xor-int v0, p1, p2 | v0 = p1 ^ p2 | √ | √ | × | × |
shl-int v0, p1, p2 | v0 = p1 << p2 | √ | √ | × | × |
shr-int v0, p1, p2 | v0 = p1 >> p2 | √ | √ | × | × |
ushr-int v0, p1, p2 | v0 = p1 >>> p2 | √ | √ | × | × |
add-int/2addr v0, v1 | v0 = v0 + v1 | √ | √ | √ | √ |
sub-int/2addr v0, v1 | v0 = v0 - v1 | √ | √ | √ | √ |
mul-int/2addr v0, v1 | v0 = v0 * v1 | √ | √ | √ | √ |
div-int/2addr v0, v1 | v0 = v0 / v1 | √ | √ | √ | √ |
rem-int/2addr v0, v1 | v0 = v0 % v1 | √ | √ | √ | √ |
and-int/2addr v0, v1 | v0 = v0 & v1 | √ | √ | × | × |
or-int/2addr v0, v1 | v0 = v0 │ v1 | √ | √ | × | × |
xor-int/2addr v0, v1 | v0 = v0 ^ v1 | √ | √ | × | × |
shl-int/2addr v0, v1 | v0 = v0 << v1 | √ | √ | × | × |
shr-int/2addr v0, v1 | v0 = v0 >> v1 | √ | √ | × | × |
ushr-int/2addr v0, v1 | v0 = v0 >>> v1 | √ | √ | × | × |
add-int/lit16 v0, v1, lit16 | v0 = v1 + lit16 | √ | × | × | × |
sub-int/lit16 v0, v1, lit16 | v0 = v1 - lit16 | √ | × | × | × |
mul-int/lit16 v0, v1, lit16 | v0 = v1 * lit16 | √ | × | × | × |
div-int/lit16 v0, v1, lit16 | v0 = v1 / lit16 | √ | × | × | × |
rem-int/lit16 v0, v1, lit16 | v0 = v1 % lit16 | √ | × | × | × |
and-int/lit16 v0, v1, lit16 | v0 = v1 & lit16 | √ | × | × | × |
or-int/lit16 v0, v1, lit16 | v0 = v1 │ lit16 | √ | × | × | × |
xor-int/lit16 v0, v1, lit16 | v0 = v1 ^ lit16 | √ | × | × | × |
add-int/lit8 v0, v1, lit8 | v0 = v1 + lit8 | √ | × | × | × |
sub-int/lit8 v0, v1, lit8 | v0 = v1 - lit8 | √ | × | × | × |
mul-int/lit8 v0, v1, lit8 | v0 = v1 * lit8 | √ | × | × | × |
div-int/lit8 v0, v1, lit8 | v0 = v1 / lit8 | √ | × | × | × |
rem-int/lit8 v0, v1, lit8 | v0 = v1 % lit8 | √ | × | × | × |
and-int/lit8 v0, v1, lit8 | v0 = v1 & lit8 | √ | × | × | × |
or-int/lit8 v0, v1, lit8 | v0 = v1 │ lit8 | √ | × | × | × |
xor-int/lit8 v0, v1, lit8 | v0 = v1 ^ lit8 | √ | × | × | × |
shl-int/lit8 v0, v1, lit8 | v0 = v1 << lit8 | √ | × | × | × |
shr-int/lit8 v0, v1, lit8 | v0 = v1 >> lit8 | √ | × | × | × |
ushr-int/lit8 v0, v1, lit8 | v0 = v1 >>> lit8 | √ | × | × | × |
类名
smali类名 | java类名 |
---|---|
Ljava/lang/String; | java.lang.String |
Ljava/lang/Object; | java.lang.Object |
L全/类/名; | 全.类.名 |
smali类名写法要注意, 最前面L开头, 最后;结尾
数组
smali数组 | Java数组 |
---|---|
[I | int[] |
[[I | int[][] |
[Ljava/lang/String; | String[] |
… | … |
smali数组在类型左侧加[号, 几维就加几个, 最多255维.
类的定义
Java代码
public class BaseData {
public int add(int x, int y){
return x * y;
}
}
Smali代码
.class public Lme/luzhuo/smalidemo/BaseData; // 本类
.super Ljava/lang/Object; // 父类
.source "BaseData.java" // 文件名
# direct methods
// 构造方法, 方法名为<init>
.method public constructor <init>()V
.locals 0
.line 20
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
// 普通方法 / add:方法名 / II:返回类型 / I:返回类型
.method public add(II)I
.locals 1
.param p1, "x" # I // 参数
.param p2, "y" # I
.line 26 // 该函数在原.source中的位置(含注释)
mul-int v0, p1, p2
return v0
.end method
类的定义: 本类 / 父类 / 文件名
.class public Lme/luzhuo/smalidemo/BaseData; // 本类
.super Ljava/lang/Object; // 父类
.source "BaseData.java" // 文件名
属性的定义: 属性名 / 属性类型
# static fields
// 属性: .field 修饰符 属性名:属性类型
.field private static final TAG:Ljava/lang/String; = "PropActivity"
方法的定义: 方法名 / 参数类型 / 参数名 / 返回类型 / 返回值
// 方法: .method 修饰符 方法名(参数类型)返回类型
.method public add(II)I
.locals 1
.param p1, "x" # I // 参数名
.param p2, "y" # I
return v0 // 返回值
.end method
返回指令 | Description |
---|---|
return-void | 直接返回 |
return v0 | 返回v0 |
return-object v0 | 返回v0(对象) |
return-wide v0 | 给v0(双寄存器的值) |
特殊的方法:
// 构造方法
.method public constructor <init>()V
.end method
// 静态方法
.method public static final constructor <clinit>()V
.end method
调用方法:
const/4 v0, 0x3
const/4 v1, 0x5
// 调用方法: 类->方法
invoke-virtual {p0, v0, v1}, Lme/luzhuo/smalidemo/BaseData;->add(II)I
调用指令 | Description | 案例 |
---|---|---|
invoke-virtual | 调用一般方法 | invoke-virtual {p0, v0, v1}, Lme/luzhuo/smalidemo/BaseData;->add(II)I |
invoke-super | 调用父类方法 | invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V // super.onCreate(savedInstanceState); |
invoke-direct | 调用private/构造方法 | invoke-direct {p0}, Ljava/lang/Object;-><init>()V |
invoke-static | 调用静态方法 | invoke-static {}, Lme/luzhuo/smalidemo/BaseData;->aaa()V |
invoke-interface | 调用interface方法 | invoke-interface {v0}, Lme/luzhuo/smalidemo/Inter;->mul()V |
寄存器
方法内部先声明寄存器数量, 然后再写代码
.method public add(II)I
.locals 1
.param p1, "x" # I
.param p2, "y" # I
// 先完成上面部分的声明, 然后在这些代码
.line 26
mul-int v0, p1, p2
return v0
.end method
寄存器的声明方式
.locals 0 // 声明不算参数, 需要加几个寄存器
.registers 0 // 声明算上参数, 一共需要几个寄存器
寄存器命名规则
v0 v1 v2 v... // .locals 寄存器的命名
p0 p1 p2 p... // .registers 寄存器的命名
.registers不用声明, .locals要声明
有参数, 用p表示第几个参数所占的寄存器, 从1开始
给寄存器赋值:
const/4 v0, 0x3
const-string v0, "\u4f60\u88ab\u6211\u53cd\u7f16\u8bd1\u5566\u002c\u0020\u54c8\u54c8\u54c8\u54c8"
常量指令 | Description | 案例 |
---|---|---|
const(/4, /16, ,/high16) vx, num | 把nun赋给vx寄存器, num为(4bit, 16bit, 32bit(int), 16bit(float)) | const v0, 0x3 |
const-wide(/16, ,/high16) vx, num | 把num赋给vx和vx+, num为(?, 64bit(long), 64bit(double)) | const-wide v0, 0x123456L |
const-string( , -jumbo) vx, string | "Unicode"字符串赋给vx (一般, 过长) | const-string v0, "\u4f60\u88ab..." |
const-class vx, class | 将Class赋值给vx | const-class v0, LJava/lang/String; |
- boolean
- 用
const/4
赋值, 1true, 0false
- 用
- float/double
- 用
0x
16进制表示小数 - long和double的16进制数后加L
- 用
// smali 给寄存器赋值, 并起名(带名称的常量)
const/16 v0, 0xa
.local v0, "a":I
// java
int a = 0xa;
// ---
// smali 给寄存器赋值对象
const/4 v2, 0x0
new-array v2, v2, [Ljava/lang/String;
// java
new String[]
值的判断指令
// smali
const/16 v0, 0xa
const/16 v1, 0x14
if-le v0, v1, :cond_0
const/16 v0, 0x1e
goto :goto_0
:cond_0
const/16 v1, 0x1e
:goto_0
// java
if (v0 <= v1) {
cond_0
}else{
const/16 v0, 0x1e
goto_0
}
// 翻译成人话: 等式不成立则往下执行
// java中写 a > b, 到这里就相反, 变成 a <= b 了.
指令 | Description |
---|---|
if-eq v0, v1, :cond_0 | if (v0 == v1) cond_0 |
if-ne v0, v1, :cond_0 | if (v0 != v1) cond_0 |
if-gt v0, v1, :cond_0 | if (v0 > v1) cond_0 |
if-ge v0, v1, :cond_0 | if (v0 >= v1) cond_0 |
if-lt v0, v1, :cond_0 | if (v0 < v1) cond_0 |
if-le v0, v1, :cond_0 | if (v0 <= v1) cond_0 |
if-eqz v0, :cond_0 | if (v0 == 0) cond_0 |
if-nez v0, :cond_0 | if (v0 != 0) cond_0 |
if-gtz v0, :cond_0 | if (v0 > 0) cond_0 |
if-gez v0, :cond_0 | if (v0 >= 0) cond_0 |
if-ltz v0, :cond_0 | if (v0 < 0) cond_0 |
if-lez v0, :cond_0 | if (v0 <= 0) cond_0 |
移位指令
smali
.method public show()I
const/16 v0, 0xa
const/16 v1, 0x14
const/4 v2, 0x0
new-array v2, v2, [Ljava/lang/String;
invoke-virtual {p0, v0, v1, v2}, Lme/luzhuo/smalidemo/BaseData;->add(II[Ljava/lang/String;)I
move-result v2
return v2
.end method
移位指令 | Description |
---|---|
move( , /from16, /16) v0, v1 | 将v1值移入到v0(4bit(int), 16bit->8bit, 16bit) |
move-wide( , /from16, /16) v0, v1 | 将v1值移入到v0(4bit, 16bit->8bit, 16bit) |
move-object( , /from16, /16) v0, v1 | 将v1对象指针移入到v0(4bit, 16bit->8bit, 16bit) |
move-result( , -object, -wide) v0 | 将上条指令计算结果, 移入到v0(值, 对象指针, 双寄存器值) |
move-exception v0 | 将异常移入到v0 |
实例字段指令
smali
.method public static final aaa()V
.locals 2
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const-string v1, "sfsdf"
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
return-void
.end method
iget / aget / sget: 数字 / 数组 / 静态
实例字段指令 | Description |
---|---|
iget | 取值(int) |
iget-wide | 取值(双寄存器值) |
iget-object | 取值(对象指针) |
iget-boolean | 取值(bool) |
iget-byte | 取值(字节) |
iget-char | 取值(字符) |
iget-short | 取值(short) |
iput | 赋值(int) |
iput-wide | 赋值(双寄存器值) |
iput-object | 赋值(对象指针) |
iput-boolean | 赋值(bool) |
iput-byte | 赋值(字节) |
iput-char | 赋值(字符) |
iput-short | 赋值(short) |
其他
注解
smali
.method protected onCreate(Landroid/os/Bundle;)V
.locals 0
.param p1 # Landroid/os/Bundle;
.annotation build Landroid/support/annotation/Nullable;
.end annotation
.end param
//...
return-void
.end method
java
protected void onCreate(Bundle @Nullable savedInstanceState) {
}
创建数组
smali
const/4 v2, 0x0
new-array v2, v2, [Ljava/lang/String;