Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android逆向之旅---反編譯利器Apktool和Jadx源碼分析以及錯誤糾正

Android逆向之旅---反編譯利器Apktool和Jadx源碼分析以及錯誤糾正

編輯:關於Android編程

一、前言

在之前的破解過程中可以看到我們唯一離不開的一個神器那就是apktool了,這個工具多強大就不多說了,但是如果沒有他我們沒法涉及到後面的破解工作了,這個工具是開源的,也是使用Java語言開發的,代碼相對簡單,我們今天就來分析一下他的大體邏輯,注意是大體邏輯哦,因為如果要一行一行代碼分析,首先覺得沒必要,其次浪費時間,有了源碼,誰看不懂呢。至於為什麼要分析這個工具其實原因只有一個,就是我們在之前的反編譯過程中會發現,總是有那麼幾個apk應用不讓我們那麼容易的反編譯,他們就利用apktool的漏洞,對apk做了一定的混淆工作,所以我們需要通過分析源碼來解決這些異常錯誤,從而能夠對每個apk反編譯都是如魚得水。

 

二、破解的國際慣例

其實在之前的破解文章中,我們在拿到一個apk進行破解之前,都會干這兩件事:

第一件事:用壓縮軟件解壓apk,得到classes.dex,然後使用dex2jar+jd-gui工具查看代碼邏輯

但是這裡我們會發現如果想看資源文件比如AndroidManifest.xml和res下面的一下xml文件都是亂碼的,因為他們是遵循Android中的arsc文件格式,關於這個格式不了解的同學可以網上搜一下,但是關於這個文件格式我在之前的幾篇文章中做了格式解析:

Android中如何解析資源文件樣式其實不管是什麼文件格式,都是有文件格式的說明文檔的,只要按照這個說明文章去做解析即可

第二件事:使用apktool工具進行反編譯apk,得到smali源碼和資源文件

這裡得到的是smali源碼,破解了這麼長時間,smali語法就不做太多的介紹了,他就是Android虛擬機識別執行的指令代碼,他和dex文件可以互相轉化的,使用baksmali.jar和smali.jar這兩個工具即可,後面會詳細說到,當然這裡還可以得到所有的資源文件,即arsc格式解析之後的內容,而且這個工具可以實現回編譯,這個功能也是很強大的,不過後面分析源碼就知道了,回編譯其實是借助aapt這個強大的系統命令來完成的。

所以這裡我們可以看到最終如果我們想要完全的分析一個apk,apktool工具是不可或缺的,他是開啟破解大門的鑰匙,這個工具也是在逆向領域敲門磚,而且現在很多比較可視化的破解工具,比如:apk改之理,jeb,gda等,其實這些工具核心都是使用apktool+dex2jar+jd-gui這三個工作組成的,只是後期做了一定的界面優化而已。

 

三、Apktool工具反編譯常見的問題

上面說了apktool工具的地位和作用,下面我們再來看一下apktool工具在反編譯的過程中會遇到哪些問題呢?

這裡我們只看BAT這三家公司的app,我們在反編譯的過程中發現了QQ和支付寶分別報了這兩個錯誤:

1、QQ報了這個錯誤:

Exception in thread "main" brut.androlib.AndrolibException: Multiple res specs: attr/name

這個主要是因為QQ利用了apktool的一個漏洞,做了屬性id的混淆

\

2、支付寶報了這個錯誤:

Exception in thread "main" brut.androlib.AndrolibException: Could not decode arsc file

這個錯誤其實是在使用apktool工具的時候報的錯誤最多的,這個主要是利用apktool的漏洞,修改了resource.arsc的頭部信息

\

其實網上很多解決方案都是說apktool這個工具的版本太舊了,用最新版本,但是這裡可以看一下apktool.jar的版本:

\

這個版本是最新的了。

其實反編譯失敗很簡單,就是這些公司他們知道了apktool這個工具反編譯那麼牛逼,那肯定想辦法不讓你反編譯成功呀,所以他們也去看apktool的源碼,分析得到漏洞,然後進行apk的一些混淆,防止反編譯,所以說防護和破解真的是無休止的戰爭,但是幸好apktool的代碼也是更新的比較快的,所以會解決這些漏洞,但是我們在破解的時候遇到這些問題,不能一味的等待apktool的更新,既然是開源的,那麼就直接分析源碼,發現報錯的地方修復即可。

 

