1. 程式人生 > >Android逆向之旅---Android中分析抖音和火山小視訊的資料請求加密協議(IDA動態除錯SO)

Android逆向之旅---Android中分析抖音和火山小視訊的資料請求加密協議(IDA動態除錯SO)

一、前言

最近萌發了一個做app的念頭,大致什麼樣的app先暫時不說,後面會詳細介紹這個app的開發流程和架構,不過先要解決一些技術前提問題,技術問題就是需要分析解密當前短視訊四小龍:抖音,火山,秒拍,快手這四家短視訊的資料請求加密協議,只有破解了加密協議,才可以自定義資料請求拉回資料。不多說了,本文先來第一站搞定抖音和火山這兩個資料請求的加密協議,為什麼說是這兩個呢?因為我們在後面分析會發現這兩個app其實用的是一套加密協議,畢竟這兩個app都是今日頭條內部孵化的專案。所以只要搞定一個即可。我們決定搞定抖音吧,畢竟我比較看好和喜愛看抖音。

二、逆向分析

不多說了,趕緊來分析吧,不過本文不在利用粗暴的靜態方式去破解了,應廣大同學要求,就介紹IDA動態除錯so來進行破解,這樣也能給大家帶來IDA的使用技巧。畢竟我寫文章技術都是為了你們。這種分析請求資料的突破口一般都是抓包

,這不用多說了。不過都是用了https請求,所以需要手動在裝置中安裝Fiddler證書,才能抓到正確的資料資訊:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

開啟抖音之後,看到資料刷的很快,發現一個feed的介面是返回的首頁的資料,在分析它的請求引數中有三個欄位是minCursor,maxCursor,count其實這三個欄位就是後面他進行資料分頁請求的關鍵,到後面再詳細說。不過這裡看到還沒有什麼問題,不過問題往下看他的更多請求引數,會發現兩個欄位:

0?wx_fmt=png

這時候會發現其他引數都和本地裝置有關或者直接寫死的,唯獨這兩個引數資訊是始終變化的。所以猜想這兩個欄位是用於請求協議資料加密和服務端進行校驗的。那麼如果我們想單獨構造資訊去請求,這兩個欄位的資訊一定要正確,不然請求不到正確的資料的。好了,這裡簡單了,使用Jadx開啟抖音app即可,直接全域性搜尋欄位的資訊"as=":

0?wx_fmt=png

看到這裡是構造了as和cp兩個欄位的值,直接點選進入即可:

0?wx_fmt=png

這裡大致的邏輯也比較簡單,利用UserInfo.getUserInfo函式獲取字串,然後對半開給as和cp兩個欄位,右移操作就是除以2的意思。這裡不分析程式碼來看看引數怎麼來的,直接用Xposed進行hook這個函式列印引數看結果,粗暴快捷,以後其實這都是快速解決問題的一種方式,hook大法是最無敵的

0?wx_fmt=png

先來看一下這個加密方法的引數資訊,看到是native的,也就是說加密操作是在so中做的,後面需要除錯的也是這個so了。也不管了,hook這個方法然後列印資訊看引數構造:

0?wx_fmt=png

直接執行模組,列印日誌看資訊:

0?wx_fmt=png

看到三個引數列印的值,發現大致三個引數的意義是:當前時間戳,請求url,請求引數的陣列資訊。好了,我們現在可以新建一個Android工程,然後構造這三個引數資訊,然後呼叫它的so函式,為了能夠快速找到這個so名稱可以用萬能大法:全域性搜尋字串資訊"System.loadLibrary" 

即可:

0?wx_fmt=png

這樣就找到了這個so名稱了,到libs目錄下把這個so拷貝出來到我們自己構建的demo工程中,這裡先不著急除錯去分析native的加密函式功能,還是老規矩拿來主義,直接上層構造一個和他一樣的包名的native函式,呼叫它的so獲取結果即可:

0?wx_fmt=png

然後就開始構造引數資訊了,這裡為了簡單,先把那些公共的引數資訊寫死比如裝置的sid,aid,版本號等資訊:

0?wx_fmt=png

這裡我們利用公眾引數資訊,構造請求欄位陣列資訊,然後還有單獨的幾個欄位值不能參與操作,可以通過之前的列印日誌分析出來。當然時間戳也是伺服器格式,和本地是少三位的,直接除以1000即可。下面為了簡單直接把公眾引數寫死即可,當然後續優化就是把這些引數值進行動態獲取填充即可:

0?wx_fmt=png

構造好引數之後,然後就開始呼叫native函式,然後獲取返回結果即可:

0?wx_fmt=png

到這裡,我們構造的工作就完成了,下面就開始直接執行吧,不過可惜的是,沒有這麼順利,直接執行閃退了:

