Android Studio Analyze APK 一直顯示 Parsing Manifest探因及解決

1、背景

你們都知道,Android Studio開發工具自帶了Analyze Apk,能夠很方便的分析Apk文件。具體位於菜單build >> Analyze APK...路徑下,點擊後能夠選擇目標路徑下的Apk文件,甚至能夠直接將目標APK文件直接拖拽到Android Studio中,不到幾秒中時間,立刻就會生成對應的分析結果。html

例如,微信Apk分析結果是這樣的:
java

又如,支付寶Apk分析結果: android

瞬間感受本身很niubility,有沒有?git

有時候,咱們也常常用它來分析本身的Apk,例如,生成的安裝包到底長什麼樣子,裏面的資源/代碼構成,Manifest中配置是否如預期,又或者方法數,等等。可是,一次忽然的機會,發現本身開發的Ap分析不了,一直處於Parsing Manifest狀態。es6

一臉懵逼,有木有? github

2、探因

這個問題曾經困惑了我很多時間,以前也沒有具體去研究過。如今又遇到了。瞬間想到魯迅說的一句話:安全

技術路上,會遇到不少看似莫名其妙的問題。
細心探究,解決了,就是成長。
無視它並避讓過去,看似繞過了問題,
實際上失去了一次很好的技術歷練的機會。
而且下次極可能還會遇到相似的,甚至同樣的問題,
長期看將是困難和停滯。
複製代碼

既然先輩都這樣說了,那,硬着頭皮解一下?bash

2.1 AS日誌

如今給人的感受是Analyze APK執行過程當中直接停住了,後者長時間一直在分析。但無論怎樣,畢竟是在AS中的操做,先查一下對應的AS日誌,看看有沒Parsing Manifest或相關的日誌信息,能夠起到幫助的。微信

Help >> Show Log in Finder,打開日誌,對應時間點看了又看,沒找到Parsing Manifest直接相關的,不過,找到了控件顯示先關的日誌:app

2019-08-08 19:21:25,323 [entQueue-0]   INFO - ools.idea.apk.viewer.ApkEditor - Disposing ApkEditor with ApkViewPanel: com.android.tools.idea.apk.viewer.ApkViewPanel@7a608115 
2019-08-08 19:21:25,323 [entQueue-0]   INFO - s.idea.apk.viewer.ApkViewPanel - Cleared Archive on ApkViewPanel: com.android.tools.idea.apk.viewer.ApkViewPanel@7a608115
複製代碼

從日誌裏面能夠看出來,AS中對應的Analyze Apk相關的類名有ApkEditorApkViewPanel,包名是com.android.tools.idea.apk.viewer。AS日誌部分的有效信息只有這麼多了。

2.2 系統全局搜索

AS日誌中沒有,那有沒有可能存在有效的信息輸出在了系統其它的地方?因而,直接花點時間,系統全局搜索下。

/ grep -rnl "Parsing Manifest" *
複製代碼

輸出信息中有一些警告信息之類的,最終在輸出信息中找到了個相關的:

Applications/Android Studio.app/Contents/plugins/android/lib/android.jar
複製代碼

看目錄名,大概是AS插件中對應的Android相關的lib工具包。找到對應位置,用JD-GUI打開對應的jar文件,具體看下一下。

經過全局搜索關鍵字 Parsing Manifest,的確能夠定位到具體的 ApkViewPanel類,且包名與上面AS日誌中都能對的上,但字節碼反解成java過程當中有內部錯誤。嘗試着用用jadx打開,由於android.jar包還挺大,時間比較長,、最終雖然 ApkViewPanel部份內容能夠顯示,但內部依然有部份內部錯誤沒法顯示,且 Parsing Manifest不能直接顯示。

2.3 GitHub定位與源碼分析

不過不要緊,咱們試着去找找源碼看看。搜索對應包名:com.android.tools.idea.apk.viewer,選擇java類別,很快,咱們找到了對應的源碼位置。

github.com/JetBrains/a…

正好,AS就是JetBrains主導的產品,Perfect!

很快,咱們找到了對應 Parsing Manifest的位置:

setAppInfo()方法中,將對應的控件內容從原來的Parsing Manifest改爲了對應的包名和版本號等信息。