四、分析Apktool源碼

上面說了為什麼要分析apktool的源碼,下面就真正的開始分析吧

當然第一步先得到apktool的源碼吧,地址:https://code.google.com/p/android-apktool/

看到有google的域名是不是瞬間感覺整個人都不好了,的確國內程序猿一般打開都是始終loading的過程,直至error,所以我們只能去萬能的github上search了,找到了這個地址:https://github.com/iBotPeaches/Apktool,可以看到這個有很多人關注,而且代碼是有人維護和更新的,所以靠譜,clone到本地。

但是他是一個gradle項目,所以咋們就給Eclipse裝一個gradle插件,然後導入項目即可,這裡因為apktool是Java項目,所以還是使用Eclipse比較習慣吧。但是這裡又遇到一個蛋疼的地方,還是國內網絡的問題,gradle下載失敗,因為這裡引用了一些第三方的jar

\

好吧,那麼我們只能無奈的手動去一個一個找這些jar包,不過在這個過程中還是比較蛋疼的,就是有些jar找的很蛋疼,不過最後還是都湊齊了,沒有報錯了,項目結構如下:

\

這裡Apktools這個項目是入口的項目,也是主要功能項目類,Baksmali和Smali,SmaliUtil是操作smali的工具類,BrutCommon和BrutDir,BrutUtil是一些輔助的工具類,代碼簡單,不做太多的解釋,這裡除了Apktool之外,其他工程都是一個功能庫,他們直接的引用關系如下:

Baksmali依賴於:SmaliUtil
BrutDir依賴於:BrutCommon,BrutUtil
BrutUtil依賴於:BrutCommon
Smali依賴於:SmaliUtil
Apktool依賴於:Baksmali,BrutCommon,BrutDir,BrutUtil,Smali

這裡直接來看看主要功能Apktools項目

 

第一、分析Apktool的反編譯源碼

首先我們知道,Java項目的入口方法肯定是main方法,搜一下找到這個Main類:

\

這個方法中得到參數,然後進行參數的分析和組裝。繼續往下看,看執行代碼:

\

這裡看到了我們經常用的一些命令參數,他們的含義這裡也都可以了解到了,有一個ApkDecoder類,是反編譯的核心類:

\

最終也是調用他的decode方法:

\

這裡看到使用了Androlib這個核心類來做了一些操作,首先會判斷需不需要解析資源文件,即arsc格式的,這裡又細分了解析resource.arsc和AndroidManifest.xml這兩個文件的解析,下面繼續看:

\

這裡會解析dex文件,得到smali源碼,而且區分了多個dex的情況。

 

其實到這裡我們可以發現,apktool在反編譯的整個過程中核心點就三個:

解析resource.arsc文件,AndroidManifest.xml文件,dex文件

那麼關於這三個文件的格式解析,一定請看這篇文章:Android中解析所有文件格式

如果看了這篇文章之後,會發現Android中的這三個文件都有各自的格式,解析也是很簡單的。所以這裡就不在詳細介紹了具體的解析步驟了,但是這三個文件分別對應的三個經典格式圖必須展示一下:

AndroidManifest.xml文件格式圖

\

 

Resource.arsc文件格式圖

\

Dex文件個格式圖

\

這三張圖可算是經典中的經典,而且一定要看懂,因為不看懂這三張圖的話,自己在分析apktool解析源碼的時候會非常的費勁。

 

下面繼續分析,Androidlib這個核心解析類其實就那麼幾個方法,下面來一一講解:

1、decodeRawFiles

這個方法主要解析原生的文件,就是Android在編譯apk的過程中不參與編譯的文件目錄,一般是assets和libs

\

 

2、decodeManifestWithResources

這個方法主要是解析AndroidManifest.xml的

\

我們知道Android在安裝一個apk的時候,肯定也是需要解析AndroidManifest.xml文件的,而且Android中解析xml文件采用的是Pull解析法,所以這裡直接把Android中的一些方法copy過來了。

