smali 檔案格式

wcode發表於2019-02-01

本篇文章同時收錄在我的個人部落格:smali 檔案格式

HelloWorld

首先寫一個 HelloWorld 類:

package jiuyou.hello.info;

public class HelloWorld {
    public static void main(String[] args){
        System.out.println("hello world");
    }
}複製程式碼

然後生成 apk 再用 apktool 工具轉成 smali 檔案:

.class public Ljiuyou/hello/info/HelloWorld;    #定義類名
.super Ljava/lang/Object;                       #定義父類
.source "HelloWorld.java"                       #原始檔名


# direct methods      #直接方法  (# virtual methods 為虛方法)
.method public constructor <init>()V      #建構函式
    .locals 0     #方法中使用到的區域性變數個數

    .prologue     #程式碼起始指令
    .line 8       #原始碼所在行數
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V         #呼叫父類構造方法

    return-void     #返回空
.end method         #方法結束

.method public static main([Ljava/lang/String;)V      #對應 main 方法
    .locals 2       #方法包含兩個區域性 v0,v1
    .param p0, "args"    # [Ljava/lang/String;   # main 方法的引數 agrs 標記為 p0

    .prologue       #程式碼起始指令
    .line 10
    sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;  #將 System.out 這個靜態變數賦給 v0

    const-string v1, "hello world"    #構造字串

    #方法呼叫(呼叫 v0 的方法 println ,v1 是引數)
    invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V    

    .line 11
    return-void
.end method複製程式碼

欄位

靜態欄位格式如下:

# static fields
.field <訪問許可權> static [修飾關鍵字] <欄位名>:<欄位型別>複製程式碼

例項欄位格式如下:

# instance fields
.field <訪問許可權> [修飾關鍵字] <欄位名>:<欄位型別>複製程式碼

舉個例子

java :

private String name;

private final String sex="男";

public static int age;複製程式碼

smali :

# static fields
.field public static age:I

# instance fields
.field private name:Ljava/lang/String;

.field private final sex:Ljava/lang/String;複製程式碼

方法

方法有直接方法和虛方法兩種,兩者格式基本相同:

# direct methods  (virtual methods)
.method <訪問許可權> [修飾關鍵字] <方法原型>
    <.locals>
    [.parameter] or [.param]
    [.prologue]
    [.line]
    <程式碼體>
.end method複製程式碼

.locals:區域性變數個數
.parameter or .param:指定每個引數
.prologue:程式碼的開始處,混淆過的程式碼可能沒有該指令
.line:指定了該處指令在原始碼中的行號,混淆過的程式碼可能沒有該指令

舉個例子:
java

public String test(int a){
    int b=a+10;
    return "test";
}複製程式碼

smali

# virtual methods
.method public test(I)Ljava/lang/String;
    .locals 2
    .param p1, "a"    # I

    .prologue
    .line 11
    add-int/lit8 v0, p1, 0xa

    .line 12
    .local v0, "b":I
    const-string v1, "test"

    return-object v1
.end method複製程式碼

介面

interface 格式如下:

# interfaces
.implements <介面名>複製程式碼

舉個例子:
java

public interface If {
    int demo(String s);
}

public class InterfaceTest implements If {
    @Override
    public int demo(String s) {
        return 0;
    }
}複製程式碼

smali :
If.smali

# virtual methods
.method public abstract demo(Ljava/lang/String;)I
.end method複製程式碼

InterfaceTest.smali

# interfaces
.implements Ljiuyou/hello/info/If;

# virtual methods
.method public demo(Ljava/lang/String;)I
    .locals 1
    .param p1, "s"    # Ljava/lang/String;

    .prologue
    .line 11
    const/4 v0, 0x0

    return v0
.end method複製程式碼

註解

格式如下:

.annotation [註解屬性] <註解類名>
    [註解欄位 = 值]
.end annotation複製程式碼

如果註解的作用範圍是類, .annotation 指令會直接定義在 smali 檔案中,如果作用範圍是方法或者欄位,則會包含在方法或欄位定義中。
舉個例子:
java

@Deprecated
public class AnnotationTest {
    @At(value = "tom")
    public String name;
}複製程式碼

smali

# annotations
.annotation runtime Ljava/lang/Deprecated;
.end annotation


# instance fields
.field public name:Ljava/lang/String;
    .annotation runtime Ljiuyou/hello/info/At;
        value = "tom"
    .end annotation
.end field複製程式碼