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
其中包含欄位this
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類