1. 程式人生 > >Smali語法詳解

Smali語法詳解

smali檔案格式

每個smali檔案都由若干條語句組成,所有的語句都遵循著一套語法規則。在smali 檔案的頭3 行描述了當前類的一些資訊,格式如下:

  1. .class < 訪問許可權> [ 修飾關鍵字] < 類名>  
  2. .super < 父類名>  
  3. .source <原始檔名>  
開啟MainActivity.smali 檔案,頭3 行程式碼如下:
  1. .classpublic Lcom/droider/crackme0502/MainActivity;     //指令指定了當前類的類名。
  2. .super Landroid/app/Activity;<span style=
    "white-space:pre">             </span>//指令指定了當前類的父類。
  3. .source "MainActivity.java"<span style="white-space:pre">               </span>//指令指定了當前類的原始檔名。
smali檔案中欄位的宣告使用“.field”指令。欄位有靜態欄位與例項欄位兩種。靜態欄位的宣告格式如下:
  1. static fields  
  2. .field < 訪問許可權> static [ 修飾關鍵字] < 欄位名>:< 欄位型別>  

例項欄位的宣告與靜態欄位類似,只是少了static關鍵字,它的格式如下:
  1. # instance fields  
  2. .field < 訪問許可權> [ 修飾關鍵字] < 欄位名>:< 欄位型別>  
  1. 比如以下的例項欄位宣告。  
  2. # instance fields   //baksmali 生成的註釋
  3. .field private btnAnno:Landroid/widget/Button;  //私有欄位
smali 檔案中方法的宣告使用“.method ”指令,方法有直接方法與虛方法兩種。
直接方法的宣告格式如下:
  1. # direct methods                
    //新增的註釋
  2. .method <訪問許可權> [ 修飾關鍵字] < 方法原型>  
  3.     <.locals>                 //指定了使用的區域性變數的個數
  4.  [.parameter]                   //指定了方法的引數
  5.  [.prologue]                    //指定了程式碼的開始處,混淆過的程式碼可能去掉了該指令
  6.  [.line]                    //指定了該處指令在原始碼中的行號
  7. <程式碼體>  
  8. .end method  

虛方法的宣告與直接方法相同,只是起始處的註釋為“virtual methods”,如果一個類實現了介面,會在smali 檔案中使用“.implements ”指令指出,相應的格式宣告如下:
  1. # interfaces  
  2. .implements < 介面名>        //介面關鍵字
  3. 如果一個類使用了註解,會在 smali 檔案中使用“.annotation ”指令指出,註解的格式宣告如下:  
  4. # annotations  
  5. .annotation [ 註解屬性] < 註解類名>  
  6.     [ 註解欄位 =  值]  
  7. .end annotation  

註解的作用範圍可以是類、方法或欄位。如果註解的作用範圍是類,“.annotation ”指令會直接定義在smali 檔案中,如果是方法或欄位,“.annotation ”指令則會包含在方法或欄位定義中。例如:
  1. # instance fields  
  2. .field public sayWhat:Ljava/lang/String;            //String 型別 它使用了 com.droider.anno.MyAnnoField 註解,註解欄位info 值為“Hello my friend”
  3.     .annotation runtime Lcom/droider/anno/MyAnnoField;  
  4.         info = "Hello my friend"
  5.     .end annotation  
  6. .end field  

Android 程式中的類
1、內部類

Java 語言允許在一個類的內部定義另一個類,這種在類中定義的類被稱為內部類(Inner Class)。內部類可分為成員內部類、靜態巢狀類、方法內部類、匿名內部類。在反編譯dex 檔案的時候,會為每個類單獨生成了一個 smali 檔案,內部類作為一個獨立的類,它也擁有自己獨立的smali 檔案,只是內部類的檔名形式為“[外部類]$[內部類].smali ”,例如:

  1. class Outer {  
  2.    class Inner{}  
  3. }  
