在這篇博文中,我將帶領大家學習如何將調試器應用到一個Android應用程序上,并利用第一次反編譯得到的信息來分析應用的方法調用過程。比較獨特的一點是,本方法并不需要獲取安卓設備的root權限。
該方法在移動應用滲透測試時可以派上用場,因為在應用程序運行過程中,我們可以一步步進入到它的邏輯內部,并有可能獲得該應用的關鍵信息,而通常其他方法卻無法做到這一點。例如,在加密前攔截數據流,程序運行時獲取加密密鑰,獲取密碼以及其他的敏感數據。對移動應用滲透測試員和那些想深入了解安卓平臺上的攻擊方式的開發者來說,這篇博文將是非常有趣的。
1、所需工具
下面列舉了本次攻擊演示所需要的所有工具:
Windows/Mac OS X/Linux
Java(推薦1.7版本)
IDE(Eclipse,IntelliJ IDEA,Android Studio,三者任選其一)
Android SDK(https://developer.android.com/sdk/index.html?hl=i)
APKTool(https://code.google.com/p/android-apktool/)或者APK Studio(http://apkstudio.codeplex.com)
安卓設備/模擬器
Dex2Jar(https://code.google.com/p/dex2jar/)
JD-GUI(http://jd.benow.ca/)
在這篇博文中,我將使用Windows 8系統、APK Studio和IntelliJ IDEA來演示。我所使用的安卓手機是普通的Nexus 4,系統版本是Android 4.4.4。推薦大家將所有工具都添加到path環境變量中,這樣用起來比較方便。
2、安卓設備設置
接下來我們就先設置一下手機,為下面的步驟做好準備。
設定開發者選項
首先我們需要做的就是確保我們的安卓手機啟用了USB調試功能,這也是我們可以使用Android SDK工具集來與手機通信的前提條件。要做到這一點,我們需要啟用開發者選項功能。如果你正在運行一個普通的安卓設備,那么你可以通過導航到“Settings”=>“About phone”,然后單擊“Build number”,最終手機應該提示開發者選項已啟用。(其實這里直接進行“設置”=>“開發者選項”=>“開啟開發者選項”就可以了。[譯者注])
啟用USB調試
下一步,我們通過進行“Settings”=>“Developer options”=>”USB debugging”來訪問開發人員選項并啟用USB調試功能。
通過USB鏈接手機和電腦并使用ADB
將手機與電腦通過USB數據線連接之后,會提示“USB調試已經連接上設備”。接下來,我們要確保ADB(安卓調試橋)可以連接到手機。ADB是Android SDK工具集內包含的一個軟件工具。我們在Windows系統控制臺(cmd)上輸入以下代碼:
adb devices
正常情況下將會出現下圖所示的結果:
如果你的電腦上沒有提示上圖中的內容,那么很可能是系統中沒有安裝正確的驅動程序。你需要重新安裝該驅動,驅動程序可以從AndroidSDK或者手機制造商的網站獲得。
3、判斷應用可調試性
當調試安卓應用程序的時候,我們首先要檢查該應用程序是否開啟了調試功能。可以通過以下幾種方法來檢查是否開啟了調試功能。
第一種方法是打開安卓設備監視器(Eclipse中的是DDMS),我們可以在設備區域窗口中看到我們的設備列表。
如果安卓手機里面的某個應用設置為可調試,那么該應用程序會出現在該列表中。在這里我創建了一個測試應用程序,我們可以看到該程序并沒有出現在該列表中,表明該程序我設置為了不可調試。
第二種方法是,我們可以通過檢查APK文件中的AndroidManifest.xml文件來確定應用是否可以調試。APK文件本質上是一個包含應用所有信息的zip壓縮文件。
如果你沒有目標應用的APK文件,那么就必須先從手機中導出該APK文件。每當我們從Google Play 商店中下載應用時,系統都自動下載了該應用的APK文件,并將其存儲在了安卓設備上。這些APK文件的位置通常在手機中/data/app目錄下。如果你的手機還沒有root過,可能你將不能查看該目錄下的文件。然而,如果你知道目標APK的名字,那么也可以通過adb工具將該APK文件轉存到電腦中。為了查找目標APK文件,我們可以打開一個Windows shell并輸入以下指令:
adb shell
這時將產生一個連接安卓設備的shell,然后輸入:
pm listpackages –f
這條指令將列出安卓設備上所有應用的安裝包。
通過查看結果列表,我們就能找到目標應用。
接下來,需要將該APK文件導入到電腦中。為此,我們需要新打開一個shell并輸入以下指令:
adb pull/data/app/[.apk file] [location]
到這里,我們已經得到了目標APK文件。然后我們將打開該文件并檢查里面的AndroidManifest.xml文件。不幸的是,我們不能直接解壓該APK并查看xml文件,因為它是經過二進制編碼處理過的,所以首先必須解碼才可以。目前針對該問題最受歡迎的工具是apktool。不過,最近我一直在使用APK Studio軟件,因為它有一個易于操作的友好界面。所以,在接下來的演示中我都使用APK Studio。
為了開始使用APK Studio,單擊綠色的安卓小圖標。然后在彈出的窗口中填寫項目名稱并選擇待分析的APK文件,最后設置文件保存的位置。
打開APK文件之后,選擇AndroidManifest.xml文件,然后查找該應用的節點。如果該文件中沒有“android:debuggable”標記,那么說明該APK文件是不可調試的。如果有一個標記為‘android:debuggable=”false”’,同樣說明該APK文件是不可調試的。
4、修改AndroidManifest.xml文件開啟應用調試功能
apktool和APK Studio比較好的一點是,可以編輯任何反編譯的APK文件并重新編譯它們。接下來,我們通過添加“android:debuggable”標記來啟用該應用的調試功能。編輯AndroidManifest.xml文件,然后在里面添加‘android:debuggable=”true”’。
添加該標記之后,通過單擊菜單上的錘子圖標重新創建APK文件。我們重建的APK文件會被保存在build/apk目錄中。
重建的APK文件只有在簽名之后才能夠安裝到設備上。所有的安卓應用都需要簽名,但大多數應用程序并不檢查它們是否是用原始的證書進行簽名的。如果此時應用程序檢查了證書的原始性,那么直接簽名可能就沒效果了,除非我們同時也編輯了驗證數字證書的相關代碼。
接下來,我們需要安裝剛剛重建的APK文件。首先,卸載手機中原有的應用程序。然后使用adb重新安裝重建的APK文件,輸入以下指令:
adbinstall [.apk file]
然后檢查并確保重新安裝的應用在安卓設備上正確地運行。如果一切正常,那么我們回到安卓設備監視器界面并刷新一下,此時可以看到我們的應用已經顯示在列表中了。
5、IDE準備
既然現在我們的應用已經可以調試了,那么接下來可以將調試器附加在它上面。在做這之前,我們需要設置一下IDE。在這篇博文中,我使用IntelliJ IDEA。首先,我創建一個新的安卓項目,該項目名字可以隨意取,但是包名字必須跟APK文件的包結構相同。
以上這些都很容易實現。但是,如果你還不確定,可以查看下APK Studio中該APK文件的包結構。對于我的這個應用來說,包結構就是APK的名字“com.netspi.egruber.test”。可以在APK Studio中查看如下圖所示。
取消選中“Create HelloWorld Activity”項,其它的地方使用默認設置,這就完成了項目的創建。此時,你的項目結構看起來應該是這樣:
現在已經創建好了項目,就可以將APK文件的源代碼導入到該項目中。我們之所以要這么做,是因為調試器知道關于該應用的所有符號名字、方法、變量等信息。安卓應用程序比較好的一點是,它們可以輕松地通過反編譯來得到正確的java源代碼。接下來我們就需要這么做,然后將源代碼導入到IDE項目中。
6、Dump apk文件并反編譯得到源代碼
首先,為了得到源代碼,需要將APK文件轉換到jar文件。然后,可以使用一個java反編譯器來恢復到java源代碼,我們使用dex2jar工具來進行此步驟。Dex2jar包含一個d2j-dex2jar.bat文件,通過執行該文件就可以將APK文件轉換成jar文件。它的語法很簡單:
d2j-dex2jar.bat[.apk file]
到這里,你應該得到了一個jar文件。下一步,我們將使用工具JD-GUI來打開該jar文件。
現在你應該可以看到jar文件的包結構啦,包里面都是可讀的java源代碼文件。接下來我們通過選擇“文件”=>“保存所有文件”來將源代碼保存為一個zip文件。
保存源代碼之后,將其解壓到當前目錄中。
現在我們需要將這兩個目錄導入到之前創建的安卓項目中。對于IntelliJ IDEA來說,進入到項目的src文件夾并將這兩個目錄粘貼到這里。
在IntelliJ中,如果我們返回到項目中,則項目結構將會刷新。
單擊其中一個導入的活動文件將會在右邊的窗口中顯示該文件中的源代碼。在下面的截圖中可以看到,我導入的源代碼是使用ProGuard混淆過的。
7、附加調試器
現在我們的項目中已經填充了應用程序的源代碼,我們就可以開始設置斷點。在這個例子中,我在一個方法處設置一個斷點,當向一個文本輸入框中輸入內容的時候程序就會調用該方法。即使代碼是經過混淆過的,也可以正常工作。
設置斷點后,單擊主界面右上角的小屏幕圖標彈出安卓設備中的進程列表,該列表只列出可以調試的進程,然后單擊目標進程將調試器附加到該進程。當然,不同的IDE對應的功能圖標不同。
選中目標進程之后,調試器就連接到了安卓設備。
在我測試的應用中,我將向文本輸入框中輸入數字42,別忘了之前我們在這里設置了斷點。
在單擊“Enter Code”按鍵后,進程執行到斷點處時會暫停。之所以這樣能夠正常工作,原因是調試器知道在安卓設備上該調用什么程序。編譯后的安卓應用中包含了調試信息,例如變量名字,任何理解java調試線協議(JDWP)的調試器都可以識別這些信息。如果一個安卓應用允許調試,那么一個兼容JDWP的調試器,例如大多數的Java IDE,將能夠連接安卓虛擬機并讀取和執行調試指令。
此時,我們就能夠在變量區域窗中查看到我們向應用中輸入的內容。
8、結論
在這里,我們不僅能夠從應用中讀取數據,而且還能夠插入自己的數據。如果我們想中斷程序流程或者繞過邏輯判斷,那么本文中的方法將可以起到作用。通過調試,我們可以更好地理解安卓應用如何執行某些操作。尤其是當我們需要查看加密功能是如何使用,或者確定動態密鑰的值時,該方法將可以派上用場。當調試函數與文件系統或者數據庫進行交互時,此方法也能幫助我們查看信息是如何存儲的。最主要的是,不需要root權限,我們就能在安卓設備上執行這種類型的測試。