靜態分析Android程序

靜態分析是探索Android程序內幕的一種最多見的方法,它與動態調試雙劍合璧,幫助分析人員解決分析時遇到的各種「疑難」問題。固然,靜態分析技術自己須要分析人員具有較強的代碼理解能力,這些都須要在平時的開發過程當中不斷地積累經驗,很難想象一個連Android應用程序源碼都看不懂的人去逆向分析Android程序。html

1, 什麼是靜態分析

靜態分析(Static Analysis)是指在不運行代碼的狀況下,採用詞法分析、語法分析等各類技術手段對程序文件進行掃描並生成程序的反彙編代碼,而後閱讀反彙編代碼來掌握程序功能的一種技術。在實際的分析過程當中,徹底不運行程序是不太可能的,分析人員時常須要先運行目標程序來尋找程序的突破口。靜態分析強調的是靜態,在整個分析的過程當中,閱讀反彙編代碼是主要的分析工做。生成反彙編代碼的工具稱爲反彙編工具或反編譯工具,選擇一個功能強大的反彙編工具不只能得到更好的反彙編效果,並且也能爲分析人員節省很多時間。在Android的逆向分析中,常見的工具備APkTool、baksmail、dex2jar和Editor等工具,具體分析時須要靈活的使用這些工具。java

靜態分析Android程序有兩種方法:一種方法是閱讀反彙編生成的Dalvik字節碼,可使用IDA Pro分析dex文件,或者使用文本編輯器閱讀baksmali反編譯生成的smali文件;另外一種方法是閱讀反彙編生成的Java源碼,可使用dex2jar生成jar文件,而後再使用jd-gui閱讀jar文件的代碼。android

2, 如何快速定位程序的關鍵代碼

在逆向一個Android軟件時,因爲軟件的複雜性,若是盲目的進行分析,可能須要閱讀成千上萬行的反彙編代碼才能找到程序的關鍵點,這無疑是浪費時間的表現,本小節將介紹如何快速的定位程序的關鍵代碼。程序員

2.1反編譯apk程序

每一個apk文件中都包含有一個AndroidManifest.xml文件,它記錄着軟件的一些基本信息。包括軟件的包名、運行的系統版本、用到的組件等。而且這個文件被加密存儲進了apk文件中,在開始分析前,有必要先反編譯apk文件對其進行解密。反編譯apk的工具使用前面章節介紹過的Apktool。Apktool提供了反編譯與打包apk文件的功能。本小節使用到的實例程序爲crackme0502.apk,按照前面使用Apktool的步驟,在命令提示符下輸入「apktool d crackme0502.apk」便可反編譯成功。固然,也能夠借鑑一些一鍵反編譯工具。性能優化

2.2 程序的主Activity

咱們知道,一個Android程序由一個或多個Activity以及其它組件組成,每一個Activity都是相同級別的,不一樣的Activity實現不一樣的功能。每一個Activity都是Android程序的一個顯示「頁面」,主要負責數據的處理及展現工做,在Android程序的開發過程當中,程序員不少時候是在編寫用戶與Activity之間的交互代碼。bash

每一個Android程序有且只有一個主Activity(隱藏程序除外,它沒有主Activity),它是程序啓動的第一個Activity。例如,打開crackme0502文件夾下的AndroidManifest.xml文件,其中有以下片段的代碼。數據結構

<activity android:label="@string/title_activity_main" android:name=". MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
複製代碼

在程序中使用到的Activity都須要在AndroidManifest.xml文件中手動聲明,聲明Activity使用activity標籤,其中android:label指定Activity的標題,android:name指定具體的Activity類,「.MainActivity」前面省略了程序的包名,完整類名應該爲com.droider.crackme0502. MainActivity,intent-filter指定了Activity的啓動意圖,android.intent.action.MAIN表示這個Activity是程序的主Activity。 android.intent.category.LAUNCHER表示這個Activity能夠經過LAUNCHER來啓動。若是AndroidMenifest.xml中,全部的Activity都沒有添加android.intent.category.LAUNCHER,那麼該程序安裝到Android設備上後,在程序列表中是不可見的,一樣的,若是沒有指定android.intent.action.MAIN,Android系統的LAUNCHER就沒法匹配程序的主Activity,所以該程序也不會有圖標出現。app

