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代码
- 重新打包签名