反編譯上述程式碼後會生成兩個檔案:Outer.smali 與Outer$Inner.smali。開啟檔案,程式碼結構如下:
  1. .classpublic Lcom/droider/crackme0502/MainActivity$SNChecker;  
  2. .super Ljava/lang/Object;  
  3. .source "MainActivity.java"
  4. # annotations  
  5. .annotation system Ldalvik/annotation/EnclosingClass;  
  6.     value = Lcom/droider/crackme0502/MainActivity;  
  7. .end annotation  
  8. .annotation system Ldalvik/annotation/InnerClass;  
  9.     accessFlags = 0x1
  10.     name = "SNChecker"
  11. .end annotation  
  12. # instance fields  
  13. .field private sn:Ljava/lang/String;  
  14. .field final synthetic this$0:Lcom/droider/crackme0502/MainActivity;  
  15. # direct methods  
  16. .method public constructor  
  17. <init>(Lcom/droider/crackme0502/MainActivity;Ljava/lang/String;)V  
  18. ……  
  19. .end method  
  20. # virtual methods  
  21. .method public isRegistered()Z  
  22. ……  
  23. .end method  
發現它有兩個註解定義塊“Ldalvik/annotation/EnclosingClass;”與“Ldalvik/annotation/ InnerClass; ”、兩個例項欄位sn 與this$0 、一個直接方法 init()、一個虛方法isRegistered() 。this$0 是內部類自動保留的一個指向所在外部類的引用。左邊的 this 表示為父類的引用,右邊的數值0 表示引用的層數。

2、監聽器
Android程式開發中大量使用到了監聽器,如Button的點選事件響應OnClickListener、Button的長按事件響應OnLongClickListener、ListView列表項的點選事件響應 OnItemSelected-Listener等。

例項原始碼以及反編譯設定按鈕點選事件監聽器的程式碼如下:

  1. publicvoid onCreate(Bundle savedInstanceState) {  
  2.        super.onCreate(savedInstanceState);  
  3.        setContentView(R.layout.activity_main);  
  4.        btnAnno = (Button) findViewById(R.id.btn_annotation);  
  5.        btnCheckSN = (Button) findViewById(R.id.btn_checksn);  
  6.        edtSN = (EditText) findViewById(R.id.edt_sn);  
  7.        btnAnno.setOnClickListener(new OnClickListener() {  
  8.            @Override
  9.            publicvoid onClick(View v) {  
  10.                getAnnotations();                  
  11.            }  
  12.        });  
  13.        btnCheckSN.setOnClickListener(new OnClickListener() {  
  14.            @Override
  15.            publicvoid onClick(View v) {  
  16.                SNChecker checker = new SNChecker(edtSN.getText().toString());  
  17.                String str = checker.isRegistered() ? "註冊碼正確" : "註冊碼錯誤";  
  18.                Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();  
  19.            }  
  20.        });  
  21.    }  

  1. 反編譯如下:  
  2. .method public onCreate(Landroid/os/Bundle;)V  
  3.      .locals 2
  4.     .parameter "savedInstanceState"
  5.     ……  
  6.     .line 32
  7.     iget-object v0, p0, Lcom/droider/crackme0502/MainActivity;->btnAnno:  
  8.     Landroid/widget/Button;  
  9.     new-instance v1, Lcom/droider/crackme0502/MainActivity$1; #新建一個  
  10.     MainActivity$1例項  
  11.     invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity$1;  
  12. -><init>(Lcom/droider/crackme0502/MainActivity;)V # 初始化MainActivity$1
  13. 例項  
  14.     invoke-virtual {v0, v1}, Landroid/widget/Button;  
  15. ->setOnClickListener(Landroid/view/View$OnClickListener;)V # 設定按鈕點選事件  
  16. 監聽器  
  17.     .line 40
  18.     iget-object v0, p0, Lcom/droider/crackme0502/MainActivity;  
  19. ->btnCheckSN:Landroid/widget/Button;  
  20.     new-instance v1, Lcom/droider/crackme0502/MainActivity$2; #新建一個  
  21. MainActivity$2例項  
  22.     invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity$2
  23. -><init>(Lcom/droider/crackme0502/MainActivity;)V; # 初始化MainActivity$2例項  
  24.     invoke-virtual {v0, v1}, Landroid/widget/Button;  
  25. ->setOnClickListener(Landroid/view/View$OnClickListener;)V#設定按鈕點選事件  
  26. 監聽器  
  27.     .line 50
  28.     return-void
  29. .end method  