在反編譯出的AndroidManifest.xml中找到主Activity後,能夠直接去查看其所在類的OnCreate()方法的反彙編代碼,對於大多數軟件來講,這裏就是程序的代碼入口處,全部的功能都從這裏開始獲得執行,咱們能夠沿着這裏一直向下查看,追蹤軟件的執行流程。框架

2.3 重點關注的Application類

若是須要在程序的組件之間傳遞全局變量,或者在Activity啓動以前作一些初始化工做,就能夠考慮使用Application類了。使用Application時須要在程序中添加一個類繼承自android.app.Application,而後重寫它的OnCreate()方法,在該方法中初始化的全局變量能夠在Android其它組件中訪問,固然前提條件是這些變量具備public屬性。最後還須要在AndroidManifest.xml文件的Application標籤中添加「android:name」屬性,取值爲繼承自android.app.Application的類名。編輯器

鑑於Application類比程序中其它的類啓動得都要早,一些商業軟件將受權驗證的代碼都轉移到了該類中。例如,在OnCreate()方法中檢測軟件的購買狀態,若是狀態異常則拒絕程序繼續運行。所以,在分析Android程序過程當中,咱們須要先查看該程序是否具備Application類,若是有,就要看看它的OnCreate()方法中是否作了一些影響到逆向分析的初始化工做。

2.4 定位關鍵代碼的經常使用方法

若是盲目的對一個Android程序進行分析,可能須要閱讀成千上萬行的反彙編代碼才能找到程序的關鍵點,這無疑是浪費時間的表現。

信息反饋法

所謂信息反饋法,是指先運行目標程序,而後根據程序運行時給出的反饋信息做爲突破口尋找關鍵代碼。在第2章中,咱們運行目標程序並輸入錯誤的註冊碼時,會彈出提示「無效用戶名或註冊碼」,這就是程序反饋給咱們的信息。一般狀況下,程序中用到的字符串會存儲在String.xml文件或者硬編碼到程序代碼中,若是是前者的話,字符串在程序中會以id的形式訪問,只需在反彙編代碼中搜索字符串的id值便可找到調用代碼處;若是是後者的話,在反彙編代碼中直接搜索字符串便可。

特徵函數法

這種定位代碼的方法與信息反饋法相似。在信息反饋法中,不管程序給出什麼樣的反饋信息,終究是須要調用Android SDK中提供的相關API函數來完成的。好比彈出註冊碼錯誤的提示信息就須要調用Toast.MakeText().Show()方法,在反彙編代碼中直接搜索Toast應該很快就能定位到調用代碼,若是Toast在程序中有多處的話,可能須要分析人員逐個甄別。

順序查見解

順序查見解是指從軟件的啓動代碼開始,逐行的向下分析,掌握軟件的執行流程,這種分析方法在病毒分析時常常用到。

代碼注入法

代碼注入法屬於動態調試方法,它的原理是手動修改apk文件的反彙編代碼,加入Log輸出,配合LogCat查看程序執行到特定點時的狀態數據。這種方法在解密程序數據時常用,詳細的內容會在本書的第8章介紹。

棧跟蹤法

棧跟蹤法屬於動態調試方法,它的原理是輸出運行時的棧跟蹤信息,而後查看棧上的函數調用序列來理解方法的執行流程,這種方法的詳細內容會在本書的第8章介紹。

Method Profiling

Method Profiling(方法剖析)屬於動態調試方法,它主要用於熱點分析和性能優化。該功能除了能夠記錄每一個函數佔用的CPU時間外,還可以跟蹤全部的函數調用關係,並提供比棧跟蹤法更詳細的函數調用序列報告,這種方法在實踐中可幫助分析人員節省不少時間,也被普遍使用,

3,閱讀smali文件

3.1 smali文件格式

