安卓動態調試七種武器之離別鉤 – Hooking(下)

来源:http://www.cnblogs.com/alisecurity/archive/2016/06/22/5606796.html
-Advertisement-
Play Games

Android動態調試七武器系列文章——Hooking下篇,分享一些常用或原創的調試工具以及手段,希望能對國內移動安全的研究起到一些催化劑的作用。 ...


0x00 序

隨著移動安全越來越火,各種調試工具也都層出不窮,但因為環境和需求的不同,並沒有工具是萬能的。另外工具是死的,人是活的,如果能搞懂工具的原理再結合上自身的經驗,你也可以創造出屬於自己的調試武器。因此,筆者將會在這一系列文章中分享一些自己經常用或原創的調試工具以及手段,希望能對國內移動安全的研究起到一些催化劑的作用。

 

目錄如下:

安卓動態調試七種武器之長生劍 - Smali Instrumentation
安卓動態調試七種武器之孔雀翎 – Ida Pro
安卓動態調試七種武器之離別鉤 – Hooking (上)
安卓動態調試七種武器之離別鉤 – Hooking (下)
安卓動態調試七種武器之碧玉刀- Customized DVM
安卓動態調試七種武器之多情環- Customized Kernel
安卓動態調試七種武器之霸王槍 - Anti Anti-debugging
安卓動態調試七種武器之拳頭 - Tricks & Summary

 

文章中所有提到的代碼和工具都可以在我的github下載到,地址是: https://github.com/zhengmin1989/TheSevenWeapons

 

0x01 利用函數掛鉤實現native層的hook

我們在離別鉤(上)中已經可以做到動態的載入自定義so文件並且運行so文件中的函數了,但還不能做到hook目標函數,這裡我們需要用到函數掛鉤的技術來做到這一點。函數掛鉤的基本原理是先用mprotect()將原代碼段改成可讀可寫可執行,然後修改原函數入口處的代碼,讓pc指針跳轉到動態載入的so文件中的hook函數中,執行完hook函數以後再讓pc指針跳轉回原本的函數中。

 

用來註入的程式hook5邏輯與之前的hook4相比並沒有太大變化,僅僅少了“調用 dlclose 卸載so文件”這一個步驟,因為我們想要執行的hook後的函數在so中,所以並不需要調用dlclose進行卸載。基本步驟如下:

保存當前寄存器的狀態 -> 獲取目標程式的mmap, dlopen, dlsym, dlclose 地址 -> 調用mmap分配一段記憶體空間用來保存參數信息 –> 調用dlopen載入so文件 -> 調用dlsym找到目標函數地址 -> 使用ptrace_call執行目標函數 -> 恢復寄存器的狀態

hook5的主要代碼邏輯如下:

 

我們知道arm處理器支持兩種指令集,一種是arm指令集,另一種是thumb指令集。所以要hook的函數可能是被編譯成arm指令集的,也有可能是被編譯成thumb指令集的。Thumb指令集可以看作是arm指令壓縮形式的子集,它是為減小代碼量而提出,具有16bit的代碼密度。Thumb指令體系並不完整,只支持通用功能,必要時仍需要使用ARM指令,如進入異常時。需要註意的一點是thumb指令的長度是不固定的,但arm指令是固定的32位長度。

 

為了讓大家更容易的理解hook的原理,我們先只考慮arm指令集,因為arm相比thumb要簡單一點,不需要考慮指令長度的問題。所以我們需要將target和hook的so編譯成arm指令集的形式。怎麼做呢?很簡單,只要在Android.mk中的文件名後面加上”.arm”即可 (真正的文件不用加)。

 

 

確定了指令集以後,我們來看實現掛鉤最重要的邏輯,這個邏輯是在註入後的so里實現的。首先我們需要一個結構體保存彙編代碼和hook地址:

 

 

 

我們接著來看註入的邏輯,最重要的函數為hook_direct(),他有三個參數,一個參數是我們最開始定義的用來保存彙編代碼和hook地址的結構體,第二個是我們要hook的原函數的地址,第三個是我們用來執行hook的函數。函數的源碼如下:

 