顯然,在代碼myNameComponent.append("Parsing Manifest");setAppInfo(result);之間,程序出了問題。

這之間關鍵的類,主要有 apkParser對象對應的 ApkParser類,還有 Archives類。繼續跟蹤 ApkParser類,發現其主要也是一個外殼性質的類, apkParser.constructTreeStructure()方法主要流程來到以下所示位置:
如今,咱們發現,不管是此處的 ArchiveTreeStructure類,仍是以前的 Archives類,這兩個關鍵線索上的類都不是在這個項目中。根據代碼文件中的 import導入,很快,咱們發現,線索被定向到了 com.android.tools.apk.analyzer包中。

從包名上來看,com.android.tools.apk.analyzer應該是Android Tools中帶的一個工具。來到項目iml文件,咱們發現與之相關的構件。其中,組名是:com.android.tools.apkparser,構件名是:apkanalyzer

2.4 工具本體-apkanalyzer

至此,咱們先總結下問題的緣由。

AS中自帶的Analyze APK,其實是經過集成了插件實現,而插件內部,又經過調用了 Android Tools中的名叫apkanalyzer的工具實現的分析。所以,想要追溯出現問題的緣由,咱們須要再去對應追蹤下apkanalyzer

若是熟悉Android Tools,咱們對應去tools目錄下找找,很快便能找到apkanalyzer。及時不熟悉,不知道目錄位置也不要緊,打不了全局搜索下。

終於,對應的工具本體出如今咱們面前。

實際上,若是對Google Developer比較熟悉,或者直接在上面搜索下,也能直接在Analyze APK頁面上找到核心信息,直接指向工具本體—apkanalyzer
developer.android.com/studio/buil…

啊哈,饒了半天,原來官方文檔上直接有啊,哭了,有木有?

一樣的,經過反編譯工具查看apkanalyzer.jar代碼終究不太方便,且內部也有很多INNER ERROR。因而,咱們繼續去GitHub上找找。

GitHub上搜索到的apkanalyzer相關的零零散散,好像都是我的的,不太官方,也不符合咱們的預期。怎麼辦呢?

源碼不夠,Google Source來湊!

直接Google Source搜索可能的關鍵字,立刻獲得告終果。

顯然,這正是咱們須要的。

但此時,若是直接源碼跟蹤下去,仍是有難度的。

2.5 apkanalyzer查因

apkanalyzer做爲一個工具,是獨立的。在實際使用時能夠直接脫離AS環境,Google Developer官網上也有專門的篇幅進行了介紹。
developer.android.com/studio/comm…

實際使用時,咱們經過不一樣的命令行命令及參數,能夠獲得咱們指望的結果,如用來分析APK基本屬性,Manifest,dex或資源等。

由此,咱們能夠多試幾個,反正AS中Analyze APK最終用的也是它。在必定的命令上,結果確定是同樣的。也就是說,經過命令行直接執行apkanalyzer,確定也會有問題,但有個好處時,命令行執行每每都能拋出對應的錯誤日誌。

有了進一步的錯誤日誌提示,就有了異常棧和關鍵性的真正的錯誤緣由信息。

那咱們就試一試吧。

➜  bin apkanalyzer -h apk file-size Corn-dev-debug.apk
46.9MB

➜  bin apkanalyzer apk summary Corn-dev-debug.apk
com.corn	10300	10.3.0.0

➜  bin apkanalyzer manifest print Corn-dev-debug.apk
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:versionCode="10300"
    android:versionName="10.3.0.0"
    package="com.mymoney"
    platformBuildVersionCode="27"
    platformBuildVersionName="8.1.0">

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="26" />

    <uses-permission
        android:name="android.permission.GET_ACCOUNTS"
        android:maxSdkVersion="22" />

...
...
...
複製代碼

說明直接分析Manifest文件都是沒有問題的。

