1. 程式人生 > >android Smali靜態分析(一)

android Smali靜態分析(一)

檔案頭
.class <訪問許可權> [修飾關鍵字] <類名>
.super <父類名>
.source <原始檔名>

示例

.class public Lcom/yiji/test/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"
欄位
# static fields
.field <訪問許可權> static [修飾關鍵字] <欄位名>:<欄位型別>

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

示例

# static fields
.field public static final ARGS_KEY:Ljava/lang/String;

# instance fields
.field private btnOk:Landroid/widget/Button;
方法
# direct methods
.method <訪問許可權> [修飾關鍵字] <方法原型>
    <.locals>
    [.parameter]
    [.prologue]
    [.line
] <程式碼體> .end method # virtual methods .method <訪問許可權> [修飾關鍵字] <方法原型> <.locals> [.parameter] [.prologue] [.line] <程式碼體> .end method

.locals 區域性變數個數
.parameter 引數個數,每條指令宣告一個引數
.prologue 程式碼開始
.line 行號

介面
# interfaces
.implements <介面名>
註解
# annotations
.annotation [註解屬性] <註解類名>
    [註解欄位=值]
.end annotation

示例

# instance fields
.field public sayWhat:Ljava/lang/String;
    .annotation runtime Lcom/droider/anno/MyAnnoField;
        info = "Hello my friend"
    .end annotation
.end field

對應java程式碼

@com.droider.anno.MyAnnoField(info = "Hello my friend")
public String sayWhat;

內部類

內部類有自己獨立的smali檔案,命名方式為“[外部類]$[內部類].smali”
示例

.class public Lcom/yiji/test/MainActivity$SNChecker;
.super Ljava/lang/Object;
.source "MainActivity.java"

# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Lcom/yiji/test/MainActivity;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x1
    name = "SNChecker"
.end annotation

# instance fields
.field private sn:Ljava/lang/String;
.field final synthetic this$0:Lcom/yiji/test/MainActivity;

# direct method
.method public constructor <init>(Lcom/yiji/test/MainActivity;Ljava/lang/String;)V
...
.end method

# virtual methods
.method public isRegistered()Z
...
.end method

其中包含欄位this0init()this0是指向外部類的引用,0表示層數,如下

public class Outer {               //this$0
    public class FirstInner {      // this$1
        public class SecondInner { // this$2
            public class ThreadInner {
            }
        }
    }
}

synthetic屬性表明是編譯器合成

# direct methods
.method public constructor <init>(Lcom/yiji/test/MainActivity;Ljava/lang/String;)V
    .locals 0
    .parameter # 第一個引數MainActivity引用
    .parameter # 第二個引數sn

    .progolue
    iput-object p1, p0, Lcom/yiji/test/MainActivity$SNChecker;->this$0:Lcom/yiji/test/MainActivity; # 將MainActivity引用賦值給this$0
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V # 呼叫預設建構函式
    iput-object p2, p0, Lcom/yiji/test/MainActivity$SNCheck;->sn:Ljava/lang/String; # 賦值sn
.end method

這段程式碼使用了兩條“.parameter”指令,卻用到了p0-p2共3個暫存器,因為對非靜態方法,會隱含p0暫存器指向this引用。

監聽器
btn.setOnClickListener(new android.view.View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ...
    }
});
.method public onCreate(Landroid/os/Bundle;)V
    .locals 2
    .parameter "savedInstanceState"

    ...
    iget-object v0, p0, Lcom/yiji/test/MainActivity;->btn:Landroid/widget/Button;
    new-instance v1, Lcom/yiji/test/MainActivity$1; # 新建MainActivity$1例項
    invoke-direct {v1, p0}, Lcom/yiji/test/MainActivity$1;-><init>(Lcom/yiji/test/Mainactivity;)V # 初始化MainActivity$1例項
    invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V # 設定按鈕點選事件

MainActivity$1.smali檔案

.class Lcom/yiji/test/MainActivity$1
.super Ljava/lang/Object;
.source "MainActivity.java"

# interfaces
.implements Landroid/view/View$OnClickListener;

# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
    value = Lcom/yiji/test/MainActivity;->onCreate(Landroid/os/Bundles;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
    accessFlag = 0x0
    name = null
.end annotation

# instance fields
.field final synthetic this$0:Lcom/yiji/test/MainActivity;

# direct methods
.method constructor <init>(Lcom/yiji/test/MainActivity;)V
    ...
.end method

# virtual methods
.method public onClick(Landroid/view/View;)V
    ...
.end method
註解類

MemberClasses註解
在MainActivity.smali中有如下程式碼:

# annotations
.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Lcom/yiji/test/MainActivity$SNChecker;
    }
.end annotations

MemberClasses是編譯時自動加上的,檢視MemberClasses註解類原始碼,如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface MemberClasses { }

可以看出MemberClasses是“系統註解”,記錄一個內部類列表。

EnclosingMethod註解
在MainActivity$1.smali中有一段程式碼如下:

# annotations
.annotation system Lcom/dalvik/annotation/EnclosingMethod;
    value = Lcom/yiji/test/MainActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation

EnclosingMethod註解用來說明MainActivity$1類的作用範圍,其中的Method說明它作用於一個方法,而value表明它位於MainActivity的onCreate()方法中。

EnclosingClass註解
在MainActivity$SNChecker.smali檔案中,有如下程式碼:

# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Lcom/yiji/test/MainActivity;
.end annotation

EnclosingClass表明MainActivity$SNChecker作用於一個類,value表明這個類是MainActivity。

InnerClass註解

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x1
    name = "SNChecker"
.end annotation

InnerClass表明是一個內部類,name表示內部類的名稱,accessFlags訪問標誌,宣告如下:

enum {
    kDexVisibilityBuild    = 0x00,  /* annotation visibility */
    kDexVisibilityRuntime  = 0x01,
    kDexVisibilitySystem   = 0x02,
};

AnnotationDefault註解
如果註解在宣告時提供了預設值,那麼會用到AnnotationDefault註解,示例:

# annotations
.annotation system Ldalvik/annotation/AnnotationDefault;
    value = .subannotation Lcom/yiji/test/anno/MyAnnoClass;
        value = "MyAnnoClass"
    .end subannotation
.end annotation

可以看出MyAnnoClass類有一個預設值”MyAnnoClass”。

Signature註解
用於驗證方法的簽名

.method pubilc onItemClick(Landroid/widget/AdapterView;Landroid/view/View;IJ)V
    .locals 6
    .parameter
    .parameter "v"
    .parameter "position"
    .parameter "id"
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "(",
            "Landroid/widget/AdapterView",
            "<*>;",
            "Landroid/view/View;",
            "IJ)V"
        }
    .end annotation
    ...
.end method

Throws註解
如果方法丟擲異常則生成相應的Throws註解

.method public final get()Ljava/lang/Object;
    .locals 1
    .annotation system Ldalvik/annotation/Throws;
        value = {
            Ljava/lang/InterruptedException;
            Ljava/util/concurrent/ExcutionException;
        }
    .end annotation
    ...
.end method

其他註解
- SuppressLint註解:去掉程式碼檢查器的警告資訊
- TargetApi註解:去掉程式碼版本檢查的錯誤資訊
- SdkConstant註解:被標記為@hide,指定sdk中可以被匯出的常量
- Widget註解:被標記為@hide,表明是UI類