Android APK文件(四、Smali语法)

2,540 阅读4分钟

smali语言是Davlik的寄存器语言,语法上和汇编语言相似,Dalvik VM与JVM的最大的区别之一就是Dalvik VM是基于寄存器的。基于寄存器的意思是,在smali里的所有操作都必须经过寄存器来进行。

参考网址

静态分析Android程序——smali文件解析

blog.csdn.net/hp910315/ar…

Smali基本语法(一)

blog.csdn.net/l_o_s/artic…

Android smali语法

blog.csdn.net/Rozol/artic…

Android studio动态调试smali

www.cnblogs.com/goodhacker/…

数据类型

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文件,然后重新打包。

  1. 反编译得到smali
  2. 修改smali代码
  3. 重新打包签名

结尾

Android APK文件(一、编译打包过程)

Android APK文件(二、解压和反编译)

Android APK文件(三、AAPT2工具使用)

Android APK文件(四、Smali语法)