1. 程式人生 > >Android安全:Hook技術

Android安全:Hook技術

原址

一、Hook技術 
1.Hook英文翻譯為“鉤子”,而鉤子就是在事件傳送到終點前截獲並監控事件的傳輸,像個鉤子鉤上事件一樣,並且能夠在鉤上事件時,處理一些自己特定的事件; 
2.Hook使它能夠將自己的程式碼“融入”被勾住(Hook)的程序中,成為目標程序的一部分; 
3.在Andorid沙箱機制下,Hook是我們能通過一個程式改變其他程式某些行為得以實現; 
二、Hook分類 
1.根據Android開發模式,Native模式(C/C++)和Java模式(Java)區分,在Android平臺上 
  Java層級的Hook; 
  Native層級的Hook; 
2.根Hook物件與Hook後處理事件方式不同,Hook還分為: 
  訊息Hook; 
  API Hook; 
3.針對Hook的不同程序上來說,還可以分為: 
  全域性Hook; 
  單個程序Hook; 
三、Hook原理 


Hook技術本質是函式呼叫,由於處於Linux使用者狀態,每個程序有自己獨立的程序控制元件,所以必須先注入所要Hook的程序空間,修改其記憶體中程序程式碼,替換過程表的符號地址,通過ptrace函式附加程序,向遠端程序注入so庫,從而達到監控以及遠端程序關鍵函式掛鉤; 
四、Hook工作流程 
1.Android相關核心函式: 
  ptrace函式:跟蹤一個目標程序,結束跟蹤一個目標程序,獲取記憶體位元組,像記憶體寫入地址; 
  dlopen函式:以指定模式開啟指定的動態連結庫檔案; 
  mmap函式:分配一段臨時的記憶體來完成程式碼的存放; 
2.向目標程序注入程式碼總結後的步驟分為以下幾步: 
  用ptrace函式attch上目標程序; 
  發現裝載共享庫so函式; 
  裝載指定的.so; 
  讓目標程序的執行流程跳轉到注入的程式碼執行; 
  使用ptrace函式的detach釋放目標整合; 
五、常用Hook工具-Xposed框架
 
1.Xposed框架是一款可以在不修改APK的情況下影響程式執行(修改系統)的框架服務; 
2.通過替換/system/bin/app_process程式控制zygote程序,使app_process在啟動過程中載入XposedBridge.jar這個jar包,從而完成對Zygote程序及其建立的Dalvik虛擬機器的劫持; 
六、Xposed框架安裝 
1.從官方網站(http://repo.xposed.info/module/de.robv.android.xposed.installer),下載de.robv.android.xposed.installer_v33_36570c.apk,安裝本地服務XposedInstaller; 
2.安裝進入到XposedInstaller應用程式,“框架”模組出現“未啟用”提示; 

3.點選“框架”,進入到需要啟用框架的介面,我們點選“安裝/更新”就能完成框架的激活了,因為安裝時會需要Root許可權(下載相關工具如“Root精靈”),安裝後會啟動Xposed的app_process,所以安裝過程會存在裝置多次重啟(安裝過程如下圖); 
正在安裝(下載): 

獲取Root許可權(授權Root許可權提示,並確定): 

安裝完成(安裝完成提示重啟): 

安裝成功(框架模組啟用提示消失,即安裝成功): 

七、Xposed框架模組安裝 
1.Xposed框架內建了下載功能,我們只需要在下載模組點選之後,進行瀏覽、下載、搜尋即可; 

2.預設按照時間排序,你可以點選放大鏡圖示,進行搜尋如(XuiMod,一款專門用於狀態列和置頂電池模組); 
搜尋XuiMod模組: 

3.點選搜尋到的模組,可以檢視到該模組的描述資訊,版本資訊。在版本資訊模組下進行模組的下載安裝; 
XuiMod描述資訊: 

XuiMod版本資訊,點選下載相關模組: 

下載完成,點選“安裝”進行安裝: 

安裝完成後,進入“模組”,啟用下載安裝的模組,重啟生效: 

重啟後,長按XuiMod進入到模組執行介面,進行相關的操作,重啟生效(如下圖,手機頂部開啟電源充電,居中,充電動畫功能): 

八、Xposed自定義模組開發 
上個段落,我們講解下如何下載、安裝和使用Xposed模組。那麼我們如何根據自己的需求,自己開發一個Xposed模組,下面我們就介紹下相關流程: 
1.下載XposedBridgeApi-<version>.jar(http://forum.xda-developers.com/xposed/xposed-api-changelog-developer-news-t2714067)檔案,使用者提供Hook相關的API,如下: 

  1. /**
  2. *包裝載入時的回撥
  3. */
  4. public void handleLoadPackage(final LoadPackageParam lpparam)
  5. /**
  6. *Xposed提供的Hook方法
  7. *@param className 待Hook的Class
  8. *@param classLoader ClassLoader
  9. *@param methodName 待Hook的Method
  10. *@param paramterTypesAndClassback hook回撥
  11. */
  12. Unhook findAndHookMethod(String className,ClassLoader classLoader,String methodName,Object... parameterTypesAndCallback)
2.建立一個Android Project HookDemo,在專案app目錄下建立lib目錄(如果將jar包放置到libs目錄下,可能會產生錯誤,估計Xposed作者在其框架內部也引用了BrideApi,這樣操作能避免重複),將jar包放置到lib目錄(不是專案本身的libs目錄)下,選擇jar包->右鍵->Add As Library將這個jar包新增到BuildPATH; 

3.建立一個InputDemo專案(該專案使用輸入框提示使用者輸入資訊,點選按鈕獲取使用者的資訊並做相關的邏輯),用於模擬Hook目標,通過Xposed獲取使用者輸入資訊(關鍵程式碼和執行如下); 

  1. OK.setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. String inPut = Input.getText() + "";
  5. //獲取使用者輸入,並驗證是否輸入正確
  6. if (isInputOK(inPut)) {
  7. Toast.makeText(MainActivity.this, "Input Success", Toast.LENGTH_SHORT).show();
  8. } else {
  9. Toast.makeText(MainActivity.this, "Input Faild", Toast.LENGTH_SHORT).show();
  10. }
  11. }
  12. });
  13. … …
  14. private boolean isInputOK(String inPut) {
  15. if ("123456".equals(inPut)) {
  16. return true;
  17. } else {
  18. return false;
  19. }
  20. }
