Smali语法(一)
本文主要介绍下Smali语法相关.
一: 简介
Smali是一种用于Android应用逆向工程和动态代码修改的小型低级字节码语言,它是Dalvik虚拟机(Virtual Machine)指令集的一种文本表示形式。它并非Java源代码的直接映射,而是更接近于VM实际运行的机器码。SMALI由四部分组成:
- 类(Class): 定义了类的数据结构,包括字段、方法等。
- 字段(Field): 表示类变量或实例变量。
- 调用(Call): 描述方法的调用,包括方法名、参数列表和返回值类型。
- 条件和循环(Conditions and Loops): 控制流指令,如if-else、while等。
二: Smali文件格式.
注: 本篇文章用到代码均是来自.v2rayNG.apk
2.1: 头信息
smali文件的头三行描述了当前类的一些信息,格式如下:
- .class <访问权限> <修饰关键字> <类名>
指令指定了当前类的类名.
- .super <父类名>
指令指定了当前类的父类
- .source <源文件名>
指令指定了当前类的源文件.
我们以MainActivity.smali为例:
.class public final Lcom/v2ray/ang/ui/MainActivity;
.super Lcom/v2ray/ang/ui/BaseActivity;
.source "MainActivity.kt"
MessageUtil.smali如下:
.class public final Lcom/v2ray/ang/util/MessageUtil;
.super Ljava/lang/Object;
.source "MessageUtil.kt"
2.2: 接口信息
MainActivity.smali 头信息紧跟着如下:
# interfaces
.implements Lcom/google/android/material/navigation/NavigationView$OnNavigationItemSelectedListener;
.implements这一行通常出现在类声明.class中,它的作用是声明该类实现了哪些接口(Interface).
也就是代表了MainActivity实现了NavigationView$OnNavigationItemSelectedListener接口.
2.3: 注解
如果一个类使用了注解,那smali代码中会使用".annotation"指令指出.
具体的格式如下:
#annotations
.annotation <注解属性> <注解类名>
…
.end annotation
2.4: 定义字段
smali中使用.field 来定义字段.
如MainActivity.smali 中定义了修饰符 private 私有 final 不可变的 类型 Lkotlin/Lazy. 用于延时加载的适配器类型字段: adapter$delegate.
# instance fields
.field private final adapter$delegate:Lkotlin/Lazy;
2.5: 定义方法
定义方法则是: 以 .method开始, .end method 结束;
.method public constructor <init>()V
.registers 8
.line 46
invoke-direct {p0}, Lcom/v2ray/ang/ui/BaseActivity;-><init>()V
.line 49
new-instance v0, Lcom/v2ray/ang/ui/MainActivity$adapter$2;
invoke-direct {v0, p0}, Lcom/v2ray/ang/ui/MainActivity$adapter$2;-><init>(Lcom/v2ray/ang/ui/MainActivity;)V
check-cast v0, Lkotlin/jvm/functions/Function0;
invoke-static {v0}, Lkotlin/LazyKt;->lazy(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
move-result-object v0
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->adapter$delegate:Lkotlin/Lazy;
.line 50
sget-object v0, Lcom/v2ray/ang/ui/MainActivity$mainStorage$2;->INSTANCE:Lcom/v2ray/ang/ui/MainActivity$mainStorage$2;
check-cast v0, Lkotlin/jvm/functions/Function0;
invoke-static {v0}, Lkotlin/LazyKt;->lazy(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
move-result-object v0
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->mainStorage$delegate:Lkotlin/Lazy;
.line 51
sget-object v0, Lcom/v2ray/ang/ui/MainActivity$settingsStorage$2;->INSTANCE:Lcom/v2ray/ang/ui/MainActivity$settingsStorage$2;
check-cast v0, Lkotlin/jvm/functions/Function0;
invoke-static {v0}, Lkotlin/LazyKt;->lazy(Lkotlin/jvm/functions/Function0;)Lkotlin/Lazy;
move-result-object v0
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->settingsStorage$delegate:Lkotlin/Lazy;
.line 52
new-instance v0, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;
invoke-direct {v0}, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;-><init>()V
check-cast v0, Landroidx/activity/result/contract/ActivityResultContract;
new-instance v1, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda12;
invoke-direct {v1, p0}, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda12;-><init>(Lcom/v2ray/ang/ui/MainActivity;)V
invoke-virtual {p0, v0, v1}, Lcom/v2ray/ang/ui/MainActivity;->registerForActivityResult(Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher;
move-result-object v0
const-string v1, "registerForActivityResul\u2026rtV2Ray()\n }\n }"
invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->requestVpnPermission:Landroidx/activity/result/ActivityResultLauncher;
.line 58
move-object v0, p0
check-cast v0, Landroidx/activity/ComponentActivity;
.line 664
new-instance v1, Lcom/v2ray/ang/ui/MainActivity$special$$inlined$viewModels$default$1;
invoke-direct {v1, v0}, Lcom/v2ray/ang/ui/MainActivity$special$$inlined$viewModels$default$1;-><init>(Landroidx/activity/ComponentActivity;)V
check-cast v1, Lkotlin/jvm/functions/Function0;
.line 668
new-instance v2, Landroidx/lifecycle/ViewModelLazy;
const-class v3, Lcom/v2ray/ang/viewmodel/MainViewModel;
invoke-static {v3}, Lkotlin/jvm/internal/Reflection;->getOrCreateKotlinClass(Ljava/lang/Class;)Lkotlin/reflect/KClass;
move-result-object v3
.line 670
new-instance v4, Lcom/v2ray/ang/ui/MainActivity$special$$inlined$viewModels$default$2;
invoke-direct {v4, v0}, Lcom/v2ray/ang/ui/MainActivity$special$$inlined$viewModels$default$2;-><init>(Landroidx/activity/ComponentActivity;)V
check-cast v4, Lkotlin/jvm/functions/Function0;
.line 672
new-instance v5, Lcom/v2ray/ang/ui/MainActivity$special$$inlined$viewModels$default$3;
const/4 v6, 0x0
invoke-direct {v5, v6, v0}, Lcom/v2ray/ang/ui/MainActivity$special$$inlined$viewModels$default$3;-><init>(Lkotlin/jvm/functions/Function0;Landroidx/activity/ComponentActivity;)V
check-cast v5, Lkotlin/jvm/functions/Function0;
.line 668
invoke-direct {v2, v3, v4, v1, v5}, Landroidx/lifecycle/ViewModelLazy;-><init>(Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
check-cast v2, Lkotlin/Lazy;
.line 58
iput-object v2, p0, Lcom/v2ray/ang/ui/MainActivity;->mainViewModel$delegate:Lkotlin/Lazy;
.line 356
new-instance v0, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;
invoke-direct {v0}, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;-><init>()V
check-cast v0, Landroidx/activity/result/contract/ActivityResultContract;
new-instance v1, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda10;
invoke-direct {v1, p0}, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda10;-><init>(Lcom/v2ray/ang/ui/MainActivity;)V
invoke-virtual {p0, v0, v1}, Lcom/v2ray/ang/ui/MainActivity;->registerForActivityResult(Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher;
move-result-object v0
const-string v1, "registerForActivityResul\u2026RESULT\"))\n }\n }"
invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->scanQRCodeForConfig:Landroidx/activity/result/ActivityResultLauncher;
.line 362
new-instance v0, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;
invoke-direct {v0}, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;-><init>()V
check-cast v0, Landroidx/activity/result/contract/ActivityResultContract;
new-instance v2, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda9;
invoke-direct {v2, p0}, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda9;-><init>(Lcom/v2ray/ang/ui/MainActivity;)V
invoke-virtual {p0, v0, v2}, Lcom/v2ray/ang/ui/MainActivity;->registerForActivityResult(Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher;
move-result-object v0
invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->scanQRCodeForUrlToCustomConfig:Landroidx/activity/result/ActivityResultLauncher;
.line 533
new-instance v0, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;
invoke-direct {v0}, Landroidx/activity/result/contract/ActivityResultContracts$StartActivityForResult;-><init>()V
check-cast v0, Landroidx/activity/result/contract/ActivityResultContract;
new-instance v1, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda11;
invoke-direct {v1, p0}, Lcom/v2ray/ang/ui/MainActivity$$ExternalSyntheticLambda11;-><init>(Lcom/v2ray/ang/ui/MainActivity;)V
invoke-virtual {p0, v0, v1}, Lcom/v2ray/ang/ui/MainActivity;->registerForActivityResult(Landroidx/activity/result/contract/ActivityResultContract;Landroidx/activity/result/ActivityResultCallback;)Landroidx/activity/result/ActivityResultLauncher;
move-result-object v0
const-string v1, "registerForActivityResul\u2026mUri(uri)\n }\n }"
invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->checkNotNullExpressionValue(Ljava/lang/Object;Ljava/lang/String;)V
iput-object v0, p0, Lcom/v2ray/ang/ui/MainActivity;->chooseFileForCustomConfig:Landroidx/activity/result/ActivityResultLauncher;
return-void
.end method
如上所示: .method public constructor ()V
则代表了无参构造.
注意这里.registers则是指定方法内使用寄存器的总数.