使用Apktool反編譯apk文件後,會在反編譯工程目錄下生成一個smali文件夾,裏面存放着全部反編譯出的smali文件,這些文件會根據程序包的層次結構生成相應的目錄,程序中全部的類都會在相應的目錄下生成獨立的smali文件。如上一節中程序的主Activity名爲com.droider.crackme0502. MainActivity,就會在smali目錄下依次生成com\droider\ crackme0502目錄結構,而後在這個目錄下生成MainActivity.smali文件。

smali文件的代碼一般狀況下比較長,並且指令繁多,在閱讀時很難用肉眼捕捉到重點,若是有閱讀工具可以將特殊指令(例如條件跳轉指令)高亮顯示,勢必會讓分析工做事半功倍,爲此筆者專門爲文本編輯器Notepad++編寫了smali語法文件來支持高亮顯示與代碼摺疊,並以此做爲smali代碼的閱讀工具。

不管是普通類、抽象類、接口類或者內部類,在反編譯出的代碼中,它們都以單獨的smali文件來存放。每一個smali文件都由若干條語句組成,全部的語句都遵循着一套語法規範。在smali文件的頭3行描述了當前類的一些信息,格式以下。

.class <訪問權限> [修飾關鍵字] <類名>
.super <父類名>
.source <源文件名>
打開MainActivity.smali文件,頭3行代碼以下。
.class public Lcom/droider/crackme0502/MainActivity;
.super Landroid/app/Activity;
.source "MainActivity.java"
複製代碼

第1行「.class」指令指定了當前類的類名。在本例中,類的訪問權限爲public,類名爲「Lcom/droider/crackme0502/MainActivity;」,類名開頭的L是遵循Dalvik字節碼的相關約定,表示後面跟隨的字符串爲一個類。

第2行的「.super」指令指定了當前類的父類。本例中的「Lcom/droider/crackme0502/ MainActivity;」的父類爲「Landroid/app/Activity;」。

第3行的「.source」指令指定了當前類的源文件名。

前3行代碼事後就是類的主體部分了,一個類能夠由多個字段或方法組成。smali文件中字段的聲明使用「.field」指令。字段有靜態字段與實例字段兩種。靜態字段的聲明格式以下。

# static fields
.field <訪問權限> static [修飾關鍵字] <字段名>:<字段類型>
複製代碼

baksmali在生成smali文件時,會在靜態字段聲明的起始處添加「static fields」註釋,smali文件中的註釋與Dalvik語法同樣,也是以井號「#」開頭。「.field」指令後面跟着的是訪問權限,能夠是public、private、protected之一。修飾關鍵字描述了字段的其它屬性,如synthetic。指令的最後是字段名與字段類型,使用冒號「:」分隔,語法上與Dalvik也是同樣的。

實例字段的聲明與靜態字段相似,只是少了static關鍵字,它的格式以下。

# instance fields
.field <訪問權限> [修飾關鍵字] <字段名>:<字段類型>
複製代碼

好比如下的實例字段聲明。

# instance fields
.field private btnAnno:Landroid/widget/Button;
複製代碼

第1行的「instance fields」是baksmali生成的註釋,第2行表示一個私有字段btnAnno,它的類型爲「Landroid/widget/Button;」。

若是一個類中含有方法,那麼類中必然會有相關方法的反彙編代碼,smali文件中方法的聲明使用「.method」指令。方法有直接方法與虛方法兩種。直接方法的聲明格式以下。

# direct methods
.method <訪問權限> [修飾關鍵字] <方法原型>
    <.locals>
    [.parameter]
    [.prologue]
    [.line]
<代碼體>
.end method
複製代碼

「direct methods」是baksmali添加的註釋,訪問權限和修飾關鍵字與字段的描述相同,方法原型描述了方法的名稱、參數與返回值。「.locals」指定了使用的局部變量的個數。「.parameter」指定了方法的參數,與Dalvik語法中使用「.parameters」指定參數個數不一樣,每一個「.parameter」指令代表使用一個參數,好比方法中有使用到3個參數,那麼就會出現3條「.parameter」指令。「.prologue」指定了代碼的開始處,混淆過的代碼可能去掉了該指令。「.line」指定了該處指令在源代碼中的行號,一樣的,混淆過的代碼可能去除了行號信息。

