smali語法詳解

大囚長發表於2018-04-18
smali檔案格式

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

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


開啟MainActivity.smali 檔案,頭3 行程式碼如下:

  1. .class public 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.   
  4. 如果一個類使用了註解,會在 smali 檔案中使用“.annotation ”指令指出,註解的格式宣告如下:  
  5. # annotations  
  6. .annotation [ 註解屬性] < 註解類名>  
  7.     [ 註解欄位 =  值]  
  8. .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. .class public Lcom/droider/crackme0502/MainActivitySNChecker;&nbsp;&nbsp;</span></span></li><li><span>.<span class="keyword">super</span><span>&nbsp;Ljava/lang/Object;&nbsp;&nbsp;</span></span></li><li class="alt"><span>.source&nbsp;<span class="string">"MainActivity.java"</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>#&nbsp;annotations&nbsp;&nbsp;</span></li><li><span>.annotation&nbsp;system&nbsp;Ldalvik/annotation/EnclosingClass;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;=&nbsp;Lcom/droider/crackme0502/MainActivity;&nbsp;&nbsp;</span></li><li><span>.end&nbsp;annotation&nbsp;&nbsp;</span></li><li class="alt"><span>.annotation&nbsp;system&nbsp;Ldalvik/annotation/InnerClass;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;accessFlags&nbsp;=&nbsp;<span class="number">0x1</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;<span class="string">"SNChecker"</span><span>&nbsp;&nbsp;</span></span></li><li><span>.end&nbsp;annotation&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;</span></li><li><span>#&nbsp;instance&nbsp;fields&nbsp;&nbsp;</span></li><li class="alt"><span>.field&nbsp;<span class="keyword">private</span><span>&nbsp;sn:Ljava/lang/String;&nbsp;&nbsp;</span></span></li><li><span>.field&nbsp;<span class="keyword">final</span><span>&nbsp;synthetic&nbsp;</span><span class="keyword">this</span><span>
    SNChecker;&nbsp;&nbsp;</span></span></li><li><span>.<span class="keyword">super</span><span>&nbsp;Ljava/lang/Object;&nbsp;&nbsp;</span></span></li><li class="alt"><span>.source&nbsp;<span class="string">"MainActivity.java"</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;</span></li><li class="alt"><span>#&nbsp;annotations&nbsp;&nbsp;</span></li><li><span>.annotation&nbsp;system&nbsp;Ldalvik/annotation/EnclosingClass;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;=&nbsp;Lcom/droider/crackme0502/MainActivity;&nbsp;&nbsp;</span></li><li><span>.end&nbsp;annotation&nbsp;&nbsp;</span></li><li class="alt"><span>.annotation&nbsp;system&nbsp;Ldalvik/annotation/InnerClass;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;accessFlags&nbsp;=&nbsp;<span class="number">0x1</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;=&nbsp;<span class="string">"SNChecker"</span><span>&nbsp;&nbsp;</span></span></li><li><span>.end&nbsp;annotation&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;</span></li><li><span>#&nbsp;instance&nbsp;fields&nbsp;&nbsp;</span></li><li class="alt"><span>.field&nbsp;<span class="keyword">private</span><span>&nbsp;sn:Ljava/lang/String;&nbsp;&nbsp;</span></span></li><li><span>.field&nbsp;<span class="keyword">final</span><span>&nbsp;synthetic&nbsp;</span><span class="keyword">this</span><span>
    0:Lcom/droider/crackme0502/MainActivity;  
  2.    
  3. # direct methods  
  4. .method public constructor  
  5. <init>(Lcom/droider/crackme0502/MainActivity;Ljava/lang/String;)V  
  6. ……  
  7. .end method  
  8.    
  9. # virtual methods  
  10. .method public isRegistered()Z  
  11. ……  
  12. .end method  


發現它有兩個註解定義塊“Ldalvik/annotation/EnclosingClass;”與“Ldalvik/annotation/ InnerClass; ”、兩個例項欄位sn 與this0init()isRegistered()this

