之前也做過一些關于Android安全相關的總結,但是如果不深入了解逆向技術,所有的安全都是紙上談兵,知己知彼百戰不殆,只有對常見逆向技術非常熟悉,才能更好的對自己APP做安全防護,這篇文章我們就嘗試對APP做一些逆向工作。
篩選應用
對市面上的APP做個初步分析,會發現從逆向角度主要分三類:
- 一是裸奔派,沒做認識安全方面的防護,甚至代碼混淆都沒有做,網絡協議也是全明文的。很多小公司APP出于開發人員能力或者為了快速搶占市場無暇顧及這塊兒。這種產品如果有羊毛可薅,往往會比較慘,因為隨便一個新人甚至外行人跟著一篇逆向教程就能破解。
- 二是加固派,采用第三方公司的加固技術對APP進行加固。采用加固技術的大部分是一些中等規模的公司,公司有了安全方面的訴求,但是沒有精力對這方面做過多投入,所以直接選擇了第三方公司的加固技術。專業的事交給專業的人去做是沒有問題的,但是目前最大的問題是Android系統是開源的,一個APK無法決定自己被安裝到什么環境,不管加固技術做再多工作,最終還是要在運行時把代碼還原出來的,只需要想法注入到運行時,把ClassLoader加載到內存中的類導出即可。
-
三是實力自信派,去解壓或者逆向APK,看起來跟裸奔派差不多,代碼和配置文件什么的都能看得到,但是想獲取到敏感信息時,發現敏感信息都被很好的隱藏了起來。去翻看各家大廠的APP,基本都屬于這一類。大廠為什么不采用加固技術呢?我得觀點是加固是一項門檻很高的技術,大廠APP交給第三方公司加固肯定不放心,自己投入人力去開發加固技術又不劃算。另外一點是由于android系統升級很快,加上大廠APP使用很多黑科技依賴系統底層,這些往往導致某些場景下加固技術失效,大廠用戶量巨大,同事維護的APP版本眾多,一次加固技術問題(例如導致APP閃退)都會造成嚴重的后果,所以大家最終都放棄了加固技術,采用局部安全加強的方法。下面是直接用AS解壓支付寶、微信、抖音的圖片,我們可以看到直接看到dex文件和manifest文件。
支付寶
微信
抖音
通過上面分析我們知道,第一類沒有任何挑戰,第二類通常比較簡單,采用成熟的虛擬機或者hook方案,如果沒有沒有找到合適的方案,自己去破解難度比較大,第三類上手簡單,破解具體敏感點比較有挑戰。這里我們選擇第三類的APP進行研究學習,為了規避不必要的麻煩,這里我選擇了一款國外的應用whatsapp。
逆向目的
我們為什么要逆向一個APP?因為現在都是輕客戶端實現,所以通常客戶端里面不會有什么重要的算法實現,目前常見的逆向目的,主要有網絡協議破解、資源獲取(字體、圖片、秘鑰)、源碼修改(植入廣告、游戲金幣修改)等。目前最常見的還是協議破解,例如前一段火爆的微信群控外掛,就是需要破解微信協議才可以實現,這里我們把我們的目標定為協議破解。
抓包
既然我們想要破解協議,第一步肯定是要抓包,先看下抓到的請求是什么樣的。我們打開charles和設置好手機上的代理,運行whatsapp,發現并沒有抓到數據,而手機上的其他應用數據抓包都是好的,現在只能猜測它網絡使用了tcp直連,或者網絡請求禁用了代理,或者其他我們不知道的技術。抓包沒能獲得有效線索(暫不考慮tcp抓包),那么我們就暫時跳過這條路,看能不能從代碼層面找到點突破。
靜態分析
我們先找到一個靜態分析的切入點,進入APP的驗證碼發送頁面,在終端輸入
adb shell dumpsys activity top
通過打印Activity棧,可以定位當前頁面的類名為VerifySms,
下面我們就可以準備去翻逆向代碼了。通過dex2jar直接把dex文件反匯編為java代碼,或者直接使用jadx,直接反編譯整個apk,代碼、manifest和資源文件一起都能看到,如下圖:
現在已經可以愉快地讀代碼了。很快就找到了請求相關的代碼:
通過源碼分析,發現邏輯還挺復雜,代碼又做過了混淆,閱讀代碼讀起來挺困難,有些邏輯需要看下運行時的值才好理解,這時候就需要動態調試了。
動態調試
動態調試需要兩步,首先要有一個debuggable的apk包,手機安裝這個包并運行,第二步是要有這個包對應的源碼。當然我們不可能有源碼,我們只能使用由dex反匯編后的smali代碼,不過關系不大,smali語法相對來說不是很復雜。我這里先做第一步,使用apktools反匯編apk包,可以看到反編譯后的項目:
我們打開AndroidManifest.xml文件,修改debuggable為true,然后用apktools重新打包,生成的apk包是未簽名的,重新簽下名后就可以安裝和調試了。需要注意的是重新打包時經常會報很多資源方面的錯,根據報錯刪除或修改相關資源即可。下面我們需要將上面的反編譯后的項目導入AndroidStudio,具體的操作細節可以參考這個文章http://www.lxweimin.com/p/1a28e6439c6a。導入后我們輸入如下指令查看whatsapp進程信息
adb shell ps | grep com.whatsapp
我們可以看到whatsapp的PID為22512,我們通過如下命令做好端口映射
adb forward tcp:5007 jdwp:22512
映射成功后,跟平時調試程序一樣,在AS上去附加應用就好:
附加后,在代碼中打上斷點,操作安裝重編譯后的whatsapp,就可以愉快的調試了:
我們想研究發短信的接口,發現調用幾次之后,下次調用的時間變得很長,嚴重影響調試,我們看能不能修改下代碼,讓發送按鈕始終可用。
我們研究代碼可以得知,每次點擊發送短信,都會把按鈕置為不可用,當倒計時結束時再置為可用。我們只需要把按鈕職位不可用的代碼修改掉,按鈕就始終可用了,通過閱讀和debug,我們找到了設置按鈕狀態的地方,我們修改一下代碼,傳的值永遠為true即可,修改的代碼如下:
我們重新打包安裝,然后發現,這個按鈕始終可用了,可以隨時觸發發送驗證碼的請求,方便不停的觸發debug的場景。后面我們還發現接口參數用到了包簽名,沒關系,我們封裝一個自己的類,返回原始包的簽名,所有使用簽名的地方都調用我們這個類,就可以繞過服務端的簽名驗證了。
現在我們發現一個問題,每次修改一點代碼,都要重新打包安裝,才能繼續調試,效率有些太低了。有沒有辦法可以避免頻繁打包呢?下一節我們使用hook來解決這個問題。
hook 大法
這里的hook是指在使用高權限模式(設備需要root)運行的框架,改變運行時一些類的行為和實現,簡單點說就是利用hook技術,可以在運行時改變你程序的行為,但并不需要改變你程序的代碼。Android平臺上用的比較多的是xposed框架,大家可以編寫自己的模塊,也可以去網上下載別人寫好的模塊,例如微信的防撤回、自動搶紅包模塊。下面是一張xposed圖片
這里我們就不講xposed的使用細節了,我們用xposed編寫一個模塊,去hook網絡請求的參數和返回值:
使用hook,就不需要每次都重新打包了(正常xposed插件每次編譯更新后都需要重啟手機才能生效,可以使用免重啟的方法提高效率。有了hook,可以很方便的更改APP原來的實現邏輯,能夠大大的提高逆向效率。我們也可以使用frida來進行hook,它使用起來更為方便,這里有一篇教程可以看一下。
小結
我們整理一下我們的逆向流程,為了分享網絡協議,我們可以先抓包,通抓包數據分析協議,通常數據都是加密或者加過簽名的,為了弄清楚加密規則,我們就要去靜態分析源碼,邏輯太復雜,我們可以通過動態調試幫助理解邏輯;為了方便調試或者驗證自己的想法,我們需要對原APP修改Smali代碼然后重新打包;為了解決修改代碼重新打包低效的問題,我們使用hook技術,可以方便的修改APP原有邏輯。這套流程整下來,發現剩下的就是體力活了。