虛方法的聲明與直接方法相同,只是起始處的註釋爲「virtual methods」。

若是一個類實現了接口,會在smali文件中使用「.implements」指令指出。相應的格式聲明以下。

# interfaces
.implements <接口名>
複製代碼

「# interfaces」是baksmali添加的接口註釋,「.implements」是接口關鍵字,後面的接口名是DexClassDef結構中interfacesOff字段指定的內容。

若是一個類使用了註解,會在smali文件中使用「.annotation」指令指出。註解的格式聲明以下。

# annotations
.annotation [註解屬性] <註解類名>
    [註解字段 = 值]
.end annotation
複製代碼

註解的做用範圍能夠是類、方法或字段。若是註解的做用範圍是類,「.annotation」指令會直接定義在smali文件中,若是是方法或字段,「.annotation」指令則會包含在方法或字段定義中。例以下面的代碼。

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

實例字段sayWhat爲String類型,它使用了com.droider.anno.MyAnnoField註解,註解字段info值爲「Hello my friend」。將其轉換爲Java代碼以下所示:

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

4,使用IDA Pro靜態分析Android程序

IDA Pro是目前很棒的靜態反編譯軟件,是反編譯者不可缺乏的利器、巨酷的反編譯軟件,它能夠更好的反彙編和更有深層分析.能夠快速到達指定代碼位置。

IDA Pro從6.1版本開始,提供了對Android的靜態分析與動態調試支持。包括Dalvik指令集的反彙編、原生庫(ARM/Thumb代碼)的反彙編、原生庫(ARM/Thumb代碼)的動態調試等。具體可查看IDA Pro官方的更新日誌,連接以下:www.hex-rays.com/ products/ ida/6.1/index.shtml。

4.1 簡單使用

以5.2節的crackme0502.apk爲例,首先解壓出classes.dex文件,而後打開IDA Pro,將classes.dex拖放到IDA Pro的主窗口,會彈出加載新文件對話框,如圖5-4所示,IDA Pro解析出了該文件屬於「Android DEX File」,保持默認的選項,點擊OK按鈕,稍等片刻IDA Pro就會分析完dex文件。

在這裏插入圖片描述
IDA Pro支持結構化形式顯示數據結構,所以,咱們有必要先整理一下反彙編後的數據。dex文件的數據結構大部分在Android系統源碼中dalvik\libdex\DexFile.h文件中,筆者將其中的結構整理爲dex.idc腳本,在分析dex文件時直接導入便可使用。導入的方法爲點擊IDA Pro的菜單項「File→Script file」,而後選擇dex.idc便可。點擊IDA Pro主界面的Structures選項卡,如圖5-5所示。
在這裏插入圖片描述
點擊IDA View-A選項卡,回到反彙編代碼界面,而後點擊菜單項「Jump→Jump to address」,或者按下快捷鍵G,彈出地址跳轉對話框,輸入0讓IDA Pro跳轉到dex文件開頭。將鼠標定位到註釋「# Segment type: Pure data」所在的行,而後點擊菜單項「Edit→Structs→ Struct var」,或者按下快捷鍵ALT+Q,彈出選擇結構類型對話框,如圖5-6所示,選擇DexHeader後點擊OK按鈕返回。

此時,dex文件開頭的0x70個字節就會格式化顯示,效果如圖5-7所示。一樣,讀者能夠手動對dex文件中其它的結構進行整理,如DexHeader下面的DexStringId結構。

在這裏插入圖片描述
在這裏插入圖片描述
點擊菜單項「Jump→Jump to segment」,或者按下快捷鍵CTRL+S,彈出段選擇對話框,如圖5-8所示,IDA Pro將dex文件一共分紅了9個段,其中前7個段由DexHeader結構給出,最後2個段能夠經過計算得出。仔細查看段名,能夠發現IDA Pro對其命名不是很好,有3個HEADER段與2個CODE段,筆者以爲第3個段更名爲PROTOS更合適一些,還有第6個段更名爲CLASSDEFS更好,IDA Pro爲何這樣命名咱們不得而知,不過,咱們須要知道每一個段具體所表明的含義。
在這裏插入圖片描述
dex文件中全部方法能夠點擊Exports選項卡查看。方法的命名規則爲「類名.方法名@方法聲明」。在Exports選項卡中隨便選擇一項,如SimpleCursorAdapter.swapCursor@LL,而後雙擊跳轉到相應的反彙編代碼處,該處的代碼以下。