0 、一個直接方法 init()、一個虛方法isRegistered() 。this
0 是內部類自動保留的一個指向所在外部類的引用。左邊的 this 表示為父類的引用,右邊的數值0 表示引用的層數。


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

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

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



  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</span><span class="number">1</span><span>;&nbsp;#新建一個&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;MainActivity
    1; #新建一個  
  10.     MainActivity1例項  
  11.     invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity<span class="number">1</span><span>;&nbsp;&nbsp;</span></span></li><li><span>-&gt;&lt;init&gt;(Lcom/droider/crackme0502/MainActivity;)V&nbsp;#&nbsp;初始化MainActivity
    <span class="number">1</span><span>;&nbsp;&nbsp;</span></span></li><li><span>-&gt;&lt;init&gt;(Lcom/droider/crackme0502/MainActivity;)V&nbsp;#&nbsp;初始化MainActivity
    1  
  12. 例項  
  13.     invoke-virtual {v0, v1}, Landroid/widget/Button;  
  14. ->setOnClickListener(Landroid/view/ViewOnClickListener;)V&nbsp;#&nbsp;設定按鈕點選事件&nbsp;&nbsp;</span></li><li><span>監聽器&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">40</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;iget-object&nbsp;v0,&nbsp;p0,&nbsp;Lcom/droider/crackme0502/MainActivity;&nbsp;&nbsp;</span></li><li class="alt"><span>-&gt;btnCheckSN:Landroid/widget/Button;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">new</span><span>-instance&nbsp;v1,&nbsp;Lcom/droider/crackme0502/MainActivity
    OnClickListener;)V&nbsp;#&nbsp;設定按鈕點選事件&nbsp;&nbsp;</span></li><li><span>監聽器&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">40</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;iget-object&nbsp;v0,&nbsp;p0,&nbsp;Lcom/droider/crackme0502/MainActivity;&nbsp;&nbsp;</span></li><li class="alt"><span>-&gt;btnCheckSN:Landroid/widget/Button;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">new</span><span>-instance&nbsp;v1,&nbsp;Lcom/droider/crackme0502/MainActivity
    2; #新建一個  
  15. MainActivity<span class="number">2</span><span>例項&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-direct&nbsp;{v1,&nbsp;p0},&nbsp;Lcom/droider/crackme0502/MainActivity
    <span class="number">2</span><span>例項&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-direct&nbsp;{v1,&nbsp;p0},&nbsp;Lcom/droider/crackme0502/MainActivity
    2  
  16. -><init>(Lcom/droider/crackme0502/MainActivity;)V; # 初始化MainActivity<span class="number">2</span><span>例項&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-virtual&nbsp;{v0,&nbsp;v1},&nbsp;Landroid/widget/Button;&nbsp;&nbsp;</span></li><li class="alt"><span>-&gt;setOnClickListener(Landroid/view/View
    <span class="number">2</span><span>例項&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-virtual&nbsp;{v0,&nbsp;v1},&nbsp;Landroid/widget/Button;&nbsp;&nbsp;</span></li><li class="alt"><span>-&gt;setOnClickListener(Landroid/view/View
    OnClickListener;)V#設定按鈕點選事件  
  17. 監聽器  
  18.     .line 50  
  19.     return-void  
  20. .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. public final class R {  
  2.     public static final class attr {      //屬性  
  3.     }  
  4.     public static final class dimen {      //尺寸  
  5.         public static final int padding_large=0x7f040002;  
  6.         public static final int padding_medium=0x7f040001;  
  7.         public static final int padding_small=0x7f040000;  
  8.     }  
  9.     public static final class drawable {    //圖片  
  10.         public static final int ic_action_search=0x7f020000;  
  11.         public static final int ic_launcher=0x7f020001;  
  12.     }  
  13.     public static final class id {        //id標識  
  14.         public static final int btn_annotation=0x7f080000;  
  15.         public static final int btn_checksn=0x7f080002;  
  16.         public static final int edt_sn=0x7f080001;  
  17.         public static final int menu_settings=0x7f080003;  
  18.     }  
  19.     public static final class layout {    // 佈局  
  20.         public static final int activity_main=0x7f030000;  
  21.     }  
  22.     public static final class menu {    // 選單  
  23.         public static final int activity_main=0x7f070000;  
  24.     }  
  25.     public static final class string {    // 字串  
  26.         public static final int app_name=0x7f050000;  
  27.         public static final int hello_world=0x7f050001;  
  28.         public static final int menu_settings=0x7f050002;  
  29.         public static final int title_activity_main=0x7f050003;  
  30.     }  
  31.     public static final class style {    // 樣式  
  32.         public static final int AppTheme=0x7f060000;  
  33.     }  
  34. }  