4.在HookDemo專案中,修改AndroidManifest.xml檔案中配置外掛的名稱和Api版本號; 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3. package="com.example.pengchengxiang.hookdemo">
  4. <application>
  5. … …
  6. <meta-data
  7. android:name="xposedmodule"
  8. android:value="true" />
  9. <!--模組描述-->
  10. <meta-data
  11. android:name="xposeddescription"
  12. android:value="a hook demo" />
  13. <!--模組版本-->
  14. <meta-data
  15. android:name="xposedminversion"
  16. android:value="30" />
  17. </application>
  18. </manifest>
5.建立一個入口類繼承並實現IXposedHookLoadPackage介面,使用findAndHookMethod方法Hook輸入資訊;  
  1. public class Main implements IXposedHookLoadPackage {
  2. @Override
  3. public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
  4. if (!loadPackageParam.packageName.equals("com.example.pengchengxiang.inputdemo")) {
  5. return;
  6. }
  7. XposedBridge.log("Loaded app:" + loadPackageParam.packageName);
  8. //Hook MainActivity類的isInputOK方法,並將該方法的引數輸出至Xposed工具中
  9. findAndHookMethod("com.example.pengchengxiang.inputdemo.MainActivity", loadPackageParam.classLoader, "isInputOK", String.class, new XC_MethodHook() {
  10. @Override
  11. protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
  12. XposedBridge.log("hook start");
  13. XposedBridge.log("param1:" + param.args[0]);
  14. }
  15. @Override
  16. protected void afterHookedMethod(MethodHookParam param) throws Throwable {
  17. XposedBridge.log("hook end");
  18. XposedBridge.log("param1:" + param.args[0]);
  19. }
  20. });
  21. }
  22. }

注意:在實際應用過程中,你Hook的方法引數可能是目標程式自定義的類,非Android SDK提供,如"com.example.pengchengxiang.inputdemo.Test"。這裡我們可以使用方法XposedHelpers.findClass來獲取引數型別的class物件,如下:

  1. XposedHelpers.findAndHookMethod("com.example.pengchengxiang.inputdemo.MainActivity", loadPackageParam.classLoader, "isInputOK", String.class,
  2. XposedHelpers.findClass("com.example.pengchengxiang.inputdemo.Test", loadPackageParam.classLoader), new XC_MethodHook() {...}
6.宣告主入口路徑,在assets資料夾中建立xposed_init檔案,並在其中宣告主入口類; 
com.example.pengchengxiang.hookdemo.Main
7.完成InputDemo和HookDemo並安裝在手機中,在XposedInstaller中啟動我們的自己開發的模組; 

8.重新啟動手機,在XposedInstaller中日誌模組,檢視在InputDemo中使用XposedBridge.log輸出的日誌; 


提示1:檢視日誌模組,如果報錯如下圖: 

處理1:第一,檢查XposedBridgeApi-54.jar是否防在新建的lib目錄下;第二,估計Xposed作者在其框架內部也使用了BridgeApi,使用Provided依賴避免重複引用;