\

然後在弄一個xmlPull的解析jar包即可:

\

 

3、decodeResourcesFull

這個方法用來解析resource.arsc文件的,這個文件我們知道他主要包含了所有資源文件的一種格式,Android中資源文件都有相應的類型,以及唯一的一個整型id值,那麼這個文件就包含這些內容

\

這個方法其實用到的解析類和AndroidManifest.xml的解析類是一樣的,因為他們都屬於arsc格式,而且資源文件也是xml格式的,這裡值得注意的是,會產生一個反編譯中最關鍵的一個文件:public.xml,這個文件是在反編譯之後的res\values\public.xml

\

這裡可以看到,一個id字段,都有對應的類型,名稱,和id值的

而這裡的id值是一個整型值,8個字節;由三部分組成的:

PackageId+TypeId+EntryId
PackageId:是包的Id值,Android中如果是第三方應用的話,這個值默認就是0x7F,系統應用的話就是0x01,具體我們可以後面看aapt源碼得知,他占用兩個字節。
TypeId:是資源的類型Id值,一般Android中有這幾個類型:attr,drawable,layout,dimen,string,style等,而且這些類型的值是從1開始逐漸遞增的,而且順序不能改變,attr=0x01,drawable=0x02....他占用兩個字節。
EntryId:是在具體的類型下資源實體的id值,從0開始,依次遞增,他占用四個字節。

 

4、decodeSourcesSmali

這個方法主要是將dex文件解析成smali源碼

\

這裡使用了SmaliDecoder的decode方法:

\

這裡需要借助一個工具包dexlib,他是用來處理dex文件的,處理完dex文件之後,在交給baksmali這個工具類生成smali文件即可。

 

到這裡我們可以看到上面就大致分析完了apktool在反編譯的時候做的主要三件事:

解析resource.arsc,解析AndroidManifest.xml,解析dex文件

源碼分析完了,下面就開始測試運行一下,這裡用使用了BAT三家的主要app做實驗:

\

這裡為了運行簡單,我們在入口的main方法中,去手動構造一個參數:

\

這裡用了BAT三家的幾個app測試,發現,只有qq和支付寶有問題,所以這裡就直接看著兩個app反編譯會出現什麼錯誤,然後來分析解決這個問題:

1、分析QQ應用反編譯的問題

\

這裡報錯了,錯誤和我們開始使用apktool工具的時候是一樣的,看看崩潰代碼:

\

這裡可以發現,使用一個Map結構存放ResResSpec格式數據的,而且key是spec的name值,那麼我們知道資源id的值是唯一的,這裡不可能會出現相同的name值的,是騰訊做了混淆機制,這種混淆機制只對apktool工具有效,對Android系統解析apk運行是不影響的,那麼問題就好辦了,我們知道了崩潰的原因,修復也就簡單了,直接加一個判斷,判斷這個key是否存在map中,存在的話就直接返回即可:

\

再次運行:

\

看到了,過濾了重復的資源值,反編譯成功了,這裡因為反編譯過程中會用到系統的資源id,需要需要系統資源包framework.apk參與解析工作,這裡因為QQ程序包比較大,反編譯時間會長點。我們可以去看看反編譯之後的目錄:

\

我們可以看看他的AndroidManifest.xml內容:

\

解析成功,可以正常查看了。

這裡我們就解決了QQ反編譯的問題了,

 

2、分析支付寶應用反編譯的錯誤問題

\

看到了,這個錯誤和我們開始看到的錯誤是一樣的,下面我們看看崩潰的地方是什麼原因導致的:

\

這裡是讀取一個字符串常量池Chunk頭部信息報錯的,關於Chunk的頭部信息可以參考這篇文章:Android中解析resource.arsc文件

StringChunk的頭部信息包括這些內容:

header:標准的Chunk頭部信息結構
stringCount:字符串的個數
styleCount:字符串樣式的個數
flags:字符串的屬性,可取值包括0x000(UTF-16),0x001(字符串經過排序)、0X100(UTF-8)和他們的組合值
stringStart:字符串內容塊相對於其頭部的距離
stylesStart:字符串樣式塊相對於其頭部的距離