由於這些資源類都是R 類的內部類,因此它們都會獨立生成一個類檔案,在反編譯出的程式碼中,可以發現有R.smali、Rattr.smaliR
attr.smali 、R
dimen.smali、Rdrawable.smaliR
drawable.smali、R
id.smali、Rlayout.smaliR
layout.smali、R
menu.smali 、Rstring.smaliR
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/ActivityManagerRunningAppProcessInfo;&gt;;"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">new</span><span>-instance&nbsp;v3,&nbsp;Ljava/lang/StringBuilder;&nbsp;&nbsp;#&nbsp;新建一個StringBuilder&nbsp;物件&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-direct&nbsp;{v3},&nbsp;Ljava/lang/StringBuilder;-&gt;&lt;init&gt;()V&nbsp;&nbsp;#&nbsp;呼叫&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;建構函式&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">37</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;.local&nbsp;v3,&nbsp;sb:Ljava/lang/StringBuilder;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">interface</span><span>&nbsp;{v2},&nbsp;Ljava/util/List;-&gt;iterator()Ljava/util/Iterator;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;#獲取程式列表的迭代器&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v4&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;:goto_0&nbsp;#迭代迴圈開始&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">interface</span><span>&nbsp;{v4},&nbsp;Ljava/util/Iterator;-&gt;hasNext()Z&nbsp;#開始迭代&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result&nbsp;v5&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>-nez&nbsp;v5,&nbsp;:cond_0&nbsp;&nbsp;#&nbsp;如果迭代器不為空就跳走&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">40</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-virtual&nbsp;{v3},&nbsp;Ljava/lang/StringBuilder;-&gt;toString()Ljava/lang/&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;String;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v4&nbsp;&nbsp;#&nbsp;StringBuilder轉為字串&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const</span><span>/</span><span class="number">4</span><span>&nbsp;v5,&nbsp;</span><span class="number">0x0</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">static</span><span>&nbsp;{p0,&nbsp;v4,&nbsp;v5},&nbsp;Landroid/widget/Toast;-&gt;makeText&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;widget/Toast;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v4&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-virtual&nbsp;{v4},&nbsp;Landroid/widget/Toast;-&gt;show()V&nbsp;#&nbsp;彈出StringBuilder&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;的內容&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">41</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>-</span><span class="keyword">void</span><span>&nbsp;&nbsp;#&nbsp;方法返回&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">37</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;:cond_0&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">interface</span><span>&nbsp;{v4},&nbsp;Ljava/util/Iterator;-&gt;next()Ljava/lang/Object;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;迴圈獲取每一項&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v1&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;check-cast&nbsp;v1,&nbsp;Landroid/app/ActivityManager
    RunningAppProcessInfo;&gt;;"</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">new</span><span>-instance&nbsp;v3,&nbsp;Ljava/lang/StringBuilder;&nbsp;&nbsp;#&nbsp;新建一個StringBuilder&nbsp;物件&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-direct&nbsp;{v3},&nbsp;Ljava/lang/StringBuilder;-&gt;&lt;init&gt;()V&nbsp;&nbsp;#&nbsp;呼叫&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;建構函式&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">37</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;.local&nbsp;v3,&nbsp;sb:Ljava/lang/StringBuilder;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">interface</span><span>&nbsp;{v2},&nbsp;Ljava/util/List;-&gt;iterator()Ljava/util/Iterator;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;#獲取程式列表的迭代器&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v4&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;:goto_0&nbsp;#迭代迴圈開始&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">interface</span><span>&nbsp;{v4},&nbsp;Ljava/util/Iterator;-&gt;hasNext()Z&nbsp;#開始迭代&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result&nbsp;v5&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span><span>-nez&nbsp;v5,&nbsp;:cond_0&nbsp;&nbsp;#&nbsp;如果迭代器不為空就跳走&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">40</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-virtual&nbsp;{v3},&nbsp;Ljava/lang/StringBuilder;-&gt;toString()Ljava/lang/&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;String;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v4&nbsp;&nbsp;#&nbsp;StringBuilder轉為字串&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const</span><span>/</span><span class="number">4</span><span>&nbsp;v5,&nbsp;</span><span class="number">0x0</span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">static</span><span>&nbsp;{p0,&nbsp;v4,&nbsp;v5},&nbsp;Landroid/widget/Toast;-&gt;makeText&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;widget/Toast;&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v4&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-virtual&nbsp;{v4},&nbsp;Landroid/widget/Toast;-&gt;show()V&nbsp;#&nbsp;彈出StringBuilder&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;的內容&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">41</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">return</span><span>-</span><span class="keyword">void</span><span>&nbsp;&nbsp;#&nbsp;方法返回&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;.line&nbsp;<span class="number">37</span><span>&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;:cond_0&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;invoke-<span class="keyword">interface</span><span>&nbsp;{v4},&nbsp;Ljava/util/Iterator;-&gt;next()Ljava/lang/Object;&nbsp;&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;迴圈獲取每一項&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;move-result-object&nbsp;v1&nbsp;&nbsp;</span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;check-cast&nbsp;v1,&nbsp;Landroid/app/ActivityManager
    RunningAppProcessInfo;  
  19.     .line 38  
  20.     .local v1, info:Landroid/app/ActivityManagerRunningAppProcessInfo;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">new</span><span>-instance&nbsp;v5,&nbsp;Ljava/lang/StringBuilder;&nbsp;&nbsp;#&nbsp;新建一個臨時的StringBuilder&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;iget-object&nbsp;v6,&nbsp;v1,&nbsp;Landroid/app/ActivityManager
    RunningAppProcessInfo;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">new</span><span>-instance&nbsp;v5,&nbsp;Ljava/lang/StringBuilder;&nbsp;&nbsp;#&nbsp;新建一個臨時的StringBuilder&nbsp;&nbsp;</span></span></li><li class="alt"><span>&nbsp;&nbsp;&nbsp;&nbsp;iget-object&nbsp;v6,&nbsp;v1,&nbsp;Landroid/app/ActivityManager
    RunningAppProcessInfo;  
  21.         ->processName:Ljava/lang/String;    #獲取程式的程式名  
  22.     invoke-static {v6}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)  
  23.     Ljava/lang/String;  
  24.     move-result-object v6  
  25.     invoke-direct {v5, v6}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/  
  26.     String;)V  
  27.     const/16 v6, 0xa #換行符  
  28.     invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(C)Ljava/  
  29.     lang/StringBuilder;  
  30.     move-result-object v5 # 組合程式名與換行符  
  31.     invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/  
  32.     String;  
  33.     move-result-object v5  
  34.     invoke-virtual {v3, v5}, Ljava/lang/StringBuilder; # 將組合後的字串新增到  
  35.     StringBuilder 末尾  
  36.         ->append(Ljava/lang/String;)Ljava/lang/StringBuilder;  
  37.     goto :goto_0  #跳轉到迴圈開始處  
  38. .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.    
  34.     .local v1, i:I #初始化v1為0  
  35.     :goto_0 #迴圈開始  
  36.     if-lt v1, v5, :cond_0   #如果v1小於v5,則跳轉到cond_0 標號處  
  37.     .line 56  
  38.     invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/  
  39.     lang/String;  
  40.     move-result-object v6  
  41.     const/4 v7, 0x0  
  42.     invoke-static {p0, v6, v7}, Landroid/widget/Toast; #構造Toast  
  43.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  44.         Landroid/widget/Toast;  
  45.     move-result-object v6  
  46.     invoke-virtual {v6}, Landroid/widget/Toast;->show()V #顯示已安裝的程式列表  
  47.     .line 57  
  48.     return-void  # 方法返回  
  49.     .line 53  
  50.     :cond_0  
  51.     invoke-interface {v0, v1}, Ljava/util/List;->get(I)Ljava/lang/Object;   
  52.     # 單個ApplicationInfo  
  53.     move-result-object v2  
  54.     check-cast v2, Landroid/content/pm/ApplicationInfo;  
  55.     .line 54  
  56.     .local v2, info:Landroid/content/pm/ApplicationInfo;  
  57.     new-instance v6, Ljava/lang/StringBuilder;  # 新建一個臨時StringBuilder物件  
  58.     iget-object v7, v2, Landroid/content/pm/ApplicationInfo;->packageName:  
  59.     Ljava/lang/String;  
  60.     invoke-static {v7}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)  
  61.     Ljava/lang/String;  
  62.     move-result-object v7  # 包名  
  63.     invoke-direct {v6, v7}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/  
  64.     String;)V  
  65.     const/16 v7, 0xa #換行符  
  66.     invoke-virtual {v6, v7}, Ljava/lang/StringBuilder;->append(C)Ljava/  
  67.     lang/StringBuilder;  
  68.     move-result-object v6  # 組合包名與換行符  
  69.     invoke-virtual {v6}, Ljava/lang/StringBuilder;->toString()Ljava/lang  
  70.     /String; #轉換為字串  
  71.     move-result-object v6  
  72.     invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;-  
  73.         >append(Ljava/lang/String;)Ljava/lang/StringBuilder;  # 新增到迴圈外        的StringBuilder 中  
  74.     .line 52  
  75.     add-int/lit8 v1, v1, 0x1 #下一個索引  
  76.     goto :goto_0 #跳轉到迴圈起始處  
  77. .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    #case 0  
  18.     const-string v0, “she is a baby”  
  19.     .line 25  
  20.     goto :goto_0  #跳轉到goto_0標號處  
  21.     .line 27  
  22.     :pswitch_1    #case 1  
  23.     const-string v0, “she is a girl”  
  24.     .line 28  
  25.     goto :goto_0  #跳轉到goto_0標號處  
  26.     .line 30  
  27.     :pswitch_2    #case 2  
  28.     const-string v0, “she is a woman”  
  29.     .line 31  
  30.     goto :goto_0  #跳轉到goto_0標號處  
  31.     .line 33  
  32.     :pswitch_3    #case 3  
  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-switch 0x0    #case  區域,從0開始,依次遞增  
  40.         :pswitch_0  #case 0  
  41.         :pswitch_1  #case 1  
  42.         :pswitch_2  #case 2  
  43.         :pswitch_3  #case 3  
  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.    
  47.     aput-object v8, v6, v7  
  48.     .line 23  
  49.     invoke-static {v5, v6}, Ljava/lang/String;  
  50.         ->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;  
  51.     move-result-object v4  
  52.     .line 25  
  53.     .local v4, str:Ljava/lang/String;  
  54.     const/4 v5, 0x0  
  55.     invoke-static {p0, v4, v5}, Landroid/widget/Toast;  
  56.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  57.         Landroid/widget/Toast;  
  58.     move-result-object v5  
  59.     invoke-virtual {v5}, Landroid/widget/Toast;->show()V  # 使用Toast 顯示格  
  60.     式化後的結果  
  61.     :try_end_1  #第2try 結束  
  62.     .catch Ljava/lang/ArithmeticException; {:try_start_1 .. :try_end_1} :  
  63.     catch_0   # catch_0  
  64.     .catch Ljava/lang/NumberFormatException; {:try_start_1 .. :try_end_1} :  
  65.     catch_1   # catch_1  
  66.     .line 33  
  67.     .end local v1           #i:I  
  68.     .end local v2           #m:I  
  69.     .end local v3           #n:I  
  70.     .end local v4           #str:Ljava/lang/String;  
  71.     :goto_0   
  72.     return-void  # 方法返回  
  73.     .line 26  
  74.     .restart local v1       #i:I  
  75.     :catch_0     
  76.     move-exception v0  
  77.     .line 27  
  78.     .local v0, e:Ljava/lang/ArithmeticException;  
  79.     :try_start_2  #第3try 開始  
  80.     const-string v5, “\u4eba\u6570\u4e0d\u80fd\u4e3a0” #“人數不能為0”  
  81.     const/4 v6, 0x0  
  82.     invoke-static {p0, v5, v6}, Landroid/widget/Toast;  
  83.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  84.         Landroid/widget/Toast;  
  85.     move-result-object v5  
  86.     invoke-virtual {v5}, Landroid/widget/Toast;->show()V  # 使用Toast 顯示異    常原因  
  87.     :try_end_2    #第3try 結束  
  88.     .catch Ljava/lang/NumberFormatException; {:try_start_2 .. :try_end_2} :  
  89.     catch_1  
  90.     goto :goto_0 #返回  
  91.     .line 29  
  92.     .end local v0           #e:Ljava/lang/ArithmeticException;  
  93.     .end local v1           #i:I  
  94.     :catch_1   
  95.     move-exception v0  
  96.     .line 30  
  97.     .local v0, e:Ljava/lang/NumberFormatException;  
  98.     const-string v5, “\u65e0\u6548\u7684\u6570\u503c\u5b57\u7b26\u4e32”   
  99.     #“無效的數值字串”  
  100.     invoke-static {p0, v5, v9}, Landroid/widget/Toast;  
  101.         ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)  
  102.         Landroid/widget/Toast;  
  103.     move-result-object v5  
  104.     invoke-virtual {v5}, Landroid/widget/Toast;->show()V  # 使用Toast 顯示異  
  105.     常原因  
  106.     goto :goto_0 #返回  
  107. .end method  




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

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

相關文章