雖然android有ASLR,但並沒有PIE,所以program image是固定在0x8000這個地址的,因此我們用mprotect()函數將整個target代碼段變成RWX,這樣我們就能修改函數入口處的代碼了。是否修改成功可以通過cat /proc/[pid]/maps查看:

 

隨後我們需要確定目標函數的地址,這個有兩種方法。如果目標程式本身沒有被strip的話,那些symbol都是存在的,因此可以使用dlopen()和dlsym()等方法來獲取目標函數地址。但很多情況,目標程式都會被strip,特別是可以直接運行的二進位文件預設都會被直接strip。比如target中的sevenWeapons()這個函數名會在編譯的時候去掉,所以我們使用dlsym()的話是無法找到這個函數的。這時候我們就需要使用ida或者objdump來定位一下目標函數的地址。比如我們用objdump找一下target程式裡面sevenWeapons(int number)這個函數的地址:

 

雖然target這個binary被strip了,但還是可以找到sevenWeapons()這個函數的起始地址是在0x84f4。因為”mov r2, r0”就是載入number這個參數的指令,隨後調用了<printf@plt>用來輸出結果。 最後一個參數也就是我們要執行的hook函數的地址。得到這個地址非常簡單,因為是so中的函數,調用hook_direct()的時候直接寫上函數名即可。

 

    hook_direct(&eph,hookaddr,my_sevenWeapons);

 