在MainActivity$1.smali 檔案的開頭使用了“.implements ”指令指定該類實現了按鈕點選事件的監聽器介面,因此,這個類實現了它的OnClick()方法,這也是我們在分析程式時關心的地方。另外,程式中的註解與監聽器的建構函式都是編譯器為我們自己生成的,實際分析過程中不必關心。

3、註解類



註解是Java 的語言特性,在 Android的開發過程中也得到了廣泛的使用。Android系統中涉及到註解的包共有兩個:一個是dalvik.annotation;另一個是 android.annotation。

例如:

  1. # annotations  
  2. .annotation system Ldalvik/annotation/AnnotationDefault;  
  3.     value = .subannotation Lcom/droider/anno/MyAnnoClass;  
  4.         value = "MyAnnoClass"
  5.     .end subannotation  
  6. .end annotation  

除了SuppressLint與TargetApi註解,android.annotation 包還提供了SdkConstant與Widget兩個註解,這兩個註解在註釋中被標記為“@hide”,即在 SDK 中是不可見的。SdkConstant註解指定了SDK中可以被匯出的常量欄位值,Widget 註解指定了哪些類是 UI類,這兩個註解在分析Android程式時基本上碰不到,此處就不去探究了。

4、自動生成的類

使用 Android SDK 預設生成的工程會自動新增一些類。例如:

  1. publicfinalclass R {  
  2.     publicstaticfinalclass attr {      //屬性
  3.     }  
  4.     publicstaticfinalclass dimen {      //尺寸
  5.         publicstaticfinalint padding_large=0x7f040002;  
  6.         publicstaticfinalint padding_medium=0x7f040001;  
  7.         publicstaticfinalint padding_small=0x7f040000;  
  8.     }  
  9.     publicstaticfinalclass drawable {    //圖片
  10.         publicstaticfinalint ic_action_search=0x7f020000;  
  11.         publicstaticfinalint ic_launcher=0x7f020001;  
  12.     }  
  13.     publicstaticfinalclass id {        //id標識
  14.         publicstaticfinalint btn_annotation=0x7f080000;  
  15.         publicstaticfinalint btn_checksn=0x7f080002;  
  16.         publicstaticfinalint edt_sn=0x7f080001;  
  17.         publicstaticfinalint menu_settings=0x7f080003;  
  18.     }  
  19.     publicstaticfinalclass layout {    // 佈局
  20.         publicstaticfinalint activity_main=0x7f030000;  
  21.     }  
  22.     publicstaticfinalclass menu {    // 選單
  23.         publicstaticfinalint activity_main=0x7f070000;  
  24.     }  
  25.     publicstaticfinalclass string {    // 字串
  26.         publicstaticfinalint app_name=0x7f050000;  
  27.         publicstaticfinalint hello_world=0x7f050001;  
  28.         publicstaticfinalint menu_settings=0x7f050002;  
  29.         publicstaticfinalint title_activity_main=0x7f050003;  
  30.     }  
  31.     publicstaticfinalclass style {    // 樣式
  32.         publicstaticfinalint AppTheme=0x7f060000;  
  33.     }  
  34. }  
由於這些資源類都是R 類的內部類,因此它們都會獨立生成一個類檔案,在反編譯出的程式碼中,可以發現有R.smali、R$attr.smali 、R$dimen.smali、R$drawable.smali、R$id.smali、R$layout.smali、R$menu.smali 、R$string.smali 、R$style.smali 等幾個檔案。
閱讀smali反編譯的程式碼

smali 檔案中的語句特點:

1、迴圈語句