其中header是一個標准的Chunk頭部信息:

type:是當前這個chunk的類型(兩個字節)
headerSize:是當前這個chunk的頭部大小(兩個字節)
size:是當前這個chunk的大小(四個字節)

就是八個字節。

我們繼續分析錯誤代碼:

\

這裡會檢查已給Chunk結構的完整性,出入的StringPool值是:

\

看到了,這裡是字符串常量池Chunk的頭部信息,而且值是固定的:0x001C0001

在進入看看代碼:

\

這裡如果發現格式不正確就拋出一個異常,也就是格式不是0x001C0001的話。

那麼問題差不多清楚了,這裡崩潰的原因很可能是支付寶應用的resource.arsc的StringPool的Chunk的頭部信息被混淆了,導致這個錯誤的,我們通過上面的分析知道,StringPool這個Chunk的頭部標准格式是:0x001C0001,我們來看看支付寶應用的resource.arsc文件的二進制數據:

\

發現了,有這個值,那麼為何還報錯呢?到這裡我們或許不知道該怎麼辦了,其實很簡單,我們再去弄一個能夠反編譯的apk的resource.arsc文件看看:

\

擦,發現果然不一樣,支付寶頭部信息多了8個字節,0x000001000,那麼我們再看上面的檢查Chunk頭部類型數據的代碼:

\

其實,這裡可以看到,apktool其實已經做了一個頭部信息的檢查,但是這裡只是檢查0x001C0001這個正確信息之前的值只有四個字節,而且是0的情況,這裡讀取int整型值,四個字節,發現如果等於傳遞進來的possible的話即0,就繼續執行這個方法,但是這裡的possible值是-1了,也就是這裡只會檢查四個字節,但是我們分析了支付寶的resource.arsc文件,發現他是8個字節,而且還不全是0,是前四個字節是0,後四個字節是1:

\

所以這裡檢測也是失敗的,拋出異常了。

 

好了,到這裡我們就分析完了支付寶的資源文件混淆的機制了,下面我們修改就簡單了,首先。我們把上面的8個字節全部改成0:

\

然後替換之前的resource.arsc文件,直接用壓縮軟件替換即可,

然後在修改上面的檢測代碼:

\

這裡,修改代碼,就是會做一直檢測,直到遇到正確的值為止,我們修復完成之後,運行:

\

哈哈,不報錯了,看看反編譯之後的目錄:

\

反編譯也成功啦啦~~

 

我們通過上面的分析就知道了,現在使用apktool反編譯的主要兩個錯誤就是:

1、Exception in thread "main" brut.androlib.AndrolibException: Multiple res specs: attr/name

異常原因:通過分析源碼知道,這個錯誤主要是因為apk做了混淆操作,導致在反編譯的過程中存入了重復的id值,錯誤代碼:

ResTypeSpec.java的addResSpec方法78行

修復:在這個方法存入map數據之前做一個判斷操作即可

2、Exception in thread "main" brut.androlib.AndrolibException: Could not decode arsc file

異常原因:通過分析源碼知道,這個錯誤主要是因為apk了做了resource.arsc頭部信息的修改,導致在分析頭部數據結構的時候出錯,錯誤代碼:ExtDataInput.java的skipCheckChunkTypeInt方法 73行

修復:修復resource.arsc頭部數據,修改skipCheckChunkTypeInt檢測方法邏輯

 

第二、Apktool的回編譯源碼分析

到這裡我們就分析完了apktool的反編譯功能源碼,也解決了QQ和支付寶應用反編譯的失敗問題,下面再繼續分析一下apktool的回編譯功能,關於回編譯功能的話,這裡可以先看這篇文章:Android中編譯Apk的步驟分析這裡我們可以知道aapt命令的功能:

\

使用aapt命令編譯資源文件
aapt package -f -m -J gen -S res -I D:/android-sdk-windows/platforms/android-16/android.jar -M AndroidManifest.xml
這裡的命令參數有點多就不全部介紹了,就說明幾個:
-J 後面跟著是gen目錄,也就是編譯之後產生的R類,存放的資源Id
-S 後面跟著是res目錄,也就是需要編譯的資源目錄
-l 後面跟著是系統的庫,因為我們在項目資源中會用到系統的一些資源文件,所以這裡需要鏈接一下
-M 後面跟著是工程的清單文件,需要從這個文件中得到應用的包名,然後產生對應的R文件和包名。