接下來我們看如何修改函數入口(modify function entry),首先我們保存一下原函數的地址和那個函數的前三條指令。隨後我們把目標函數的第一條指令修改為 LDR pc, [pc, #0],這條指令的意思是跳轉到PC指針所指的地址,由於pc寄存器讀出的值實際上是當前指令地址加8,所以我們把後面兩處指令都保存為hook函數的地址,這樣的話,我們就能控制PC跳轉到hook函數的地址了。

最後我們再調用hook_cacheflush()這個函數來刷新一下指令的緩存。因為雖然前面的操作修改了記憶體中的指令,但有可能被修改的指令已經被緩存起來了,再執行的話,CPU可能會優先執行緩存中的指令,使得修改的指令得不到執行。所以我們需要使用一個隱藏的系統調用來刷新一下緩存。hook_cacheflush()代碼如下:

 

刷新完緩存後,再執行到原函數的時候,pc指針就會跳轉到我們自定義的hook函數中了,hook函數里的代碼如下:

 

首先在hook函數中,我們可以獲得原函數的參數,並且我們可以對原函數的參數進行修改,比如說將數字乘2。隨後我們使用hook_precall(&eph);將原本函數的內容進行還原。hook_precall()內容如下:

 

在hook_precall()中,我們先對原本的三條指令進行還原,然後使用hook_cacheflush()對記憶體進行刷新。經過處理之後,我們就可以執行原來的函數orig_sevenWeapons(number)了。執行完後,如果我們還想再次hook這個函數,就需要調用hook_postcall(&eph)將原本的三條指令再進行一次修改。

下麵我們來使用hook5和libinject2.so來註入一下target這個程式:

 

可以看到經過註入後,我們成功的獲取了參數number的值,並且將”Hello,LiBieGou!”後面的數字變成了原來的兩倍。

 

0x02 使用adbi實現JNI層的hook

我們在上一節中介紹瞭如何hook native層的函數。下麵我們再來講講如何利用adbi來hook JNI層的函數。Adbi是一個android平臺上的一個註入框架,本身是開源的。Hook的原理和我們之前介紹的技術是一樣的,這個框架支持arm和thumb指令集,也支持通過字元串定位symbol函數的地址。

首先我們需要一個例子用來講解,所以我寫了程式叫test2。

 

enter image description here

 

點擊程式中的button後,程式會調用so中的Java_com_mzheng_libiegou_test2_MainActivity_stringFromJNI(JNIEnv* env,jobject thiz,jint a,jint b)函數用來計算a+b的結果。我們預設傳的參數是a=1, b=1。接下來我就來教你如何利用adbi來hook這個JNI函數。

 

因為adbi是一個註入框架,我們下載好源碼後,只要對應著源碼中給的example照貓畫虎即可。Hijack那個文件夾是保存的用來註入的程式,和我們之前講的hook5.c的原理是一樣的,所以不用做任何修改。我們只需要修改example中的代碼,也就是將要註入的so文件的源碼。

 

首先,我們在/adbi-master/instruments/example這個文件夾下新建兩個文件”hookjni.c”和” hookjni_arm.c”。“hookjni_arm.c”其實只是一個殼,用來將hook函數的入口編譯成arm指令集的,內容如下:

 

這個文件的目的僅僅是為了用arm指令集進行編譯,可以看到Android.mk中在”hookjni_arm.c”後面多了個”.arm”:

 

下麵我們來看”hookjni.c”:

 

這段代碼和我上一節講的代碼非常像,my_init()用來進行hook操作,我們需要提供想要hook的so文件名和函數名,然後再提供thumb指令集和arm指令集的hook函數地址。

my_Java_com_mzheng_libiegou_test2_MainActivity_stringFromJNI()就是我們提供的hook函數了。我們在這個hook函數中把a和b都改成了10。除此之外,我們還使用counter這個全局變數來控制hook的次數,這裡我們把counter設置為3,當hook了3次以後,就不再進行hook操作了。

編輯好代碼後,我們只需要在adbi的根目錄下執行” build.sh”進行編譯:

 

編譯好後,我們把hijack和libexample.so拷貝到/data/local/tmp目錄下。然後使用hijack進行註入:

 

然後我們再點擊button就可以看到我們已經成功的修改了a和b的值為10了,最後顯示1+1=20。

 

 

通過cat adbi_example.log我們可以看到hook過程中列印的log:

 

可以看到adbi是通過thumb指令集進行hook的,原因是test2程式是用thumb指令集進行編譯的。其實hook thumb指令集和arm指令集差不多,在”/adbi-master/instruments/base”中可以找到hook thumb指令集的邏輯:

 

其實h->jumpt[20]這個字元數組保存的就是thumb指令集下控制pc指針跳轉到hook函數地址的代碼。Hook完之後的流程就和arm指令集的hook一樣了。

 

0x03 使用Cydia或Xposed實現JAVA層的hook

關於Cydia和Xposed的文章和例子已經很多了,這裡就不再重覆的進行介紹了。這裡推薦一下瘦蛟舞和我寫的文章,基本上就知道怎麼使用這兩個框架了:

 

Android.Hook框架xposed篇(Http流量監控) http://drops.wooyun.org/papers/7488

Android.Hook框架Cydia篇(脫殼機製作) http://drops.wooyun.org/tips/8084

手把手教你當微信運動第一名 – 利用Android Hook進行微信運動作弊 http://drops.wooyun.org/tips/8416

 

個人感覺Xposed框架要做的更好一些,主要原因是Cydia的作者已經很久沒有更新過Cydia框架了,不光有很多bug還不支持ART。但是有很多不錯的調試軟體/插件是基於兩個框架製作的,所以有時候還是需要用到Cyida的。

 

接下來就推薦幾個很實用的基於Cydia和Xposed的插件:

 

1)ZjDroid: ZjDroid是基於Xposed Framewrok的動態逆向分析模塊,逆向分析者可以通過ZjDroid完成以下工作: 1、DEX文件的記憶體dump 2、基於Dalvik關鍵指針的記憶體BackSmali,有效破解主流加固方案 3、敏感API的動態監控 4、指定記憶體區域數據dump 5、獲取應用載入DEX信息。 6、獲取指定DEX文件載入類信息。 7、dump Dalvik java堆信息。 8、在目標進程動態運行lua腳本。 https://github.com/halfkiss/ZjDroid

 

2)XPrivacy: XPrivacy是一款基於Xposed框架的模塊應用,可以對所有應用可能泄露隱私的許可權進行管理,對禁止可能會導致崩潰的應用採取欺騙策略,提供偽造信息,比如說可以偽造手機的IMEI號碼等。 https://github.com/M66B/XPrivacy

 

3)Introspy: Introspy是一款可以追蹤分析移動應用的黑盒測試工具並且可以發現安全問題。這個工具支持很多密碼庫的hook,還支持自定義hook。 https://github.com/iSECPartners/Introspy-Android

 

