smali語法詳解
smali檔案格式
每個smali檔案都由若干條語句組成,所有的語句都遵循著一套語法規則。在smali 檔案的頭3 行描述了當前類的一些資訊,格式如下:
- .class < 訪問許可權> [ 修飾關鍵字] < 類名>
- .super < 父類名>
- .source <原始檔名>
開啟MainActivity.smali 檔案,頭3 行程式碼如下:
- .class public Lcom/droider/crackme0502/MainActivity; //指令指定了當前類的類名。
- .super Landroid/app/Activity;<span style=“white-space:pre”> </span>//指令指定了當前類的父類。
- .source ”MainActivity.java”<span style=“white-space:pre”> </span>//指令指定了當前類的原始檔名。
smali檔案中欄位的宣告使用“.field”指令。欄位有靜態欄位與例項欄位兩種。靜態欄位的宣告格式如下:
- # static fields
- .field < 訪問許可權> static [ 修飾關鍵字] < 欄位名>:< 欄位型別>
例項欄位的宣告與靜態欄位類似,只是少了static關鍵字,它的格式如下:
- # instance fields
- .field < 訪問許可權> [ 修飾關鍵字] < 欄位名>:< 欄位型別>
- 比如以下的例項欄位宣告。
- # instance fields //baksmali 生成的註釋
- .field private btnAnno:Landroid/widget/Button; //私有欄位
smali 檔案中方法的宣告使用“.method ”指令,方法有直接方法與虛方法兩種。
直接方法的宣告格式如下:
- # direct methods //新增的註釋
- .method <訪問許可權> [ 修飾關鍵字] < 方法原型>
- <.locals> //指定了使用的區域性變數的個數
- [.parameter] //指定了方法的引數
- [.prologue] //指定了程式碼的開始處,混淆過的程式碼可能去掉了該指令
- [.line] //指定了該處指令在原始碼中的行號
- <程式碼體>
- .end method
虛方法的宣告與直接方法相同,只是起始處的註釋為“virtual methods”,如果一個類實現了介面,會在smali 檔案中使用“.implements ”指令指出,相應的格式宣告如下:
- # interfaces
- .implements < 介面名> //介面關鍵字
- 如果一個類使用了註解,會在 smali 檔案中使用“.annotation ”指令指出,註解的格式宣告如下:
- # annotations
- .annotation [ 註解屬性] < 註解類名>
- [ 註解欄位 = 值]
- .end annotation
註解的作用範圍可以是類、方法或欄位。如果註解的作用範圍是類,“.annotation ”指令會直接定義在smali 檔案中,如果是方法或欄位,“.annotation ”指令則會包含在方法或欄位定義中。例如:
- # instance fields
- .field public sayWhat:Ljava/lang/String; //String 型別 它使用了 com.droider.anno.MyAnnoField 註解,註解欄位info 值為“Hello my friend”
- .annotation runtime Lcom/droider/anno/MyAnnoField;
- info = ”Hello my friend”
- .end annotation
- .end field
Android 程式中的類
1、內部類
Java 語言允許在一個類的內部定義另一個類,這種在類中定義的類被稱為內部類(Inner Class)。內部類可分為成員內部類、靜態巢狀類、方法內部類、匿名內部類。在反編譯dex 檔案的時候,會為每個類單獨生成了一個 smali 檔案,內部類作為一個獨立的類,它也擁有自己獨立的smali 檔案,只是內部類的檔名形式為“[外部類]$[內部類].smali ”,例如:
- class Outer {
- class Inner{}
- }
反編譯上述程式碼後會生成兩個檔案:Outer.smali 與Outer$Inner.smali。開啟檔案,程式碼結構如下:
- .class public Lcom/droider/crackme0502/MainActivitySNChecker; </span></span></li><li><span>.<span class="keyword">super</span><span> Ljava/lang/Object; </span></span></li><li class="alt"><span>.source <span class="string">"MainActivity.java"</span><span> </span></span></li><li><span> </span></li><li class="alt"><span># annotations </span></li><li><span>.annotation system Ldalvik/annotation/EnclosingClass; </span></li><li class="alt"><span> value = Lcom/droider/crackme0502/MainActivity; </span></li><li><span>.end annotation </span></li><li class="alt"><span>.annotation system Ldalvik/annotation/InnerClass; </span></li><li><span> accessFlags = <span class="number">0x1</span><span> </span></span></li><li class="alt"><span> name = <span class="string">"SNChecker"</span><span> </span></span></li><li><span>.end annotation </span></li><li class="alt"><span> </span></li><li><span># instance fields </span></li><li class="alt"><span>.field <span class="keyword">private</span><span> sn:Ljava/lang/String; </span></span></li><li><span>.field <span class="keyword">final</span><span> synthetic </span><span class="keyword">this</span><span>0:Lcom/droider/crackme0502/MainActivity;
- # direct methods
- .method public constructor
- <init>(Lcom/droider/crackme0502/MainActivity;Ljava/lang/String;)V
- ……
- .end method
- # virtual methods
- .method public isRegistered()Z
- ……
- .end method
發現它有兩個註解定義塊“Ldalvik/annotation/EnclosingClass;”與“Ldalvik/annotation/ InnerClass; ”、兩個例項欄位sn 與this
2、監聽器
Android程式開發中大量使用到了監聽器,如Button的點選事件響應OnClickListener、Button的長按事件響應OnLongClickListener、ListView列表項的點選事件響應 OnItemSelected-Listener等。
例項原始碼以及反編譯設定按鈕點選事件監聽器的程式碼如下:
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- btnAnno = (Button) findViewById(R.id.btn_annotation);
- btnCheckSN = (Button) findViewById(R.id.btn_checksn);
- edtSN = (EditText) findViewById(R.id.edt_sn);
- btnAnno.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- getAnnotations();
- }
- });
- btnCheckSN.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- SNChecker checker = new SNChecker(edtSN.getText().toString());
- String str = checker.isRegistered() ? ”註冊碼正確” : “註冊碼錯誤”;
- Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
- }
- });
- }
- 反編譯如下:
- .method public onCreate(Landroid/os/Bundle;)V
- .locals 2
- .parameter ”savedInstanceState”
- ……
- .line 32
- iget-object v0, p0, Lcom/droider/crackme0502/MainActivity;->btnAnno:
- Landroid/widget/Button;
- new-instance v1, Lcom/droider/crackme0502/MainActivity1; #新建一個
- MainActivity1例項
- invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity<span class="number">1</span><span>; </span></span></li><li><span>-><init>(Lcom/droider/crackme0502/MainActivity;)V # 初始化MainActivity1
- 例項
- invoke-virtual {v0, v1}, Landroid/widget/Button;
- ->setOnClickListener(Landroid/view/ViewOnClickListener;)V # 設定按鈕點選事件 </span></li><li><span>監聽器 </span></li><li class="alt"><span> .line <span class="number">40</span><span> </span></span></li><li><span> iget-object v0, p0, Lcom/droider/crackme0502/MainActivity; </span></li><li class="alt"><span>->btnCheckSN:Landroid/widget/Button; </span></li><li><span> <span class="keyword">new</span><span>-instance v1, Lcom/droider/crackme0502/MainActivity2; #新建一個
- MainActivity<span class="number">2</span><span>例項 </span></span></li><li><span> invoke-direct {v1, p0}, Lcom/droider/crackme0502/MainActivity2
- -><init>(Lcom/droider/crackme0502/MainActivity;)V; # 初始化MainActivity<span class="number">2</span><span>例項 </span></span></li><li><span> invoke-virtual {v0, v1}, Landroid/widget/Button; </span></li><li class="alt"><span>->setOnClickListener(Landroid/view/ViewOnClickListener;)V#設定按鈕點選事件
- 監聽器
- .line 50
- return-void
- .end method
在MainActivity$1.smali 檔案的開頭使用了“.implements ”指令指定該類實現了按鈕點選事件的監聽器介面,因此,這個類實現了它的OnClick()方法,這也是我們在分析程式時關心的地方。另外,程式中的註解與監聽器的建構函式都是編譯器為我們自己生成的,實際分析過程中不必關心。
3、註解類
註解是Java 的語言特性,在 Android的開發過程中也得到了廣泛的使用。Android系統中涉及到註解的包共有兩個:一個是dalvik.annotation;另一個是 android.annotation。
例如:
- # annotations
- .annotation system Ldalvik/annotation/AnnotationDefault;
- value = .subannotation Lcom/droider/anno/MyAnnoClass;
- value = ”MyAnnoClass”
- .end subannotation
- .end annotation
除了SuppressLint與TargetApi註解,android.annotation 包還提供了SdkConstant與Widget兩個註解,這兩個註解在註釋中被標記為“@hide”,即在 SDK 中是不可見的。SdkConstant註解指定了SDK中可以被匯出的常量欄位值,Widget 註解指定了哪些類是 UI類,這兩個註解在分析Android程式時基本上碰不到,此處就不去探究了。
4、自動生成的類
使用 Android SDK 預設生成的工程會自動新增一些類。例如:
- public final class R {
- public static final class attr { //屬性
- }
- public static final class dimen { //尺寸
- public static final int padding_large=0x7f040002;
- public static final int padding_medium=0x7f040001;
- public static final int padding_small=0x7f040000;
- }
- public static final class drawable { //圖片
- public static final int ic_action_search=0x7f020000;
- public static final int ic_launcher=0x7f020001;
- }
- public static final class id { //id標識
- public static final int btn_annotation=0x7f080000;
- public static final int btn_checksn=0x7f080002;
- public static final int edt_sn=0x7f080001;
- public static final int menu_settings=0x7f080003;
- }
- public static final class layout { // 佈局
- public static final int activity_main=0x7f030000;
- }
- public static final class menu { // 選單
- public static final int activity_main=0x7f070000;
- }
- public static final class string { // 字串
- public static final int app_name=0x7f050000;
- public static final int hello_world=0x7f050001;
- public static final int menu_settings=0x7f050002;
- public static final int title_activity_main=0x7f050003;
- }
- public static final class style { // 樣式
- public static final int AppTheme=0x7f060000;
- }
- }
由於這些資源類都是R 類的內部類,因此它們都會獨立生成一個類檔案,在反編譯出的程式碼中,可以發現有R.smali、R
閱讀smali反編譯的程式碼
smali 檔案中的語句特點:
1、迴圈語句
在 Android開發過程中,常見的迴圈結構有迭代器迴圈、for 迴圈、while迴圈、do while 迴圈。我們在編寫迭代器迴圈程式碼時,一般是如下形式的程式碼:
- Iterator< 物件> <物件名> = <方法返回一個物件列表>;
- for (< 物件> <物件名> : <物件列表>) {
- [處理單個物件的程式碼體]
- }
- 或者:
- Iterator< 物件> <迭代器> = <方法返回一個迭代器>;
- while (<迭代器>.hasNext()) {
- <物件> <物件名> = <迭代器>.next();
- [處理單個物件的程式碼體]
- }
- .method private iterator()V
- .locals 7
- .prologue
- .line 34
- const-string v4, “activity”
- invoke-virtual {p0, v4}, Lcom/droider/circulate/MainActivity;->
- getSystemService
- (Ljava/lang/String;)Ljava/lang/Object; # 獲取ActivityManager
- move-result-object v0
- check-cast v0, Landroid/app/ActivityManager;
- .line 35
- .local v0, activityManager:Landroid/app/ActivityManager;
- invoke-virtual {v0}, Landroid/app/ActivityManager;->getRunningAppProcesses()
- Ljava/util/List;
- move-result-object v2 #正在執行的程式列表
- .line 36
- .local v2, psInfos:Ljava/util/List;,
- ”Ljava/util/List<Landroid/app/ActivityManagerRunningAppProcessInfo;>;"</span><span> </span></span></li><li class="alt"><span> <span class="keyword">new</span><span>-instance v3, Ljava/lang/StringBuilder; # 新建一個StringBuilder 物件 </span></span></li><li><span> invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V # 呼叫 </span></li><li class="alt"><span> StringBuilder 建構函式 </span></li><li><span> .line <span class="number">37</span><span> </span></span></li><li class="alt"><span> .local v3, sb:Ljava/lang/StringBuilder; </span></li><li><span> invoke-<span class="keyword">interface</span><span> {v2}, Ljava/util/List;->iterator()Ljava/util/Iterator; </span></span></li><li class="alt"><span> #獲取程式列表的迭代器 </span></li><li><span> move-result-object v4 </span></li><li class="alt"><span> :goto_0 #迭代迴圈開始 </span></li><li><span> invoke-<span class="keyword">interface</span><span> {v4}, Ljava/util/Iterator;->hasNext()Z #開始迭代 </span></span></li><li class="alt"><span> move-result v5 </span></li><li><span> <span class="keyword">if</span><span>-nez v5, :cond_0 # 如果迭代器不為空就跳走 </span></span></li><li class="alt"><span> .line <span class="number">40</span><span> </span></span></li><li><span> invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/ </span></li><li class="alt"><span> String; </span></li><li><span> move-result-object v4 # StringBuilder轉為字串 </span></li><li class="alt"><span> <span class="keyword">const</span><span>/</span><span class="number">4</span><span> v5, </span><span class="number">0x0</span><span> </span></span></li><li><span> invoke-<span class="keyword">static</span><span> {p0, v4, v5}, Landroid/widget/Toast;->makeText </span></span></li><li class="alt"><span> (Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/ </span></li><li><span> widget/Toast; </span></li><li class="alt"><span> move-result-object v4 </span></li><li><span> invoke-virtual {v4}, Landroid/widget/Toast;->show()V # 彈出StringBuilder </span></li><li class="alt"><span> 的內容 </span></li><li><span> .line <span class="number">41</span><span> </span></span></li><li class="alt"><span> <span class="keyword">return</span><span>-</span><span class="keyword">void</span><span> # 方法返回 </span></span></li><li><span> .line <span class="number">37</span><span> </span></span></li><li class="alt"><span> :cond_0 </span></li><li><span> invoke-<span class="keyword">interface</span><span> {v4}, Ljava/util/Iterator;->next()Ljava/lang/Object; </span></span></li><li class="alt"><span> # 迴圈獲取每一項 </span></li><li><span> move-result-object v1 </span></li><li class="alt"><span> check-cast v1, Landroid/app/ActivityManagerRunningAppProcessInfo;
- .line 38
- .local v1, info:Landroid/app/ActivityManagerRunningAppProcessInfo; </span></li><li><span> <span class="keyword">new</span><span>-instance v5, Ljava/lang/StringBuilder; # 新建一個臨時的StringBuilder </span></span></li><li class="alt"><span> iget-object v6, v1, Landroid/app/ActivityManagerRunningAppProcessInfo;
- ->processName:Ljava/lang/String; #獲取程式的程式名
- invoke-static {v6}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)
- Ljava/lang/String;
- move-result-object v6
- invoke-direct {v5, v6}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/
- String;)V
- const/16 v6, 0xa #換行符
- invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(C)Ljava/
- lang/StringBuilder;
- move-result-object v5 # 組合程式名與換行符
- invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/
- String;
- move-result-object v5
- invoke-virtual {v3, v5}, Ljava/lang/StringBuilder; # 將組合後的字串新增到
- StringBuilder 末尾
- ->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
- goto :goto_0 #跳轉到迴圈開始處
- .end method
這段程式碼的功能是獲取正在執行的程式列表,然後使用Toast彈出所有的程式名。
forCirculate() 方法如下:
- .method private forCirculate()V
- .locals 8
- .prologue
- .line 47
- invoke-virtual {p0}, Lcom/droider/circulate/MainActivity;-
- >getApplicationContext()Landroid/content/Context;
- move-result-object v6
- invoke-virtual {v6}, Landroid/content/Context; #獲取PackageManager
- ->getPackageManager()Landroid/content/pm/PackageManager;
- move-result-object v3
- .line 49
- .local v3, pm:Landroid/content/pm/PackageManager;
- const/16 v6, 0x2000
- .line 48
- invoke-virtual {v3, v6}, Landroid/content/pm/PackageManager;
- ->getInstalledApplications(I)Ljava/util/List; #獲取已安裝的程式列表
- move-result-object v0
- .line 50
- .local v0, appInfos:Ljava/util/List;,”Ljava/util/List<Landroid/content/pm
- /ApplicationInfo;>;”
- invoke-interface {v0}, Ljava/util/List;->size()I # 獲取列表中ApplicationInfo
- 物件的個數
- move-result v5
- .line 51
- .local v5, size:I
- new-instance v4, Ljava/lang/StringBuilder; # 新建一個
- StringBuilder 物件
- invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V # 呼叫
- StringBuilder 的建構函式
- .line 52
- .local v4, sb:Ljava/lang/StringBuilder;
- const/4 v1, 0x0
- .local v1, i:I #初始化v1為0
- :goto_0 #迴圈開始
- if-lt v1, v5, :cond_0 #如果v1小於v5,則跳轉到cond_0 標號處
- .line 56
- invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/
- lang/String;
- move-result-object v6
- const/4 v7, 0x0
- invoke-static {p0, v6, v7}, Landroid/widget/Toast; #構造Toast
- ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
- Landroid/widget/Toast;
- move-result-object v6
- invoke-virtual {v6}, Landroid/widget/Toast;->show()V #顯示已安裝的程式列表
- .line 57
- return-void # 方法返回
- .line 53
- :cond_0
- invoke-interface {v0, v1}, Ljava/util/List;->get(I)Ljava/lang/Object;
- # 單個ApplicationInfo
- move-result-object v2
- check-cast v2, Landroid/content/pm/ApplicationInfo;
- .line 54
- .local v2, info:Landroid/content/pm/ApplicationInfo;
- new-instance v6, Ljava/lang/StringBuilder; # 新建一個臨時StringBuilder物件
- iget-object v7, v2, Landroid/content/pm/ApplicationInfo;->packageName:
- Ljava/lang/String;
- invoke-static {v7}, Ljava/lang/String;->valueOf(Ljava/lang/Object;)
- Ljava/lang/String;
- move-result-object v7 # 包名
- invoke-direct {v6, v7}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/
- String;)V
- const/16 v7, 0xa #換行符
- invoke-virtual {v6, v7}, Ljava/lang/StringBuilder;->append(C)Ljava/
- lang/StringBuilder;
- move-result-object v6 # 組合包名與換行符
- invoke-virtual {v6}, Ljava/lang/StringBuilder;->toString()Ljava/lang
- /String; #轉換為字串
- move-result-object v6
- invoke-virtual {v4, v6}, Ljava/lang/StringBuilder;-
- >append(Ljava/lang/String;)Ljava/lang/StringBuilder; # 新增到迴圈外 的StringBuilder 中
- .line 52
- add-int/lit8 v1, v1, 0x1 #下一個索引
- goto :goto_0 #跳轉到迴圈起始處
- .end method
這段程式碼的功能是獲取所有安裝的程式,然後使用Toast彈出所有的軟體包名。
2、switch分支語句
packedSwitch()方法的程式碼如下:
- .method private packedSwitch(I)Ljava/lang/String;
- .locals 1
- .parameter ”i”
- .prologue
- .line 21
- const/4 v0, 0x0
- .line 22
- .local v0, str:Ljava/lang/String; #v0為字串,0表示null
- packed-switch p1, :pswitch_data_0 #packed-switch分支,pswitch_data_0指
- 定case區域
- .line 36
- const-string v0, “she is a person” #default分支
- .line 39
- :goto_0 #所有case的出口
- return-object v0 #返回字串v0
- .line 24
- :pswitch_0 #case 0
- const-string v0, “she is a baby”
- .line 25
- goto :goto_0 #跳轉到goto_0標號處
- .line 27
- :pswitch_1 #case 1
- const-string v0, “she is a girl”
- .line 28
- goto :goto_0 #跳轉到goto_0標號處
- .line 30
- :pswitch_2 #case 2
- const-string v0, “she is a woman”
- .line 31
- goto :goto_0 #跳轉到goto_0標號處
- .line 33
- :pswitch_3 #case 3
- const-string v0, “she is an obasan”
- .line 34
- goto :goto_0 #跳轉到goto_0標號處
- .line 22
- nop
- :pswitch_data_0
- .packed-switch 0x0 #case 區域,從0開始,依次遞增
- :pswitch_0 #case 0
- :pswitch_1 #case 1
- :pswitch_2 #case 2
- :pswitch_3 #case 3
- .end packed-switch
- .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()方法程式碼如下:
- .method private tryCatch(ILjava/lang/String;)V
- .locals 10
- .parameter ”drumsticks”
- .parameter ”peple”
- .prologue
- const/4 v9, 0x0
- .line 19
- :try_start_0 # 第1個try開始
- invoke-static {p2}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
- #將第2個引數轉換為int 型
- :try_end_0 # 第1個try結束
- .catch Ljava/lang/NumberFormatException; {:try_start_0 .. :try_end_0} :
- catch_1 # catch_1
- move-result v1 #如果出現異常這裡不會執行,會跳轉到catch_1標號處
- .line 21
- .local v1, i:I #.local宣告的變數作用域在.local宣告與.end local 之間
- :try_start_1 #第2個try 開始
- div-int v2, p1, v1 # 第1個引數除以第2個引數
- .line 22
- .local v2, m:I #m為商
- mul-int v5, v2, v1 #m * i
- sub-int v3, p1, v5 #v3 為餘數
- .line 23
- .local v3, n:I
- const-string v5, ”\u5171\u6709%d\u53ea\u9e21\u817f\uff0c%d
- \u4e2a\u4eba\u5e73\u5206\uff0c\u6bcf\u4eba\u53ef\u5206\u5f97%d
- \u53ea\uff0c\u8fd8\u5269\u4e0b%d\u53ea” # 格式化字串
- const/4 v6, 0x4
- new-array v6, v6, [Ljava/lang/Object;
- const/4 v7, 0x0
- .line 24
- invoke-static {p1}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
- move-result-object v8
- aput-object v8, v6, v7
- const/4 v7, 0x1
- invoke-static {v1}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
- move-result-object v8
- aput-object v8, v6, v7
- const/4 v7, 0x2
- invoke-static {v2}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
- move-result-object v8
- aput-object v8, v6, v7
- const/4 v7, 0x3
- invoke-static {v3}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
- move-result-object v8
- aput-object v8, v6, v7
- .line 23
- invoke-static {v5, v6}, Ljava/lang/String;
- ->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
- move-result-object v4
- .line 25
- .local v4, str:Ljava/lang/String;
- const/4 v5, 0x0
- invoke-static {p0, v4, v5}, Landroid/widget/Toast;
- ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
- Landroid/widget/Toast;
- move-result-object v5
- invoke-virtual {v5}, Landroid/widget/Toast;->show()V # 使用Toast 顯示格
- 式化後的結果
- :try_end_1 #第2個try 結束
- .catch Ljava/lang/ArithmeticException; {:try_start_1 .. :try_end_1} :
- catch_0 # catch_0
- .catch Ljava/lang/NumberFormatException; {:try_start_1 .. :try_end_1} :
- catch_1 # catch_1
- .line 33
- .end local v1 #i:I
- .end local v2 #m:I
- .end local v3 #n:I
- .end local v4 #str:Ljava/lang/String;
- :goto_0
- return-void # 方法返回
- .line 26
- .restart local v1 #i:I
- :catch_0
- move-exception v0
- .line 27
- .local v0, e:Ljava/lang/ArithmeticException;
- :try_start_2 #第3個try 開始
- const-string v5, “\u4eba\u6570\u4e0d\u80fd\u4e3a0” #“人數不能為0”
- const/4 v6, 0x0
- invoke-static {p0, v5, v6}, Landroid/widget/Toast;
- ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
- Landroid/widget/Toast;
- move-result-object v5
- invoke-virtual {v5}, Landroid/widget/Toast;->show()V # 使用Toast 顯示異 常原因
- :try_end_2 #第3個try 結束
- .catch Ljava/lang/NumberFormatException; {:try_start_2 .. :try_end_2} :
- catch_1
- goto :goto_0 #返回
- .line 29
- .end local v0 #e:Ljava/lang/ArithmeticException;
- .end local v1 #i:I
- :catch_1
- move-exception v0
- .line 30
- .local v0, e:Ljava/lang/NumberFormatException;
- const-string v5, “\u65e0\u6548\u7684\u6570\u503c\u5b57\u7b26\u4e32”
- #“無效的數值字串”
- invoke-static {p0, v5, v9}, Landroid/widget/Toast;
- ->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)
- Landroid/widget/Toast;
- move-result-object v5
- invoke-virtual {v5}, Landroid/widget/Toast;->show()V # 使用Toast 顯示異
- 常原因
- goto :goto_0 #返回
- .end method
整段程式碼的功能比較簡單,輸入雞腿數與人數,然後使用Toast彈出雞腿的分配方案。傳入人數時為了演示Try/Catch效果,使用了String 型別。程式碼中有兩種情況下會發生異常:第一種是將String 型別轉換成 int 型別時可能會發生 NumberFormatException異常;第二種是計算分配方法時除數為零的ArithmeticException異常。
在Dalvik 指令集中,並沒有與Try/Catch相關的指令,在處理Try/Catch語句時,是通過相關的資料結構來儲存異常資訊的。
小結
靜態分析是軟體分析過程中最基礎也是最重要的一種手段,我們向Android逆向破解又邁進了一大步。
相關文章
- Smali 語法解析 —— 類
- Smali 語法解析——Hello World
- Smali語法:Registers(暫存器)
- Android反編譯:smali語法Android編譯
- Markdown語法詳解
- 詳解Dockerfile基本語法Docker
- Hive sql語法詳解HiveSQL
- Java語法糖詳解Java
- jQuery 的語法詳解jQuery
- sed命令語法詳解
- 詳解中括號語法及點語法
- Dart語言詳解(二)——基本語法Dart
- nginx與location語法詳解Nginx
- Azure Terraform(二)語法詳解ORM
- es6語法詳解
- SQL之EXPLAIN語法詳解SQLAI
- hive sql 常用語法詳解HiveSQL
- JSP 語法詳解(轉)JS
- Android工程師,如何簡單高效的學會smali語法Android工程師
- Dart語法詳解(三)——進階篇Dart
- Python中裝飾器語法詳解Python
- 以 Golang 為例詳解 AST 抽象語法樹GolangAST抽象語法樹
- python基本語法_輸入輸出詳解Python
- Oracle create tablespace 建立表空間語法詳解Oracle
- Vue 3 元件基礎與模板語法詳解Vue元件
- C#有關介面的語法知識詳解C#
- 自動化整合:Pipeline流水語法詳解
- Linq語法詳細
- Python程式設計入門基礎語法詳解Python程式設計
- 【日語】日語一級考試100個語法詳解
- smali 檔案格式
- Kotlin 程式語言詳解:特點、應用領域及語法教程Kotlin
- 機器學習-牛頓法詳解機器學習
- Android逆向之路—IDEA動態除錯smali語言AndroidIdea除錯
- Android逆向之路---IDEA動態除錯smali語言AndroidIdea除錯
- BCP語法解釋
- Python基本語法_集合set/frozenset_內建方法詳解Python
- Jenkins pipeline:pipeline 使用之語法詳解Jenkins