一、前言
隨着直播技術火爆之后,各家都出了直播app,早期直播app的各種請求協議的參數信息都沒有做任何加密措施,但是慢慢的有人開始利用這個后門開始弄刷粉關注工具,可以讓一個新生的小花旦分分鍾變成網紅。所以介於這個問題,直播App開始對網絡請求參數做了加密措施。所以就是本文分析的重點。逆向領域不僅只有脫殼操作,一些加密解密操作也是很有研究的目的。
二、抓包查看加密協議
本文就看一款直播app的協議加密原理,以及如何獲取加密之后的信息,我們如何通過探針技術,去調用他的加密函數功能。首先這里找突破點,毋庸置疑,直接抓包即可,我們進入主播頁面,點擊關注之后,看Fiddler中的抓包數據:
我們會發現,請求參數中,有些重要信息,比如用戶的id,設備的imei值等。不過最重要也是我們關心的就是s_sg字段了,因為這個字段就是請求參數信息的一個簽名信息。也是服務端需要進行比對的信息。如果發現不對或者沒這個字段,那么就認為這次請求操作是非法的。所以我們只要得到這個字段的正確值,才能模擬訪問此次操作的網絡請求。
三、分析加密流程
找到突破口了,就是這個字段s_sg,用Jadx打開app的dex文件,打開dex文件之后,全局搜索s_sg字符串:
這里看到只有一處出現了這個字段值,我們點進去查看:
看到這個方法,很興奮,感覺就是加密協議的功能,而且字段都能對上,我們把這個加密方法直接拷貝出來,寫一個demo之后模擬加密之后的信息,悲傷的是發現數據是對不上的,而且看看這個方法所在的類:
盡然是一個和網頁交互的類,說明應該不是這個地方進行請求加密了。這個突破口就斷了。
注意:這里說的是dex文件,不是apk文件,因為Jadx打開apk文件會解析資源文件,如果一個app有很多資源文件,那么Jadx打開就會卡死,所以很多同學問我為什么Jadx打開apk文件就出現卡死狀態,主要是因為解析資源文件導致的。所以為了防止卡死,直接解壓出dex文件,然后打開就不會卡死了。
我們繼續上面的抓包信息,就是請求的url地址,再去Jadx全局搜索:
找到了,點進去查看:
然后全局搜索這個”USER_RELATION_FOLLOW”字符串:
搜到結果,點進去進行查看:
這里看到了,用了注解方式來構造請求信息,而這里的核心類就是InkeDefaultBuilder,全局搜索這個類:
可惜沒搜到,因為這個app進行拆包操作,有多個dex文件:
所以我們需要用Jadx繼續打開他的第二個dex文件進行搜索:
果然,在第二個dex中找到了這個類。
注意:
這里需要注意,對於Jadx打開dex或者apk文件之后,跟蹤發現找不到一些搜索內容的時候,需要有如下猜想:
第一、是否包含多個dex文件,可以利用Jadx去打開其他dex文件進行搜索。
第二、是否存在動態加載插件功能,全局搜索DexClassLoader找到插件加載位置,獲取插件功能包,在用Jadx打開插件包進行搜索。
第三、是否存在so文件中,可以利用IDA打開so文件,Shift+F12展示so中所有的字符串信息視圖,然后進行搜索。
第四、是否信息來源於網絡請求返回,比如一些字符串信息展示,有可能是服務器返回的信息。
繼續分析,點進去查看這個類的定義:
查看他的父類信息:
看到有一個url加密的方法,比較好奇。我們查看這個方法:
繼續查看這個方法:
這里發現有一個網絡請求,會發現一些信息,然后設置到一個地方。我們繼續看方法:
看到d變量的定義類型,一般我們看到不可點擊的可能這個類不在這個dex文件中了,所以我們需要去另外一個dex文件進行查找,而本文案例就是來回這么折騰查找信息操作的,去另外一個dex文件中進行搜索:
查找到了,點進去查看:
這里又看到是一個a變量,看看他的定義:
看到,這里這個類又不可以點擊,說明這個類不在這個dex文件中,去另外一個dex文件中進行搜索:
發現這個類的定義了,點進去進行查看:
原來是一個native的工具類,內部有很多native方法,包括了設置信息的方法,加密解密url方法等。看看他加載的so是什么:
原來是這三個so文件,看到crypto和ssl,弄過加密的知道,這個是openssl加密的庫文件,這里猜想他在native層用了這個加密算法了。先不管,我們用IDA打開這個so文件,因為我們知道libcrypto和libssl這兩個是庫文件,所以直接打開它自己的libsecret文件吧,然后Shift+F12查看他的字符串信息頁面,在之前不是想看看那個加密字段,這里搜索看看結果:
的確找到了,那個加密的字段了,我們點擊進入查看:
然后點擊X鍵,查看調用地方,不過可惜的是,跳轉過去之后發現,那個匯編代碼不是一般的多。這里先不去看了,回過頭來,看看那個加密url的函數:
點擊進去,然后按F5查看對應的C代碼:
這時候就要開始懷疑人生了,IDA卡死了。然后簡單看一下這個函數的匯編代碼,簡直蒙圈。太長了。如果靠靜態分析,我是沒這個耐心和能力了。動態調試?我覺得也夠嗆,搞不好還有反調試,各種跳轉。不知道調試到猴年馬月。
四、獲取加密內容
那么到這里,我大致分析這個直播app的請求協議有一個加密簽名的字段s_sg,這個值是在native層中進行加密操作的,采用openssl進行加密,但是加密函數非常長,分析難度加大。但是不能就這樣放棄了。我們想要這個加密結果,用於我們自己構造參數之后獲取正確的簽名信息值。那么就需要轉化思維了。我們或許只要結果,加密過程對我們來說並不那么重要。所以這里的一個思路:自己寫一個程序調用它的so文件中的這個加密函數。
我們做過NDK開發的都知道,默認情況native方法在so中的JNI_OnLoad函數自動注冊,但是native中的函數必須按照這種格式:Java_類名_方法名,類似這樣:
那么我們就可以在自己的程序中,把app的那個Secret類拷貝過去,不過一定要注意包名一定不能變:
然后在代碼中直接調用native方法:
不過可惜的是,調用的結果,沒有加密字段信息。所以這里我們會發現應該還缺少什么設置。我們回過頭看看java層的代碼:
這里有一個set方法,在之前分析已經發現了,他的調用地方:
這里有一個SecretDataModel類,應該是從網上請求獲取到的數據,然后解析構造出這個類,看看這個類定義:
看到這里,發現已經用了第三方的json解析包,注解直接解析字段值。但是我們全局搜索這個類的話,跟蹤太麻煩了,這里就采用另外一種方式跟蹤代碼,那就是利用Xposed攔截這個類的構造方法,然后在內部打印堆棧信息來查看方法的調用路徑,這種方法我在之前已經用過了。本文能夠更好的體現:
因為應用是多dex文件,所以hook必須先hook他的Application類的attach方法拿到正確的類加載器,正確加載需要hook的類信息,不然就報錯了。這個已經講了很多遍了。然后就是利用自動拋異常來打印方法的調用堆棧信息,安裝運行,重啟生效看日志:
這里看到了,他用google的gson庫解析json數據的,看到了json數據是從下面這兩個方法中傳遞過來的,查看這個類的方法:
點進去進行查看:
為了看到返回的json數據,我們在攔截這個方法,把返回的json數據打印出來看看是啥:
運行模塊,重啟生效,看日志信息:
看到這段json數據了,這時候,在返回去看看SecretDataModel那個調用set方法:
看到這四個參數值,第一個是Context不解釋了,第二個是serverTime字段值,第三個是startCode字段值,第四個是runCode字段值。這三個字段都是可以在上面打印的json中找到的,我們把json格式化看看:
有了這三個值和Context變量,直接調用Secret的native方法set進行設置,看看能否正確獲取到加密之后的字段值:
運行demo程序看看日志信息:
看到了,設置成功了,而且獲取加密字段也成功了。到這里我們就成功的獲取到加密字段s_sg值了。
五、獲取加密配置信息
不過到這里還沒有結束,因為我們發現那三個set值字段從網絡獲取,我們還需要知道是哪個url獲取到的,這里從代碼跟蹤依然很困難,所以我們還需要利用hook來打印方法的堆棧信息來追蹤代碼,通過上面打印的獲取json數據的堆棧信息:
看到是這個類訪問獲取json數據的,進去看看:
而傳入的參數,在進行查看:
看到有一個getUrl方法,就是獲取訪問的url值,我們就可以這么來進行hook操作,打印這個url訪問地址了:
運行模塊,重啟生效,看日志信息:
下面打印了那個我們想要的json數據,上面有幾個url,我們在去Fiddler觀察這幾個url返回的數據,最后定位到這個是這個url返回的數據信息:
六、梳理加密流程
到這里我們就分析完了直播app的協議加密流程,下面來總結一下:
第一步:通過/user/account/token_v2接口獲取加密前的配置信息
第二步:通過native方法把第一步獲取到的信息進行設置(set方法)。
第三步:通過native方法將java層拼接參數的url值進行加密處理返回(encryUrl方法)
那么我們可以這么做,自己協議demo程序,在Java層拼接好參數,然后調用so的native方法,返回還有加密字段的url,然后可以解析出這個字段就是加密信息了。我們就可以批量處理這種網絡請求了。比如刷粉,觀看直播,點贊等操作。當然有的同學會認為這次操作其實不是真正意義上的破解加密算法。的確不算,但是我們弄到我們想要的就好,過程其實沒那么重要,而在這個操作過程中,我們又學習到了很多逆向技巧。
七、逆向技巧總結
第一、在用Jadx打開apk卡死的時候,記得先解壓出dex文件,在用Jadx打開dex文件即可。
第二、對於多dex的應用,使用Xposed進行hook的時候,需要先攔截Application類的attach方法獲取正確的類加載器。不然會報攔截失敗。
第三、當我們在使用Jadx進行全局搜索內容,發現沒有搜索結果的時候,可能需要從以下幾個方面考慮:
- 1、是否包含多個dex文件,可以利用Jadx去打開其他dex文件進行搜索。
- 2、是否存在動態加載插件功能,全局搜索DexClassLoader找到插件加載位置,獲取插件功能包,在用Jadx打開插件包進行搜索。
- 3、是否存在so文件中,可以利用IDA打開so文件,Shift+F12展示so中所有的字符串信息視圖,然后進行搜索。
- 4、是否信息來源於網絡請求返回,比如一些字符串信息展示,有可能是服務器返回的信息。
第四、在我們用Jadx進行代碼跟蹤非常困難的時候,記得還可以利用Xposed攔截指定方法,打印堆棧信息來跟蹤代碼,也是一種高效方法。
第五、當你在使用Jadx右鍵一個方法看看調用路徑,發現沒有結果的時候,那么看看這個方法是否是該類實現的一個接口中的方法或者是抽象方法。去父類或者接口中的那個方法在右鍵看看調用路徑。
第六、在不關心過程,只關心結果的場景下,可以構造一個app來調用程序的so,獲取我們想要的結果,這種方式一定要記住,后面很多場景都會用到。可以用它來嗅探so中一些函數的功能。比如通過調用so中的一個方法,輸入規律數據,看輸出結果是否符合一定規律,通過規律來破解加密算法。
八、總結
本文介紹的內容有點多,感謝該直播app開發者提供這么好的研究樣本,當然最后需要說一句就是:安全防護策略不夠,我們在本文可以看到我們利用調用他的so來獲取加密信息,這個方法是可以用於很多app的,對於那些我們無需關心過程,只關心結果的內容,這種方法屢試不爽。那么作為開發者如何規避這種安全問題呢?很多人第一就想到了:在so的JNI_OnLoad方法中判斷簽名信息是否正確,不正確就直接退出。這個的確可以防范。但是如果用我之前介紹的kstools工具原理,直接hook系統的PMS服務攔截獲取簽名信息方法,返回正確的應用簽名信息,這種防護策略就失效了。所以說:安全不息,逆向不止。兩者都在進步。