0x04 Introspy實戰

我們使用alictf上的evilapk400作為例子講解如何利用introspy來調試程式。Evilapk400使用了比較複雜的dex加殼技術,如果不利用基於自定義dalvik的脫殼工具來進行脫殼的話做起來會非常麻煩。但我們如果換一種思路,直接通過動態調試的方法來獲取加密演算法的字元串,key和IV等信息就可以直接獲取答案了。

首先我們安裝cyida.apk,Introspy-Android Config.apk到手機上,然後用eclipse打開“Introspy-Android Core”的源碼增加一個自定義的hook函數。雖然Introspy預設對密碼庫進行了hook,但卻沒有對一些strings的函數進行hook。所以我們手動添加一個對String.equals()的hook:

 

然後我們編譯,生成並安裝Introspy-Android Core.apk到手機上。然後我們安裝上EvilApk400。然後打開Introspy-Android Config勾選com.ali.encryption。

 

 

接著打開evilapk400,然後隨便輸入點內容並點擊登陸。

 

 

然後我們使用adb logcat就能看到Introspy輸出的信息了:

 

通過log,很容易就能看出來evilapk400使用了DES加密。通過log我們獲取了密文,Key以及IV,所以我們可以寫一個python程式來計算出最後的答案:

 

 

0x05 總結

本篇介紹了native層,JNI層以及JAVA層的hook,基本上可以滿足我們平時對於android上hook的需求了。 另外文章中所有提到的代碼和工具都可以在我的github下載到,地址是: https://github.com/zhengmin1989/TheSevenWeapons

 

0x06 參考資料

  1. Android平臺下hook框架adbi的研究(下)http://blog.csdn.net/roland_sun/article/details/36049307
  2. ALICTF Writeups from Dr. Mario

 

作者:蒸米@阿裡聚安全,更多技術文章,請訪問阿裡聚安全博客


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 之前學習swift時的個人筆記,根據github: "the swift programming language in chinese" 學習、總結,將重要的內容提取,加以理解後整理為學習筆記,方便以後查詢用。詳細可以參考 "the swift programming language in ch ...
  • 序言: 個人不善於寫東西,就直奔主題了。 其實今天會註意到多targets這個東西,是因為在學習一個第三方庫FBMemoryProfiler的時候,用到了,所以就搜索了一些相關資料,就在這裡記錄一下。 可能每個人都會遇到這樣的問題,應用上傳的時候,不小心把測試環境的包上傳到了appstore,結果指 ...
  • ====2016年3月21日更新====修改一處預設值的BUG,可以供自己拓展(BWaterflowLayout 可以當作框架靈活應用)基於UICollectionView的瀑布流自定義UICollectionViewLayout實現cell的佈局屬性 [Objective-C] 查看源文件 複製代 ...
  • 安卓請求網路的三種方式 在請求網路的時候一般常用的提交方式是post或者get請求,post請求安全,傳輸大小無限制,但是代碼量多些,get請求是瀏覽器有大小限制,用戶提交的信息在瀏覽器的地址欄顯示出來因此不安全 在Android中聯網請求需要添加許可權,4.0以後需要開啟一個線程,在網路請求的時候都 ...
  • App Store: 天的故事 1. 改回經典圖標和名稱 2. 界面優化,統一風格 3. 今日100載入故事更加智能 4. 性能優化,修複bug App Store: 天的故事 ...
  • 前段時間開發遇到webView 高度自適應問題,用最初的方法無效,找了些資料,記錄下。 1、若網頁中含有< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/x ...
  • 一、什麼是RunLoop? RunLoop是運行迴圈,每個Cocoa應用程式都由一個處於阻塞狀態的do/while迴圈驅動,當有事件發生時,就把事件分派給合適的監聽器,如此反覆直到迴圈停止。處理分派的對象就叫做“運行迴圈”。 基本作用:1、保持程式的持續運行 2、處理App中的各種事件(比如觸摸事件 ...
  • 現實情況如上所示 我出現這種情況的原因有兩種: 其一:沒有給textview對齊方式; 其二:沒有將BOOL類型的“ automaticallyAdjustsScrollViewInsets ”屬性置為yes ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...