➜  bin apkanalyzer dex list Corn-dev-debug.apk
classes7.dex
classes6.dex
classes5.dex
classes4.dex
classes3.dex
classes2.dex
classes.dex
複製代碼
➜  bin apkanalyzer resources configs --type drawable  Corn-dev-debug.apk
anydpi-v21
anydpi-v26
default
watch-v20
v21
v23
ldpi-v4
mdpi-v4
ldrtl-mdpi-v17
hdpi-v4
ldrtl-hdpi-v17
xhdpi-v4
ldrtl-xhdpi-v17
xxhdpi-v4
ldrtl-xxhdpi-v17
xxxhdpi-v4
ldrtl-xxxhdpi-v17
複製代碼
➜  bin apkanalyzer files list Corn-dev-debug.apk
Exception in thread "main" java.util.zip.ZipError: invalid END header (bad central directory offset)
	at com.sun.nio.zipfs.ZipFileSystem.zerror(ZipFileSystem.java:1605)
	at com.sun.nio.zipfs.ZipFileSystem.initCEN(ZipFileSystem.java:1045)
	at com.sun.nio.zipfs.ZipFileSystem.<init>(ZipFileSystem.java:130)
	at com.sun.nio.zipfs.ZipFileSystemProvider.newFileSystem(ZipFileSystemProvider.java:117)
	at java.nio.file.FileSystems.newFileSystem(FileSystems.java:326)
	at java.nio.file.FileSystems.newFileSystem(FileSystems.java:276)
	at com.android.utils.FileUtils.createZipFilesystem(FileUtils.java:538)
	at com.android.tools.apk.analyzer.Archives.openInnerZip(Archives.java:48)
	at com.android.tools.apk.analyzer.ArchiveTreeStructure.create(ArchiveTreeStructure.java:100)
	at com.android.tools.apk.analyzer.ArchiveTreeStructure.create(ArchiveTreeStructure.java:65)
	at com.android.tools.apk.analyzer.ApkAnalyzerImpl.filesList(ApkAnalyzerImpl.java:803)
	at com.android.tools.apk.analyzer.ApkAnalyzerCli$Action$6.execute(ApkAnalyzerCli.java:430)
	at com.android.tools.apk.analyzer.ApkAnalyzerCli.run(ApkAnalyzerCli.java:163)
	at com.android.tools.apk.analyzer.ApkAnalyzerCli.main(ApkAnalyzerCli.java:130)
複製代碼

終於,在用命令顯示Apk內全部文件列表的時候出現了問題。而且有對應的調用棧信息拋出。

從調用棧中咱們發現,命令行的調用方式,是經過ApkAnalyzerCli中的main方法去接收命令參數的。在ApkAnalyzer.jar同級的目錄中,咱們發現了有對應的ApkAnalyzerCli.jar,其做用,就是基於ApkAnalyzer.jar基礎上封裝的一個Client,以方便程序被外部調用執行,如經過命令行的方式等。

而且,忽然間發現,此處的棧信息與以前GitHub上JetBrains/android項目中分析到的源碼位置相同~!!

at com.android.tools.apk.analyzer.ArchiveTreeStructure.create(ArchiveTreeStructure.java:100)
複製代碼

看來,這就是真實的緣由所在了。

2.6 項目查因

ArchiveTreeStructure主要做用是分析apk文件中的檔案文件樹形結構,且從最終拋出的錯誤信息能夠看出:Apk包中zip文件出現的問題,zip文件頭部信息無效。

java.util.zip.ZipError: invalid END header (bad central directory offset)
複製代碼

抓住這一關鍵點,那就好辦了。直接搜索整個項目中的.zip文件,發現還真有很多。而且存在於assets目錄下。主要存放的是一些資源。

直接解壓縮.zip文件,發現有問題,果真,此處有問題的.zip文件致使apkanalyzer在分析Apk過程當中,分析到這些.zip文件出現了問題。

.zip格式顯然是不符合.zip規範的,那麼,具體是什麼問題呢?

查找到項目使用到這些文件的代碼位置。

淚奔了,有木有?!

2.7 覈驗

到如今位置,總體邏輯已經很清晰了。項目中由於存在移除了表示zip格式的頭字節的zip文件,致使在使用Android Studio Analyze APK分析Apk時,出現程序錯誤,從而只顯示Parsing Manifest

究竟對不對呢,能夠以簡單方式覈驗下。
1,經過移除此類有問題的.zip文件,從新打包,發現可使用Android Studio Analyze APK進行分析了,直接使用apkanalyzer命令行分析時,也木有問題。

2,使用二進制修改工具,將這類有問題的.zip文件對應的四個字節的頭信息給補上。
此處推薦使用 Hex Friend 工具,能夠直接以十六進制修改對應的二進制文件內容。