在 Android開發過程中,常見的迴圈結構有迭代器迴圈、for 迴圈、while迴圈、do while 迴圈。我們在編寫迭代器迴圈程式碼時,一般是如下形式的程式碼:

  1. Iterator< 物件> <物件名> = <方法返回一個物件列表>;  
  2. for (< 物件> <物件名> : <物件列表>) {  
  3. [處理單個物件的程式碼體]  
  4. }  
  5. 或者:  
  6. Iterator< 物件> <迭代器> = <方法返回一個迭代器>;  
  7. while (<迭代器>.hasNext()) {  
  8.  <物件> <物件名> = <迭代器>.next();  
  9. [處理單個物件的程式碼體]  
  10. }  

  1. .method private iterator()V  
  2.     .locals 7
  3.     .prologue  
  4.     .line 34
  5.     const-string v4, "activity"
  6.     invoke-virtual {p0, v4}, Lcom/droider/circulate/MainActivity;->  
  7.     getSystemService  
  8.          (Ljava/lang/String;)Ljava/lang/Object;  # 獲取ActivityManager  
  9.     move-result-object v0  
  10.     check-cast v0, Landroid/app/ActivityManager;  
  11.     .line 35
  12.     .local v0, activityManager:Landroid/app/ActivityManager;  
  13.     invoke-virtual {v0}, Landroid/app/ActivityManager;->getRunningAppProcesses()  
  14.     Ljava/util/List;  
  15.     move-result-object v2    #正在執行的程序列表  
  16.     .line 36
  17.     .local v2, psInfos:Ljava/util/List;,  
  18.     "Ljava/util/List<Landroid/app/ActivityManager$RunningAppProcessInfo;>;"
  19.     new-instance v3, Ljava/lang/StringBuilder;  # 新建一個StringBuilder 物件  
  20.     invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V  # 呼叫  
  21.     StringBuilder 建構函式  
  22.     .line 37
  23.     .local v3, sb:Ljava/lang/StringBuilder;  
  24.     invoke-interface {v2}, Ljava/util/List;->iterator()Ljava/util/Iterator;  
  25.  #獲取程序列表的迭代器  
  26.     move-result-object v4  
  27.     :goto_0 #迭代迴圈開始  
  28.     invoke-interface {v4}, Ljava/util/Iterator;->hasNext()Z #開始迭代  
  29.     move-result v5  
  30.     if-nez v5, :cond_0  # 如果迭代器不為空就跳走  
  31.     .line 40
  32.     invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/  
  33.     String;  
  34.     move-result-object v4  # StringBuilder轉為字串  
  35.     const/4 v5, 0x0
  36.     invoke-static {p0, v4, v5}, Landroid/widget/Toast;->makeText  
  37.          (Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/  
  38.          widget/Toast;  
  39.     move-result-object v4  
  40.     invoke-virtual {v4}, Landroid/widget/Toast;->show()V # 彈出StringBuilder  
  41.     的內容  
  42.     .line 41
  43.     return-void  # 方法返回  
  44.     .line 37
  45.     :cond_0  
  46.     invoke-interface {v4}, Ljava/util/Iterator;->next()Ljava/lang/Object;   
  47.     # 迴圈獲取每一項  
  48.     move-result-object v1  
  49.     check-cast v1, Landroid/app/ActivityManager$RunningAppProcessInfo;  
  50.     .line 38
  51.     .local v1, info:Landroid/app/ActivityManager$RunningAppProcessInfo;  
  52.     new-instance v5, Ljava/lang/StringBuilder;  # 新建一個臨時的StringBuilder  
  53.     iget-object v6, v1, Landroid/app/ActivityManager$RunningAppProcessInfo;  
  54.         ->processName:Ljava/lang/String;    #獲取程序的程序名  
  55.     invoke-static {v6}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)  
  56.     Ljava/lang/String;  
  57.     move-result-object v6  
  58.     invoke-direct {v5, v6}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/  
  59.     String;)V  
  60.     const/16 v6, 0xa #換行符  
  61.     invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(C)Ljava/  
  62.     lang/StringBuilder;  
  63.     move-result-object v5 # 組合程序名與換行符  
  64.     invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/  
  65.     String;  
  66.     move-result-object v5  
  67.     invoke-virtual {v3, v5}, Ljava/lang/StringBuilder; # 將組合後的字串新增到  
  68.     StringBuilder 末尾  
  69.         ->append(Ljava/lang/String;)Ljava/lang/StringBuilder;  
  70.     goto :goto_0  #跳轉到迴圈開始處  
  71. .end method  

這段程式碼的功能是獲取正在執行的程序列表,然後使用Toast彈出所有的程序名。