0?wx_fmt=png

這裡應該進行載入so出現問題了,那麼我們在回過頭看看我們是不是有些環境沒初始化,看看UserInfo類中是不是還有一些初始化方法沒呼叫:

0?wx_fmt=png

這裡看到的確有兩個方法有點可疑,全域性檢視這兩個方法的呼叫地方:

0?wx_fmt=png

看到全域性中就一個地方呼叫了setAppId方法,而且值就是寫死的為2,另一個方法initUser就有點麻煩了,不過還是萬能的hook大法,直接hook這個方法列印他的引數資訊即可

0?wx_fmt=png

執行模組,檢視列印的日誌資訊:

0?wx_fmt=png

看到了,引數資訊一致都是這個字串資訊,直接拷貝出來賦值呼叫即可:

0?wx_fmt=png

三、IDA除錯so程式碼

在次執行,發現可惜了,還是報錯,而且詭異的是日誌沒列印,也就說setAppId和initUser函式沒有呼叫就退出了,那麼就會想到?是不是so中的JNI_OnLoad函式中做了一些判斷邏輯呢?直接用IDA開啟這個so檔案即可:

0?wx_fmt=png

開啟之後找到JNI_OnLoad函式,F5檢視他的C程式碼,發現果然內部有很多判斷,然後直接呼叫exit函式退出了。所以如果想成功的呼叫它的so方法,得先過了他的這些判斷了,這裡就要開始進行除錯操作了,其實這裡可以直接靜態分析有一個快捷的方法,但是為了給大家介紹動態除錯so技巧,就多走點彎路吧,後面再說一下粗暴簡單的技巧。

下面就來開始進行除錯so檔案了,關於IDA除錯so檔案,我之前已經寫過一篇非常詳細的文章了:Android中IDA動態除錯so檔案詳解;這裡不會在詳細介紹具體步驟了,直接上手幹:

第一步:拷貝IDA安裝目錄下的android_server檔案到裝置目錄下

第二步:執行android_server命令

0?wx_fmt=png

第三步:轉發埠和用debug模式開啟應用

0?wx_fmt=png

這裡有同學好奇為什麼不需要修改xml中的debug屬性呢?因為我除錯的是我自己的demo工程,而Eclipse預設簽名打包出來的apk這個屬性值就是true的,所以不需要進行修改了。

0?wx_fmt=png

第四步:啟動IDA附件程序

0?wx_fmt=png

設定本地地址和一些選項:

0?wx_fmt=png

因為現在已經知道需要除錯JNI_OnLoad函式,所以需要設定掛起load函式處,然後選擇除錯的應用程序:

0?wx_fmt=png

第五步:檢視除錯埠連線偵錯程式

0?wx_fmt=png

在Eclipse中的DDMS中檢視有紅色小蜘蛛的除錯應用埠號是8647,然後連線偵錯程式:

0?wx_fmt=png

這裡一定注意埠正確,不然連結操作的。

第六步:點選IDA中的執行按鈕,或者F9快捷鍵

0?wx_fmt=png

這時候發現紅色蜘蛛變成綠色了,而且除錯對話方塊也沒有了。這時候就進入除錯頁面了:

0?wx_fmt=png

為了安全起見,再一次檢視debug選項有沒有掛起load函式:

0?wx_fmt=png

如果發現沒有,還需要進行手動勾選上:

0?wx_fmt=png

因為我們給JNI_OnLoad函式掛起了,而一個應用會載入很多系統的so檔案,所以這裡一直點選執行或者F9:

0?wx_fmt=png

過了系統so載入步驟:

0?wx_fmt=png

這些都是系統的so檔案載入,所以一路往下都直接執行越過除錯即可:

0?wx_fmt=png

可以看到這裡會載入很多系統的so檔案,當我們點選應用的按鈕,載入自己的libuserinfo.so檔案的時候才開始進行除錯工作:

0?wx_fmt=png

點選OK載入進來,然後就停留在了掛起狀態了,這時候,我們在右側欄查詢這個so檔案:

0?wx_fmt=png

然後點選,繼續查詢他的JNI_OnLoad函式:

0?wx_fmt=png

點選進入JNI_OnLoad函式處,下個斷點:

0?wx_fmt=png

因為我們在之前靜態分析了這個函式內部有很多個exit函式,為了好定位是哪個地方exit了,所以在每個exit函式之前下個斷點,來判定退出邏輯,這裡下斷點有技巧,因為是if語句,所以在arm指令中肯定就是CMP指令之後的BEQ跳轉,所以在每個CMP指令下個斷點即可,這裡發現了9個地方,所以下了斷點也很多,慢慢分析:

0?wx_fmt=png

第一處的CMP指令下個斷點,然後執行到此處,檢視R3暫存器值是否為0:

0?wx_fmt=png

是0,那麼第一處exit就沒問題,接著往下走,直接按F9到下一個CMP判斷指令斷點處:

0?wx_fmt=png

發現第二處的CMP中的R3暫存器值也是0,所以也沒問題,直接F9到下一個斷點:

0?wx_fmt=png

到了第三處判斷髮現R3寄出去你的值不是0了,而是1,所以為了繼續能夠往下走,就修改R3暫存器值即可,在右側欄的暫存器中右擊R3暫存器,然後點選修改值:

0?wx_fmt=png

把1改成0,儲存即可:

0?wx_fmt=png

修改成功了,執行發現就過了判斷:

0?wx_fmt=png就繼續往下走,到下一個斷點:

0?wx_fmt=png

這裡有問題了,我們如果直接F9到第四處CMP的話,發現直接退出除錯了,說明在3和4處判斷中間有問題了,最終發現是這個跳轉指令出現的問題,這裡需要多次單步除錯F7鍵,定位出現問題的地方了,我們進入這個跳轉地址:

0?wx_fmt=png

然後發現內部還有BL指令,出現問題了,繼續深入檢視:

0?wx_fmt=png

看到了,這裡發現問題的原因了,有一個GlobalContext類,而這個類應該是Java層的,native層應該用反射機制獲取全域性的Context變數,我們直接去Jadx中搜索這個類:

0?wx_fmt=png

那麼問題就清楚了,因為我們的demo工程中壓根沒這個類,所以native中獲取全域性context變數就失敗了,所以就exit失敗退出了,解決辦法也簡單,直接在demo工程中構造這個類,然後在Application中初始化context即可:

0?wx_fmt=png

構造的時候一定要注意包名一致,然後在demo中的Application類進行設定context即可:

0?wx_fmt=png

然後再次執行專案,可惜還是不行,所以還得進行除錯JNI_OnLoad函數了,方法步驟和上面類似,不多說了,不過這裡應該是過了上面的Context獲取失敗的問題了,繼續往下走,發現了重要資訊了:

0?wx_fmt=png

這裡有一個類似於MD5的值,繼續往下走BL處:

0?wx_fmt=png

看到R0暫存器中的值,發現是demo應用的簽名信息,繼續往下走BLX看看:

0?wx_fmt=png

這裡看到大致清楚了,是獲取應用簽名信息,也就是簽名校驗了:

0?wx_fmt=png

好吧,在這一處判斷exit函式中,應該是通過反射獲取Java層的context值,然後在獲取應用的簽名信息和已經儲存的原始抖音簽名信息做對比,如果不對就退出了。那麼過簽名校驗也很方便,直接利用我之前的kstools原理,把hook程式碼程式碼拷貝到工程中,攔截獲取簽名信息,然後返回正確的簽名信息即可:

0?wx_fmt=png

具體的hook程式碼去看我的kstools實現原理即可:Android中自動爆破簽名信息工具kstools;然後hook程式碼一定要在Application的第一行程式碼呼叫,不然沒有效果的。這樣操作完成之後,其實已經出資料了,不過為了能夠進入加密函式進行除錯分析具體的加密演算法,我們繼續除錯JNI_OnLoad函式:

0?wx_fmt=png

繼續往下走,會發現在第五個exit判斷之後,有一個函數出問題了,就是這個BL,進入內部檢視:

0?wx_fmt=png

哈哈,發現了這個字串資訊,弄過除錯的同學大致都猜到了,這個是反除錯操作,繼續往下走:

0?wx_fmt=png

這裡可以百分百確定是讀取status檔案中的TracerPid欄位值來進行反除錯檢測了,給下面的兩個CMP指令下個斷點:

0?wx_fmt=png

發現R3暫存器中的確不是0,所以為了過了反除錯,直接修改R3暫存器值為0即可:

0?wx_fmt=png

這樣就過了反除錯檢測了,單步往下走到下一個exit的判斷斷點,最終還有一個地方需要處理就是第七個CMP指令:

0?wx_fmt=png

處理方法直接修改R3暫存器中的值為0即可,就這樣我們成功的過了JNI_OnLoad中的所有判斷exit的地方了:

0?wx_fmt=png

然後給加密函式getUserInfo下個斷點:

0?wx_fmt=png

直接點選進入即可:

0?wx_fmt=png

四、加密資料結果輸出

也成功到達了加密函式斷點處,這裡已經沒有任何判斷邏輯了,就是一個單純的加密函數了,不過這裡不在進行除錯分析了,感興趣的同學可以自己操作了,因為我們的目的達到了,就是成功的獲取到了加密之後的資料了:

0?wx_fmt=png