CODE:0002CFCC     Method 2589 (0xa1d):
CODE:0002CFCC    public android.database.Cursor
CODE:0002CFCC        android.support.v4.widget.SimpleCursorAdapter.swapCursor(
CODE:0002CFCC        android.database.Cursor p0)        #方法聲明
CODE:0002CFCC         this = v2    #this引用
CODE:0002CFCC         p0 = v3        #第一個參數
CODE:0002CFCC        invoke-super     {this, p0}, <ref ResourceCursorAdapter.
                        swapCursor(ref) imp. @ _def_ResourceCursorAdapter_
                        swapCursor@LL>
CODE:0002CFD2        move-result-object              v0
CODE:0002CFD4        iget-object  v1, this, SimpleCursorAdapter_mOriginalFrom
CODE:0002CFD8        invoke-direct    {this, v1}, <void SimpleCursorAdapter.
                    findColumns(ref) SimpleCursorAdapter_findColumns@VL>
CODE:0002CFDE
CODE:0002CFDE     locret:
CODE:0002CFDE        return-object                   v0
CODE:0002CFDE        Method End
複製代碼

IDA Pro的反彙編代碼使用ref關鍵字來表示非Java標準類型的引用,如方法第1行的invoke-super指令的前半部分以下。

invoke-super     {this, p0}, <ref ResourceCursorAdapter.swapCursor(ref)
複製代碼

前面的ref是swapCursor()方法的返回類型,後面括號中的ref是參數類型。

後半部分的代碼是IDA Pro智能識別的。IDA Pro能智能識別Android SDK的API函數並使用imp關鍵字標識出來,如第1行的invoke-super指令的後半部分以下。

imp. @ _def_ResourceCursorAdapter_swapCursor@LL
複製代碼

imp代表該方法爲Android SDK中的API,@後面的部分爲API的聲明,類名與方法名之間使用下劃線分隔。

IDA Pro能識別隱式傳遞過來的this引用,在smali語法中,使用p0寄存器傳遞this指針,此處因爲this取代了p0,因此後面的寄存器命名都依次減了1。

IDA Pro能識別代碼中的循環、switch分支與Try/Catch結構,並能將它們以相似高級語言的結構形式顯示出來,這在分析大型程序時對了解代碼結構有很大的幫助。具體的代碼反彙編效果讀者能夠打開5.2節使用到的SwitchCase.apk與TryCatch.apk的classes.dex文件自行查看。

4.2 使用IDA Pro進行破解的實例

使用IDA Pro定位關鍵代碼的方法總體上與定位smali關鍵代碼差很少。

第一種方法是搜索特徵字符串。首先按下快捷鍵CTRL+S打開段選擇對話框,雙擊STRINGS段跳轉到字符串段,而後點擊菜單項「Search→text」,或者按下快捷鍵ALT+T,打開文本搜索對話框,在String旁邊的文本框中輸入要搜索的字符串後點擊OK按鈕,稍等片刻就會定位到搜索結果。不過目前IDA Pro對中文字符串的顯示與搜索都不支持,若是字符串中的中文字符顯示爲亂碼,須要編寫相關的字符串處理插件來解決,這個工做就交給讀者去完成了。

第二種方法是搜索關鍵API。首先按下快捷鍵CTRL+S打開段選擇對話框,雙擊第一個CODE段跳轉到數據起始段,而後點擊菜單項「Search→text」,或者按下快捷鍵ALT+T,打開文本搜索對話框,在String旁邊的文本框中輸入要搜索的API名稱後點擊OK按鈕,稍等片刻就會定位到搜索結果。若是API被調用屢次,能夠按下快捷鍵CTRL+T來搜索下一項。