forCirculate() 方法如下:

  1. .method private forCirculate()V  
  2.     .locals 8
  3.     .prologue  
  4.     .line 47
  5.     invoke-virtual {p0}, Lcom/droider/circulate/MainActivity;-  
  6.         >getApplicationContext()Landroid/content/Context;  
  7.     move-result-object v6  
  8.     invoke-virtual {v6}, Landroid/content/Context;    #獲取PackageManager  
  9.         ->getPackageManager()Landroid/content/pm/PackageManager;  
  10.     move-result-object v3  
  11.     .line 49
  12.     .local v3, pm:Landroid/content/pm/PackageManager;  
  13.     const/16 v6, 0x2000
  14.     .line 48
  15.     invoke-virtual {v3, v6}, Landroid/content/pm/PackageManager;  
  16.         ->getInstalledApplications(I)Ljava/util/List;  #獲取已安裝的程式列表  
  17.     move-result-object v0  
  18.     .line 50
  19.     .local v0, appInfos:Ljava/util/List;,"Ljava/util/List<Landroid/content/pm  
  20.     /ApplicationInfo;>;"  
  21.     invoke-interface {v0}, Ljava/util/List;->size()I  # 獲取列表中ApplicationInfo  
  22.     物件的個數  
  23.     move-result v5  
  24.     .line 51
  25.     .local v5, size:I  
  26.     new-instance v4, Ljava/lang/StringBuilder;          # 新建一個  
  27.     StringBuilder 物件  
  28.     invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V  # 呼叫  
  29.     StringBuilder 的建構函式  
  30.     .line 52
  31.     .local v4, sb:Ljava/lang/StringBuilder;  
  32.     const/4 v1, 0x0
  33.     .local v1, i:I #初始化v1為0
  34.     :goto_0 #迴圈開始  
  35.     if-lt v1, v5, :cond_0   #如果v1小於v5,則跳轉到cond_0 標號處  
  36.     .line 56
  37.     invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/  
  38.     lang/String;  
  39.     move-result-object v6  
  40.     const/4 v7, 0x0
  41.     invoke-static {p0, v6, v7}, Landroid/widget/Toast; #構造Toast  
  42.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  43.         Landroid/widget/Toast;  
  44.     move-result-object v6  
  45.     invoke-virtual {v6}, Landroid/widget/Toast;->show()V #顯示已安裝的程式列表  
  46.     .line 57
  47.     return-void  # 方法返回  
  48.     .line 53
  49.     :cond_0  
  50.     invoke-interface {v0, v1}, Ljava/util/List;->get(I)Ljava/lang/Object;   
  51.     # 單個ApplicationInfo  
  52.     move-result-object v2  
  53.     check-cast v2, Landroid/content/pm/ApplicationInfo;  
  54.     .line 54
  55.     .local v2, info:Landroid/content/pm/ApplicationInfo;  
  56.     new-instance v6, Ljava/lang/StringBuilder;  # 新建一個臨時StringBuilder物件  
  57.     iget-object v7, v2, Landroid/content/pm/ApplicationInfo;->packageName:  
  58.     Ljava/lang/String;  
  59.     invoke-static {v7}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)  
  60.     Ljava/lang/String;  
  61.     move-result-object v7  # 包名  
  62.     invoke-direct {v6, v7}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/  
  63.     String;)V  
  64.     const/16 v7, 0xa #換行符  
  65.     invoke-virtual {v6, v7}, Ljava/lang/StringBuilder;->append(C)Ljava/  
  66.     lang/StringBuilder;  
  67.     move-result-object v6  # 組合包名與換行符  
  68.     invoke-virtual {v6}, Ljava/lang/StringBuilder;->toString()Ljava/lang  
  69.     /String; #轉換為字串  
  70.     move-result-object v6  
  71.     invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;-  
  72.         >append(Ljava/lang/String;)Ljava/lang/StringBuilder;  # 新增到迴圈外        的StringBuilder 中  
  73.     .line 52
  74.     add-int/lit8 v1, v1, 0x1 #下一個索引  
  75.     goto :goto_0 #跳轉到迴圈起始處  
  76. .end method  

這段程式碼的功能是獲取所有安裝的程式,然後使用Toast彈出所有的軟體包名。

2、switch分支語句