看到了,我們成功的獲取到了as和cp值,然後構造到請求url中,也成功的拿到了返回資料。我們這裡多了一步解析json資料而已,原始的json資料是這樣的:

0?wx_fmt=png

之所以要解析,也是為了後面的專案準備的,到時候我會公開專案的開發程序。不管怎麼樣,到這裡我們就成功的獲取抖音的加密資訊了。主要通過動態除錯JNI_OnLoad函式來解決so呼叫閃退問題,在文章開頭的時候說到了,其實本文可以直接用簡單粗暴的方式解決,就是萬能大法:全域性搜尋字串資訊,包括Jadx中查詢和IDA中檢視,因為字串資訊給我們帶來的資訊非常多,有時候靠猜一下就可以定位到破解口了,比如這裡,我們在IDA中使用快捷鍵Shift+F12開啟字串視窗

0?wx_fmt=png

憑著這些關鍵字串資訊就能斷定so中做了哪些操作。記住這些敏感的字串資訊,對日後的逆向非常關鍵。

五、技術總結

上面就解決了抖音的請求資料加密資訊問題了,下面來總結一下本次逆向學習到的技術:

  • 第一、看到在native層用反射去呼叫Java層的方法獲取資訊也是一種防護so被惡意呼叫的方式。比如本文的context變數獲取。

  • 第二、簽名校驗永遠都不過時,其實本文當時沒想到他有簽名校驗,因為看到native函式中都沒有傳遞context變數,誰知道他是用反射呼叫Java層方法獲取的,長知識和經驗了。

  • 第三、反除錯也是永遠不過時的,不過他這裡的反除錯檢測有點簡單了,就一處而且就一個程序,如果高階點應該啟多個程序,迴圈檢查tracepid值進行校驗,會增大難度。

  • 第四、在逆向中有時候在Java層沒必要去花時間分析一個方法的引數和返回值構造情況,直接利用Xposed進行hook大法列印方法的引數資訊靠猜也就出來了。

  • 第五、靜態方式分析永遠都不會過時,全域性搜尋字串也是最基本法則,靠猜就可以快速獲取結果。

六、火山小視訊加密分析

上面解決了抖音的加密問題,下面再來看一下火山小視訊的加密資訊,突破口依然是使用Fiddler進行抓包檢視資料:

0?wx_fmt=png

通過抓包會很神奇的發現,和抖音的資料結構欄位幾乎異曲同工,果然是自家兄弟,繼續檢視他的加密欄位:

0?wx_fmt=png

這裡不在多說了,既然加密的欄位都是一樣的。那麼我們直接不多說用Jadx開啟火山小視訊,看看他有沒有那個native類UserInfo資訊:

0?wx_fmt=png

看來不用多一次分析了,完全一樣,那麼直接用同一個so,同一個加密即可,在demo工程中執行檢視日誌:

0?wx_fmt=png

初始化都是一樣的,直接執行:

0?wx_fmt=png

看到了,資料也回來了,看看他的原始json資料:

0?wx_fmt=png

到這裡,我們就成功的破解了抖音和火山小視訊的資料請求協議了,有了這兩個短視訊資料,後面我們開發app就簡單了,當然在文章開始的時候也說了,現階段短視訊四小龍:抖音,火山,秒拍,快手,那麼已經幹掉了前面兩個,下一個會是誰呢?爭取在年底把這四個app全部爆破成功,能夠請求到他的資料。為我們後面的app開發作為基礎。

嚴重說明

本文的意圖只有一個,就是通過分析app學習更多的逆向技術,如果有人利用本文知識和技術進行非法操作進行牟利,帶來的任何法律責任都將由操作者本人承擔,和本文作者無任何關係,最終還是希望大家能夠秉著學習的心態閱讀此文。鑑於安全問題,樣本和原始碼都去編碼美麗小密圈自取!

0?wx_fmt=png 七、總結

通過本文可以發現,我們其實沒有真正意義上的破解它的演算法,但是結果卻是我們想要的,這就夠了。而對於現在很多app把加密演算法放到so中,在對so做一些防護,這樣就很難利用本文的技術去呼叫app的so了。不過so再怎麼防護就是那麼幾種方法,我們依然可以用動態除錯來解決。有人在文中很好奇那些判斷校驗不能直接修改so指令做到嗎?比如簽名校驗,沒必要在Java層進hook呀,直接修改CMP和BEQ指令唄?的確可以這麼做,但是這是下一篇介紹的內容,因為我們下一篇要破解下一個短視訊app,就用到這種方式過校驗。敬請期待!每次講解除錯就需要大量截圖非常累,所以大家看完覺得好就多點一下廣告和分享更多喜歡逆向的同學吧!

手機檢視文章不方便,可以網頁看

http://www.wjdiankong.cn

長按下面