摘要:下面我們正式開始嘗試小米推送,首先,找出其業務邏輯中的一個節點。因為小米推送是商業產品,這里不便于探索太多內容,但是通過這個插件可以比較方便的進行類似的研究。
前言
有時候我們在Java開發過程中可能有這樣的需求:需要研究或者修改工程依賴的Jar包中的一些邏輯,查看代碼運行中Jar包代碼內部的取值情況(比如了解SDK與其服務器通信的請求報文加密前的情況)。
這個需求類似于Hook。
但是往往這些依賴的Jar包中的代碼已經被混淆過,刪去了本地變量表和代碼行號等debug信息,所以無法直接斷點調試,其內部邏輯和運行情況也幾乎無法觸及,研究更難以下手。這時候,一般的辦法有二:1.將Jar反解為Java源碼,以module方式引入,便可自由修改調試;2.修改字節碼或者打包后的smali代碼,實現想要的邏輯后再重新打包。這兩種方法中,前者往往十分繁雜,尤其在混淆后邏輯變得極其復雜,幾乎不可能完成;后者也很麻煩,工序較多,修改成本也比較高。
插件:HiBeaverGradle編譯插件hibeaver結合Java AOP編程中對于大名鼎鼎的ASM.jar的應用,和Android gradle 插件提供的最新的Transform API,在Apk編譯環節中、class打包成dex之前,插入了中間環節,依據開發者的配置調用ASM API對項目所依賴的jar進行相應的修改,從而可以比較高效地實現上面的Hook需求。
源碼地址:https://github.com/BryanSharp/hibeaver
(現在hiBeaver已經發布了1.2.7版本,支持輕量級AOP框架設計。)
唯一需要注意的是,運用好這個插件需要有一定的Java匯編指令基礎,并了解基本的ASM3的使用方法:后者還是很簡單的,而前者,關于Java匯編指令基礎這塊,對于事先不了解的同學,接觸起來有一定難度,但是學一學這個其實非常有益處,對于理解Java的運行有很大的幫助。
閑話少說,先看看如何快速實踐一把!關鍵看療效!
關于匯編指令的資料可以參閱本人的文章:大話+圖說:Java匯編指令——只為讓你懂
實戰演練我們就先來嘗試用這個Hook掉小米推送的SDK。
首先,在需要的工程的根項目gradle配置中加入以下內容:
如圖所示,該插件上傳到了jcenter中,只需引入classpath:
classpath "com.bryansharp:HiBeaver:1.2.7"
這里需要注意的是,目前該插件僅支持Android gradle編譯插件2.0及以上的版本。
然后,在你的App項目gradle配置底部或任意位置加入如下代碼:
apply plugin: "hiBeaver" hiBeaver { //turn this on to make it print help content, default value is true showHelp = true //this flag will decide whether the log of the modifying process be printed or not, default value is false keepQuiet = false //this is a kit feature of the plugin, set it true to see the time consume of this build watchTimeConsume = false //this is the most important part modifyMatchMaps = [:] }
然后,重新編譯一下項目,會先去jitpack下載這個插件,開始編譯后可以看到Android Studio的右下角的Gradle Console中,多輸出了以下內容:
如果你看到了和我一樣的內容,那說明初步配置成功。
可以看到,使用插件后會輸出一段友好的幫助內容,還是中英文的,告訴我們可以直接拷貝作為初始配置,這個幫助輸出也是可以關閉的。
下面我們正式開始嘗試Hook小米推送SDK,首先,找出其業務邏輯中的一個節點。
首先,引入小米推送,這個過程不贅述了,blablabla,引入成功!
眾所周知,使用小米推送需要先在代碼中調用如下:
MiPushClient.registerPush(this, APP_ID, APP_KEY);
這個代碼應該會調起本地長連接的建立、注冊服務器等流程。假如我們出于學習的目的,想研究其中的流程,試舉一例,先從查看其反編譯的代碼開始,找一個切入的節點,如下:
首先進入查看MiPushClient.registerPush這個方法:
在initialize的方法中,找到一段邏輯如下:
進入a方法,來到了這個類:com.xiaomi.mipush.sdk.u中,發現:
下面如果我們想看看運行時前兩個方法傳入參數的值,就可以開始Hook了。該如何做呢?這個方法體內打Log輸出所有的值嗎?那樣太麻煩了。我們可以這樣做:
首先在我們項目的源碼里新建一個靜態方法,包含兩個參數,如下圖:
其后,我們只要在a方法中加入一段代碼,調用我們的靜態方法,并傳入我們想查看的兩個參數即可。
這就有賴于我們的hibeaver插件了,具體如何做呢?
我們可以先看看之前的幫助內容:
里面有提到一個the most important par,最重要的部分。沒錯,這個插件的核心就在于配置這個類型為Map
首先我們配置如下:
然后重新編譯,發現輸出log如下:
這樣就輸出這個u類的所有方法信息,用于后面進行配置。
再來看看剛剛的方法a:
是一個泛型方法,眾所周知泛型只存在于編碼階段,編譯后是沒有泛型的,其實傳入的參數的實際類型為org.apache.thrift.a,最終找到其方法描述應該為:
(Lorg/apache/thrift/a;Lcom/xiaomi/xmpush/thrift/a;ZLcom/xiaomi/xmpush/thrift/r;)V
進一步配置:
然后重新編譯,console輸出新增revist部分,如下:
最后,我們增加如下代碼,在其中植入我們的代碼,調用剛剛的靜態方法,并把對應值傳遞過來:
終極配置:
以上代碼就不做詳細解釋了,相信有基礎的都能明白,然后編譯查看輸出:
下面我們debug一下,看看是否可以成功在registerPush的運行流程中調用到我們的方法:
上面可以看到,無論是debug還是log輸出都可以抓到想要的參數了。
因為小米推送是商業產品,這里不便于探索太多內容,但是通過hibeaver這個插件可以比較方便的進行類似的研究。
hibeaver所體現的技術,并沒有特別大的價值,僅僅作為工具來講比較方便易用,有助于學習研究Jar中的邏輯,和學習應用Java匯編碼。除此之外,還有幾個應用場景:1.修改引用SDK中的一些bug或者提高其效率;2.獲得必要的SDK的一些關鍵調用時機,通過hook建立回調;3.欺騙SDK、關閉或減少SDK中不受控制的網絡傳輸。不一而足,還是很有趣、很有想象空間的。
目前存在的問題,如下,這個除了偶爾同步報錯之外沒有影響,編譯正常:
還有,如果僅僅修改了gradle文件,不會觸發更新,需要在代碼上也進行任意修改方生效。
關于項目hibeaver完全開源,大家可以自行查看其中代碼,有大量的中文注釋,對于學習gradle插件開發大有裨益。
github開源項目地址:https://github.com/BryanSharp/hibeaver
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66722.html
摘要:理解本文需要一定的字節碼指令基礎,可以閱讀筆者的另一篇文章大話圖說字節碼指令只為讓你懂利用字節碼插樁技術可以很方便地幫助我們實現很多手術刀式的代碼設計,如無埋點統計上報輕量級等。 理解本文需要一定的Java字節碼指令基礎,可以閱讀筆者的另一篇文章:大話+圖說:Java字節碼指令——只為讓你懂 利用Android字節碼插樁技術可以很方便地幫助我們實現很多手術刀式的代碼設計,如無埋點統計...
摘要:注入機制作為工作的基礎,也為無侵入捕獲應用數據提供可能。代碼注入機制結合和技術,在應用字節碼加載到之前進行字節碼改寫。當然,修改字節碼文件流的動作是在中進行的。 UAVStack的中間件增強框架專題(MOF)】為大家詳細講述UAV中的MOF Agent是如何借助javaagent(premain)和javaassist技術在對應用無侵入的前提下完成數據捕獲的。歡迎繼續關注UAVStac...
閱讀 1211·2023-04-26 02:20
閱讀 3337·2021-11-22 14:45
閱讀 4111·2021-11-17 09:33
閱讀 971·2021-09-06 15:00
閱讀 1479·2021-09-03 10:30
閱讀 3837·2021-07-26 22:01
閱讀 990·2019-08-30 15:54
閱讀 530·2019-08-30 15:43