packedSwitch()方法的程式碼如下:

  1. .method private packedSwitch(I)Ljava/lang/String;  
  2.     .locals 1
  3.     .parameter "i"
  4.     .prologue  
  5.     .line 21
  6.     const/4 v0, 0x0
  7.     .line 22
  8.     .local v0, str:Ljava/lang/String;  #v0為字串,0表示null
  9.     packed-switch p1, :pswitch_data_0  #packed-switch分支,pswitch_data_0指  
  10.     定case區域  
  11.     .line 36
  12.     const-string v0, "she is a person"  #default分支  
  13.     .line 39
  14.     :goto_0      #所有case的出口  
  15.     return-object v0 #返回字串v0  
  16.     .line 24
  17.     :pswitch_0    #case0
  18.     const-string v0, "she is a baby"
  19.     .line 25
  20.     goto :goto_0  #跳轉到goto_0標號處  
  21.     .line 27
  22.     :pswitch_1    #case1
  23.     const-string v0, "she is a girl"
  24.     .line 28
  25.     goto :goto_0  #跳轉到goto_0標號處  
  26.     .line 30
  27.     :pswitch_2    #case2
  28.     const-string v0, "she is a woman"
  29.     .line 31
  30.     goto :goto_0  #跳轉到goto_0標號處  
  31.     .line 33
  32.     :pswitch_3    #case3
  33.     const-string v0, "she is an obasan"
  34.     .line 34
  35.     goto :goto_0  #跳轉到goto_0標號處  
  36.     .line 22
  37.     nop  
  38.     :pswitch_data_0  
  39.     .packed-switch0x0    #case  區域,從0開始,依次遞增  
  40.         :pswitch_0  #case0
  41.         :pswitch_1  #case1
  42.         :pswitch_2  #case2
  43.         :pswitch_3  #case3
  44.     .end packed-switch
  45. .end method  

程式碼中的switch 分支使用的是 packed-switch 指令。p1為傳遞進來的 int 型別的數值,pswitch_data_0 為case 區域,在 case 區域中,第一條指令“.packed-switch”指定了比較的初始值為0 ,pswitch_0~ pswitch_3分別是比較結果為“case 0 ”到“case 3 ”時要跳轉到的地址。

3、try/catch 語句