第三種方法是經過方法名來判斷方法的功能。這種辦法比較笨拙,對於混淆過的代碼,定位關鍵代碼比較困難。好比,咱們知道crackme0502.apk程序的主Activity類爲MainActivity,因而在Exports選項卡頁面上輸入Main,代碼會自動定位到以Main開頭的所在行,如圖5-9所示,可粗略判斷出每一個方法的做用。

在這裏插入圖片描述
下面咱們來嘗試破解一下crackme0502.apk。首先安裝運行apk程序,程序運行後有兩個按鈕,點擊「獲取註解」按鈕會Toast彈出3條信息。在文本框中輸入任何字符串後,點擊「檢測註冊碼」按鈕,程序彈出註冊碼錯誤的提示信息。這裏咱們以按鈕事件響應爲突破口來查找關鍵代碼,經過圖5-9咱們能夠發現有兩個名爲OnClick()的方法,那具體是哪個呢?咱們分別進去看看。前者調用了MainActivity.access$0()方法,在IDA Pro的反彙編界面雙擊MainActivity_access能夠看到它其實調用了MainActivity的getAnnotations()方法,看到這裏應該能夠明白,MainActivity$1.onClick()方法是前面按鈕的事件響應代碼。接下來查看MainActivity$2.onClick()方法,雙擊代碼行,來到相應的反彙編代碼處,按下空格鍵切換到IDA Pro的流程視圖,如圖5-10所示,代碼的「分水嶺」就是「if-eqz v2, loc_2D0DC」。圖中左邊紅色箭頭表示條件不知足時執行的路線,右邊的綠色箭頭是條件知足時執行的路線。
在這裏插入圖片描述
雖然不知道這堆亂碼字符串分別是什麼,但經過最後調用的Toast來看,直接修改if-eqz便可將程序破解。將鼠標定位到指令「if-eqz v2, loc_2D0DC」所在行,而後點擊IDA Pro主界面的「Hex View-A」選項卡,可看到這條指令所在的文件偏移爲0x2D0BE,相應的字節碼爲「38 02 0f 00」,經過前面的學習,咱們知道只需將if-eqz的OpCode值38改爲if-nez的OpCode值39便可。說幹說幹,使用C32asm打開classes.dex文件,將0x2D0BE的38改成39,而後保存退出。接着按照本書4.6小節的介紹,將dex文件進行Hash修復後導入apk文件,對apk從新簽名後安裝測試發現程序已經破解成功了。

爲了讓讀者看到一種常見的Android程序的保護手段,這裏更換一下破解思路。經過圖5-10可發現,MainActivity$SNChecker.isRegistered()方法實際上返回一個Boolean值,經過判斷它的返回值來肯定註冊碼是否正確。如今的問題是,若是該程序是一個大型的Android軟件,並且調用註冊碼判斷的地方可能不止一處,這種狀況時,一般有兩種解決方法:第一種是使用IDA Pro的交叉引用功能查找到全部方法被調用的地方,而後修改全部的判斷結果;第二種方法是直接給isRegistered()方法「動手術」,讓它的結果永遠返回爲真。很顯然,第二種方法解決問題更利落,並且一勞永逸。

下面嘗試使用這種方法進行破解,首先按下空格鍵切換到反彙編視圖,發現直接修改方法的第二條指令爲「return v9 」便可完成破解,對應機器碼爲「0F 09」,將其修改完成後從新修復與簽名,安裝測試發現程序啓動後就當即退出了。這時最早懷疑的是程序是否修改正確,使用IDA Pro從新導入修改過的classes.dex文件,發現修改的地方沒錯,看來是程序採起了某種保護措施!回想一下前面提到的兩種程序退出方法: Context的finish()方法與android.os.Process的killProcess()方法,按下快捷鍵CTRL+S並雙擊CODE回到代碼段,接着按下快捷鍵ALT+T搜索finish與killProcess,最後在MyApp類的onCreate()方法中找到了相應的調用,查看相應的反彙編代碼,發現這段代碼使用Java的反射機制,手工調用isRegistered()方法檢查字符串「11111」是否爲合法註冊碼,若是是或者調用isRegistered()失敗都說明程序被修改過,從而調用killProcess()來殺死進程。明白了保護手段,解決方法就簡單多了,直接將兩處killProcess()的調用直接nop掉(修改相應地方的指令爲0)就能夠了。

