一、开头(类的声明)
1、声明一个类继承自某个类
java代码如下
public class MainActivity extends AppCompatActivity
对应的smali代码如下,解析见每行注释(smali注释使用#):
.class public Lcom/ylw/yhds/activity/MainActivity;#声明类,其中Lcom/ylw/yhds/activity/MainActivity;为类的全包名,L开头,分号结尾
.super Landroidx/appcompat/app/AppCompatActivity;#上一行类的父类,同样要用全包名
.source "MainActivity.java"#该smali文件源自MainActivity.java文件,此行可以不写
2、声明一个类继承某个接口
java代码如下
public class DataPackage implements Serializable
对应的smali代码如下,解析见每行注释(smali注释使用#),当没有继承具体的类时,使用Object类:
.class public Lcom/ylw/yhds/utils/DataPackage;#声明类,其中Lcom/ylw/yhds/utils/DataPackage;为类的全包名,L开头,分号结尾 .super Ljava/lang/Object;#上一行类的父类,同样要用全包名,当没有继承具体的类时,使用Object类 .source "DataPackage.java"#该smali文件源自DataPackage.java文件,此行可以不写 # interfaces#自动生成的注释 .implements Ljava/io/Serializable;#实现了Serializable接口,同样Ljava/io/Serializable;为全包名
二、方法的定义和调用
1、构造方法
- 不论java代码中是否显式写成了构造方法,下面的构造方法代码都会生成
- 私有方法和构造方法使用invoke-direct进行调用
- 静态方法使用invoke-static进行调用
- 平常自己写的一般方法使用invoke-virtual进行调用
# direct methods#自动生成的注释,表示以下内容为构造方法 .method public constructor <init>()V#constructor <init>表示构造方法,V表示返回值为void .registers 1#.registers表示寄存器个数,可暂时理解为方法中变量的个数 .prologue .line 6#从下一行开始到return-void结束,对应原java代码的第12行,方便对比阅读,此行可不写 invoke-direct {p0}, Ljava/lang/Object;-><init>()V#方法的调用,私有方法和构造方法使用invoke-direct进行调用 #本行和以下注释不存在,为补充解释添加。{p0}对应java中向函数传递参数,这里smali的花括号类似于java中的小括号 #p0对应constructor <init>()中小括号里的内容,可以理解为java中的this #Ljava/lang/Object;-><init>()V表示要调用方法的所属类全包名路径和调用方法,即将参数p0传入到哪个类中的哪个方法 #私有方法和构造方法调用格式整理如下 #invoke-direct {参数}, 方法所属类的全包名路径->方法名称(方法参数签名)方法返回值签名 return-void#对应constructor <init>()V中的V,即构造器的返回值为void .end method#与开头.method成对出现,可以理解为java中方法的花括号
2、非构造方法(平时自己写的一些方法)
2.1、无参返回值为String
java代码如下
private static String getName(){ return "hello"; }
对应的smali代码如下,注意方法名与构造方法不同,无需constructor
.method private static getName()Ljava/lang/String;#由于java中String是一个对象,所以这里的返回值是String的全包名路径,而不是像void一样用V表示 .registers 1#.registers表示寄存器个数,可暂时理解为方法中变量的个数 .line 22#对应原java代码的第22行,方便对比阅读,此行可不写 const-string v0,"hello"#声明一个常量字符串,将hello赋值给容器v0 return-object v0#返回v0容器中的内容,这里return-object与方法开头返回值为对象Ljava/lang/String;相对应 .end method
2.2、参数为String数组,返回值为空,方法内容为for循环
java代码如下:
public static void main(String[] args) { for (int i = 8; i < 3 ; i++) { } }
smali代码如下:(重复内容注释见2.1),smali中以16进制表示数字 .method public static main([Ljava/lang/String;)V .registers 3 .param p0, "args" # [Ljava/lang/String; .prologue .line 5#从此处.line到下一个.line即.line 8,中间的smali代码对应的是java的一行代码,即第5行for循环 const/16 v0, 0x8#声明常量8,放到容器v0中 .local v0, "i":I#表示v0这个容器中存放的值,在对应的java代码中对应的是变量i,可以不写 :goto_2 const/4 v1, 0x3#声明常量3,放到容器v1中 if-ge v0, v1, :cond_8#if-ge表示如果大于等于,即如果v0>=v1,则跳转到:cond_8,执行return-void #此行非自动生成,为补充解释添加。上面的if-ge不成立则顺序执行这些代码。 add-int/lit8 v0, v0, 0x1#加法运算,v0=v0+0x1 goto :goto_2#跳转到:goto_2 .line 8 :cond_8#跳转标识:cond_8 return-void .end method
三、其他示例
smali代码
new-instance v14, Ljava/lang/StringBuilder;#提前声明,我将要创建一个StringBuilder对象,用v14容器来装 invoke-direct {v14}, Ljava/lang/StringBuilder;-><init>()V#调用StringBuilder的构造方法创建StringBuilder对象,放到v14中