Hex Friend打開zip文件後,發現文件頭字節中,確實不符合zip規範。zip文件頭四個字節是固定的, 504B0304,用來表示的是對應的zip格式。

因而,咱們手動補上試試。保存後,發現.zip文件能夠經過系統工具解壓了。

替換後再次打包驗證,發現能夠Android Studio Analyze APK能夠正常分析,apkanalyzer能夠直接使用。

3、解決

項目中之因此此處將zip文件頭四個字節去除存放,當時主要考慮是安全性問題。而後經過代碼的形式在拷貝過程當中,去補上對應的字節信息,至關於進行了修正。

如今既想不影響原有邏輯,同時又能愉快的使用Android Studio Analyze APK進行分析,怎麼辦呢?

經過分析,咱們發現,apkanalyzer拋出的異常,是在對zip文件進行分析的時候出現的,既然.zip文件自己,文件頭標識.zip格式的字節已經被去除,那程序是如何識別其爲.zip文件的呢,大機率是直接經過文件後綴了。發現文件後綴爲.zip,就直接按照zip文件格式進行了處理。

對應的調用棧上,咱們沒有找到Archives類的openInnerArchive方法,這應該是對應的jar包版本問題。不過不要緊,沿着對應的調用過程分析,咱們找到了以下的邏輯。

顯然,此處的判斷邏輯與猜想一致,直接是按照文件名稱中的格式後綴去匹配的。

那換一種思路,若是這類文件自己,不是zip後綴,程序極可能就不會執行到zip文件的分析判斷上,是否是就能夠了呢?

說幹就幹,直接將項目中此類非規範化的zip文件格式替換,例如替換成一種本身隨意想的格式,就叫.tfc吧,而後程序中作好可能的邏輯修正。

試試。果真,再次打包,分析,OK,徹底木有問題!


4、啓示

4.1 經過相似方式提升App安全防禦

其實從反面來想,若是咱們不想別人經過apkanalyzer來分析咱們的Apk,能夠經過此類技巧,直接放一個不符合規範的zip文件在assets目錄中。例如本文中的將zip文件頭四個字節去除。

若是本身想分析本身的Apk,加對應的文件移除便可。這樣在必定程度上,防防一些開發者,提升一下安全的門檻,仍是能夠的。

是否是有點,尬?

實際上,咱們發現不少App在提升反編譯門檻時,都採起的相似的思路,經過分析對應的反編譯工具的源碼,在可能對應有邏輯漏洞的地方去設防,使得反編譯程序運行到對應位置出現錯誤,以此達到反編譯失敗目的。

如針對ApkTool反編譯工具使用的一些常見方法等。

4.2 增強文件格式的嚴謹判斷邏輯

有時候,在內部項目或不太嚴格場景下的技術實現時,直接對文件後綴進行格式校驗,也許也就能夠了。可是,在一些通用的框架、工具或有外部交互及嚴格需求場景的狀況下,對文件格式的斷定,不該該只是簡單的判斷文件格式後綴。由於文件格式後綴是很容易被任意修改的,並不具備事實上的文件格式約束力。在文件格式後綴判斷的基礎上,必要時,增長上對文件事實上的格式判斷邏輯,是頗有必要的。在必定程度上來講,本例中發現的問題,其實也偏偏是apkanalyzer工具自身隱藏的一個bug。


5、結語

apkanalyzer是Android開發過程當中,用來分析Apk中頗有用的一個工具,常常被用到。由於其集成在AS中後,足夠簡單輕便,且能必定程度上知足咱們分析Apk的須要。

項目在不斷的迭代,維護和開發,項目中的技術問題也會不時出現,對每個技術問題,其實都是一次很好的技術歷練機會。認真分析,不斷探因,最終會終有所獲。

通常的產品開團隊,面對這類問題,每每習慣的選擇繞開,由於在相對繁忙的需求開發過程當中,無暇此顧。其實,對整個項目組來講,長期來看,這是一個嚴重的問題。這類技術性問題,就像廚房中的小強,若是發現了不一一解決之,最終會致使不斷的繁衍,終有一日,屋裏的主人,會被細菌病毒侵襲。

與其積重難返,不如時時解決之。

end~

相關文章
相關標籤/搜索