5,分析工具包Androguard

對於Android惡意軟件分析人員來講,提起Androguard應該不會感到陌生,Androguard提供了一組工具包來輔助分析人員快速鑑別與分析APK文件。

6,閱讀反編譯的Java代碼

在分析大型軟件時,爲了弄清程序的結構框架,須要花費掉大量的時間與精力來閱讀smali代碼,這無疑是分析成本的一大開銷。然而,Android程序大多數狀況下是採用Java語言開發的,傳統意義上的Java反彙編工具依然可以派上用場。

6.1 使用dex2jar生成jar文件

dex2jar的官網是https://sourceforge.net/projects/dex2jar/,目前最新版本爲020.0,將下載下來的dex2jar壓縮包解壓,而後將解壓後的文件夾添加到系統的PATH環境變量中,在命令提示符下輸入如下命令:

d2j-dex2jar xxx.apk
複製代碼

稍等片刻就會在同目錄下生成一個jar文件。dex2jar是一個工具包,除了提供dex文件轉換成jar文件外,還提供了一些其它的功能,每一個功能使用一個bat批處理或sh腳原本包裝,只需在Windows系統中調用bat文件、在Linux系統中調用sh腳本便可。

d2j-apk-sign用來爲apk文件簽名。命令格式:d2j-apk-sign xxx.apk。
d2j-asm-verify用來驗證jar文件。命令格式:d2j-asm-verify -d xxx.jar。
d2j-dex2jar用來將dex文件轉換成jar文件。命令格式:d2j-dex2jar xxx.apk
d2j-dex-asmifier用來驗證dex文件。命令格式:d2j-dex-asmifier xxx.dex。
d2j-dex-dump用來轉存dex文件的信息。命令格式:d2j-dex-dump xxx.apk out.jar。
d2j-init-deobf用來生成反混淆jar文件時的初始化配置文件。
d2j-jar2dex用來將jar文件轉換成dex文件。命令格式:d2j-jar2dex xxx.apk。
d2j-jar2jasmin用來將jar文件轉換成jasmin格式的文件。命令格式:d2j-jar2jasmin xxx.jar
d2j-jar-access用來修改jar文件中的類、方法以及字段的訪問權限。
d2j-jar-remap用來重命名jar文件中的包、類、方法以及字段的名稱。
d2j-jasmin2jar用來將jasmin格式的文件轉換成jar文件。命令格式:d2j-jasmin2jar dir
dex2jar爲d2j-dex2jar的副本。
dex-dump爲d2j-dex-dump的副本。
複製代碼

6.2 使用jd-gui查看jar文件的源碼

爲了達到源碼級的反編譯效果,可使用Java反編譯工具JAD將jar文件轉換成Java源文件,目前JAD官網已經沒法訪問,能夠經過http://www.varaneckas.com/jad/下載到JAD的可執行文件。

在這裏,筆者推薦使用jd-gui。jd-gui是一款用 C++ 開發的 Java 反編譯工具,支持Windows、Linux和蘋果Mac OS三個平臺。jd-gui是免費的,並且反編譯效果不錯,該工具省掉了將jar文件轉換成Java源文件的步驟,直接以源碼的形式顯示jar文件中的內容,能夠從官方免費獲取。

除了反編譯功能外,jd-gui還帶有強大的搜索功能,在主界面按下快捷鍵CTRL+F,會在程序的狀態欄顯示一個搜索工具條,輸入要搜索的內容,當前打開的反編譯窗口會高亮顯示搜索結果。除此以外,點擊菜單項「Search→Search」會彈出搜索對話框,搜索框列舉出了isRegistered()方法在哪些文件中被引用過。

在這裏插入圖片描述
相關文章
相關標籤/搜索