tryCatch()方法程式碼如下:

  1. .method private tryCatch(ILjava/lang/String;)V  
  2.     .locals 10
  3.     .parameter "drumsticks"
  4.     .parameter "peple"
  5.     .prologue  
  6.     const/4 v9, 0x0
  7.     .line 19
  8.     :try_start_0  # 第1try開始  
  9.     invoke-static {p2}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I  
  10.  #將第2個引數轉換為int 型  
  11.     :try_end_0    # 第1try結束  
  12.     .catch Ljava/lang/NumberFormatException; {:try_start_0 .. :try_end_0} :  
  13.     catch_1 # catch_1  
  14.     move-result v1  #如果出現異常這裡不會執行,會跳轉到catch_1標號處  
  15.     .line 21
  16.     .local v1, i:I    #.local宣告的變數作用域在.local宣告與.end local 之間  
  17.     :try_start_1  #第2try 開始  
  18.     div-int v2, p1, v1  # 第1個引數除以第2個引數  
  19.     .line 22
  20.     .local v2, m:I    #m為商  
  21.     mul-int v5, v2, v1  #m * i  
  22.     sub-int v3, p1, v5  #v3 為餘數  
  23.     .line 23
  24.     .local v3, n:I  
  25.     const-string v5, "\u5171\u6709%d\u53ea\u9e21\u817f\uff0c%d  
  26.         \u4e2a\u4eba\u5e73\u5206\uff0c\u6bcf\u4eba\u53ef\u5206\u5f97%d  
  27.         \u53ea\uff0c\u8fd8\u5269\u4e0b%d\u53ea"   # 格式化字串  
  28.     const/4 v6, 0x4
  29.     new-array v6, v6, [Ljava/lang/Object;  
  30.     const/4 v7, 0x0
  31.     .line 24
  32.     invoke-static {p1}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;  
  33.     move-result-object v8  
  34.     aput-object v8, v6, v7  
  35.     const/4 v7, 0x1
  36.     invoke-static {v1}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;  
  37.     move-result-object v8  
  38.     aput-object v8, v6, v7  
  39.     const/4 v7, 0x2
  40.     invoke-static {v2}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;  
  41.     move-result-object v8  
  42.     aput-object v8, v6, v7  
  43.     const/4 v7, 0x3
  44.     invoke-static {v3}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;  
  45.     move-result-object v8  
  46.     aput-object v8, v6, v7  
  47.     .line 23
  48.     invoke-static {v5, v6}, Ljava/lang/String;  
  49.         ->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;  
  50.     move-result-object v4  
  51.     .line 25
  52.     .local v4, str:Ljava/lang/String;  
  53.     const/4 v5, 0x0
  54.     invoke-static {p0, v4, v5}, Landroid/widget/Toast;  
  55.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  56.         Landroid/widget/Toast;  
  57.     move-result-object v5  
  58.     invoke-virtual {v5}, Landroid/widget/Toast;->show()V  # 使用Toast 顯示格  
  59.     式化後的結果  
  60.     :try_end_1  #第2try 結束  
  61.     .catch Ljava/lang/ArithmeticException; {:try_start_1 .. :try_end_1} :  
  62.     catch_0   # catch_0  
  63.     .catch Ljava/lang/NumberFormatException; {:try_start_1 .. :try_end_1} :  
  64.     catch_1   # catch_1  
  65.     .line 33
  66.     .end local v1           #i:I  
  67.     .end local v2           #m:I  
  68.     .end local v3           #n:I  
  69.     .end local v4           #str:Ljava/lang/String;  
  70.     :goto_0   
  71.     return-void  # 方法返回  
  72.     .line 26
  73.     .restart local v1       #i:I  
  74.     :catch_0     
  75.     move-exception v0  
  76.     .line 27
  77.     .local v0, e:Ljava/lang/ArithmeticException;  
  78.     :try_start_2  #第3try 開始  
  79.     const-string v5, "\u4eba\u6570\u4e0d\u80fd\u4e3a0" #“人數不能為0”  
  80.     const/4 v6, 0x0
  81.     invoke-static {p0, v5, v6}, Landroid/widget/Toast;  
  82.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  83.         Landroid/widget/Toast;  
  84.     move-result-object v5  
  85.     invoke-virtual {v5}, Landroid/widget/Toast;->show()V  # 使用Toast 顯示異    常原因  
  86.     :try_end_2    #第3try 結束  
  87.     .catch Ljava/lang/NumberFormatException; {:try_start_2 .. :try_end_2} :  
  88.     catch_1  
  89.     goto :goto_0 #返回  
  90.     .line 29
  91.     .end local v0           #e:Ljava/lang/ArithmeticException;  
  92.     .end local v1           #i:I  
  93.     :catch_1   
  94.     move-exception v0  
  95.     .line 30
  96.     .local v0, e:Ljava/lang/NumberFormatException;  
  97.     const-string v5, "\u65e0\u6548\u7684\u6570\u503c\u5b57\u7b26\u4e32"
  98.     #“無效的數值字串”  
  99.     invoke-static {p0, v5, v9}, Landroid/widget/Toast;  
  100.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  101.         Landroid/widget/Toast;  
  102.     move-result-object v5  
  103.     invoke-virtual {v5}, Landroid/widget/Toast;->show()V  # 使用Toast 顯示異  
  104.     常原因  
  105.     goto :goto_0 #返回  
  106. .end method  


整段程式碼的功能比較簡單,輸入雞腿數與人數,然後使用Toast彈出雞腿的分配方案。傳入人數時為了演示Try/Catch效果,使用了String 型別。程式碼中有兩種情況下會發生異常:第一種是將String 型別轉換成 int 型別時可能會發生 NumberFormatException異常;第二種是計算分配方法時除數為零的ArithmeticException異常。
在Dalvik 指令集中,並沒有與Try/Catch相關的指令,在處理Try/Catch語句時,是通過相關的資料結構來儲存異常資訊的。
小結

靜態分析是軟體分析過程中最基礎也是最重要的一種手段,我們向Android逆向破解又邁進了一大步。