smali语言是Davlik的寄存器语言,语法上和汇编语言相似,Dalvik VM与JVM的最大的区别之一就是Dalvik VM是基于寄存器的。基于寄存器的意思是,在smali里的所有操作都必须经过寄存器来进行。
参考网址
静态分析Android程序——smali文件解析
Smali基本语法(一)
Android smali语法
Android studio动态调试smali
数据类型
| smali类型 | java类型 |
|---|---|
| V | void (用于返回类型) |
| Z | boolean |
| B | byte |
| S | short |
| C | char |
| I | int |
| J | long (64 bits) |
| F | float |
| D | double (64 bits) |
类定义
Kotlin代码
class MainActivity : AppCompatActivity() {
...
}
Smali
.class public final Lapp/santaone/customer/voip/MainActivity;
.super Landroidx/appcompat/app/AppCompatActivity;
.source "MainActivity.kt"
...
总结:
- L 表示这是一个对象类型
- .class <访问权限> <关键修饰字> <类名;>
- .super <关键修饰字> <父类名;>
- .source <源文件名>
变量定义
Kotlin代码
private var incomingSip: String? = null
private var isOutgoing = false
Smali
# instance fields
.field private incomingSip:Ljava/lang/String;
.field private isOutgoing:Z
总结:
- 注释,注释由#开头,后面的instance fields, 意为实例的字段,即变量字段。
- .field表示,这是一个字段。 private,代表私有的,isOutgoing,是变量名。:Z,是变量的类型。
- [I :表示一个整形的一维数组。
方法定义
Kotlin代码
override fun onStart() {
super.onStart()
}
Smali
.method protected onStart()V
.locals 0
.line 248
invoke-super {p0}, Landroidx/appcompat/app/AppCompatActivity;->onStart()V
return-void
.end method
总结:
- .method表示,这是一个方法。protected,访问权限。onStart,方法名。V,返回类型。
寄存器
Kotlin代码
private fun print(string: String) {
Log.d(TAG, string)
}
Smali
.method private print(Ljava/lang/String;)V
.registers 3
.param p1, "string" # Ljava/lang/String;
.prologue
.line 29
const-string v0, "MainActivity"
invoke-static {v0, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 30
return-void
.end method
总结:
- android变量都是存放在寄存器中的,寄存器为32位,可以支持任何类型,其中long和double是64为的,需要使用两个寄存器保存。
- 寄存器采用v和p来命名,v表示本地寄存器,p表示参数寄存器。
- v0 v1 v2 v... // .locals 寄存器的命名。
- p0 p1 p2 p... // .registers 寄存器的命名。
- .registers 3 说明该方法有三个寄存器。其中一个本地寄存器v0,两个参数寄存器p0,p1。没有看到p0,原因是p0存放的是this。如果是静态方法的话就只有2个寄存器了,不需要存this。
运算
| smali | 描述 |
|---|---|
| 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 |
| ... | ... |
指令
| smali | 描述 |
|---|---|
| return-void | 直接返回 |
| return v0 | 返回v0 |
| return-object v0 | 返回v0(对象) |
| return-wide v0 | 给v0(双寄存器的值) |
| invoke-virtual | 调用一般方法 |
| invoke-super | 调用父类方法 |
| invoke-direct | 调用private/构造方法 |
| invoke-static | 调用静态方法 |
| invoke-interface | 调用interface方法 |
| const(/4, /16, ,/high16) vx, num | 把nun赋给vx寄存器, num为(4bit, 16bit, 32bit(int), 16bit(float)) |
| const-wide(/16, ,/high16) vx, num | 把num赋给vx和vx+, num为(?, 64bit(long), 64bit(double)) |
| const-string( , -jumbo) vx, string | "Unicode"字符串赋给vx (一般, 过长) |
| const-class vx, class | 将Class赋值给vx |
| if-eq v0, v1 | if (v0 == v1) |
| if-ne v0, v1 | f (v0 != v1) |
| if-gt v0, v1 | if (v0 > v1) |
| if-ge v0 | if (v0 >= v1) |
| if-lt v0 | if (v0 < v1) |
| if-le v0 | if (v0 <= v1) |
| if-eqz v0 | if (v0 == 0) |
| if-nez v0 | if (v0 != 0) |
| if-gtz v0 | if (v0 > 0) |
| if-gez v0 | if (v0 >= 0) |
| if-ltz v0 | if (v0 < 0) |
| if-lez v0 | if (v0 <= 0) |
| iget0 | 取值(int) |
| iget-wide0 | 取值(双寄存器值) |
| iget-object0 | 取值(对象指针) |
| iget-boolean0 | 取值(bool) |
| iget-byte0 | 取值(字节) |
| iget-char0 | 取值(字符) |
| iget-short0 | 取值(short) |
| iput0 | 赋值(int) |
| iput-wide0 | 赋值(双寄存器值) |
| iput-object 0 | 赋值(对象指针) |
| iput-boolean0 | 赋值(bool) |
| iput-byte0 | 赋值(字节) |
| iput-char0 | 赋值(字符) |
| iput-short0 | 赋值(short) |
smali插桩
smali插桩,插桩的原理就是静态的修改apk的samli文件,然后重新打包。
- 反编译得到smali
- 修改smali代码
- 重新打包签名