而且,這個命令不僅可以進行編譯,可以反編譯,就是上面我們提到的解析AndroidManifest.xml和resource.arsc的時候,使用它可以做到的,解析dex文件可以使用dumpdex這個命令的。這些命令都是在androidsdk目錄的build-tools目錄下。

知道了這個編譯過程,其實回編譯就是按照這個步驟來的,而這裡重要的就是使用aapt命令:

\

這裡我們把命令放到了項目的framework目錄下:

\

然後開始構造命令參數,主要需要引用系統的jar包:android.jar

\

 

這裡就差不多分析完了回編譯的功能,我們修改一下入口代碼,添加回編譯運行參數:

\

運行程序:

\

回編譯成功,得到apk文件:

\

不過這個文件是沒有簽名的,需要簽名,這裡不繼續了,不是本文的講解的知識點了。

 

到這裡我們就分析完了apktool工具所有的源碼了,其實他的功能很簡單:

1、反編譯的過程中主要是解析AndroidManifest.xml,resource.arsc,dex文件

2、回編譯的時候借助aapt命令完成編譯操作

 

五、分析Jadx源碼

下面繼續來看反編譯的另外一個神器:Jadx

這個工具也是開源的,可以直接去github上去搜索:https://github.com/skylot/jadx

這個工具其實和apktool反編譯的功能差不多,但是有一個特色,就是他的可視化功能,能夠高效的分析apk的結構,下面來看一個例子:

\

看到了吧,這裡感覺結構很清晰,而且是可視化的,分析起來會比較方便,感覺他是集成了apktool+jd-gui的功能,但是他和apktool相比的話,還是有點缺陷的,首先他反編譯會比較耗時,這個後面說,其次是他不能修改代碼,進行回編譯的,這個是很蛋疼的,所以他和apktool相比較的話,還是差了點,但是他反編譯還是很靠譜的,這裡為什麼分析它呢?其實是因為他是開源的,其次是借助了asm這個工具來生成class文件,實現Java代碼的可視化。

下面就來說說asm這個工具類的用途:

這裡寫了一個demo來看看效果:

\

運行結果:

\

這裡沒有打印Hello world!的代碼,但是結果卻打印了,這個就是asm功能了:能夠手動的構造一個class文件

\

這個功能,大家是否聯想到了,動態代理模式,會產生一個動態代理類,而且還會生成一個Proxy.class文件,而且在JavaWeb中的Spring框架中的Cglib也是采用了這個功能來實現AOP編程的,他可以通過輸入一個字符串來定義類,給這個類添加方法,字段等信息,然後生成類的字節碼數組,可以保存成class文件,同時也可以使用ClassLoader來加載字節碼數據,然後在反射調用指定的方法。

那麼其實Jadx的可視化功能就是借助於這個功,同時著名的dex2jar工具也是的,可以去dex2jar工具的lib目錄看看:

\

 

那麼Jadx的反編譯步驟是這樣的:

解析dex文件=》smali源碼=》解析smali指令=》借助asm生成class文件=》解析class文件得到Java源碼

 

Apktool+Jadx源碼下載:http://pan.baidu.com/s/1cHU30M

 

六、總結

好了,到這裡我們就分析完了Apktool和jadx的源碼了,我們這裡主要還是分析了Apktool的源碼,因為我們在反編譯的過程中還是需要借助這個神器的,其實他內部沒什麼神秘的,就是解析三個文件,因為apktool是開源的,所以一些公司就會去找他的漏洞,然後通過這個漏洞來給自己的apk加固,增加反編譯的困難,但是我們也是可以分析apktool源碼的,知道了反編譯的錯誤信息,也是可以去分析錯誤,然後修復錯誤,最終還是可以反編譯成功的,所以這種資源加固來抵抗apktool的方案其實效率並沒有那麼高,因為只要有apktool源碼,都不是問題。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved