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,如下:
- /**
- *包裝載入時的回撥
- */
- public void handleLoadPackage(final LoadPackageParam lpparam)
- /**
- *Xposed提供的Hook方法
- *@param className 待Hook的Class
- *@param classLoader ClassLoader
- *@param methodName 待Hook的Method
- *@param paramterTypesAndClassback hook回撥
- */
- Unhook findAndHookMethod(String className,ClassLoader classLoader,String methodName,Object... parameterTypesAndCallback)
3.建立一個InputDemo專案(該專案使用輸入框提示使用者輸入資訊,點選按鈕獲取使用者的資訊並做相關的邏輯),用於模擬Hook目標,通過Xposed獲取使用者輸入資訊(關鍵程式碼和執行如下);
- OK.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- String inPut = Input.getText() + "";
- //獲取使用者輸入,並驗證是否輸入正確
- if (isInputOK(inPut)) {
- Toast.makeText(MainActivity.this, "Input Success", Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(MainActivity.this, "Input Faild", Toast.LENGTH_SHORT).show();
- }
- }
- });
- … …
- private boolean isInputOK(String inPut) {
- if ("123456".equals(inPut)) {
- return true;
- } else {
- return false;
- }
- }
- "1.0" encoding="utf-8" xml version=
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.pengchengxiang.hookdemo">
- <application>
- … …
- <meta-data
- android:name="xposedmodule"
- android:value="true" />
- <!--模組描述-->
- <meta-data
- android:name="xposeddescription"
- android:value="a hook demo" />
- <!--模組版本-->
- <meta-data
- android:name="xposedminversion"
- android:value="30" />
- </application>
- </manifest>
- public class Main implements IXposedHookLoadPackage {
- public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
- if (!loadPackageParam.packageName.equals("com.example.pengchengxiang.inputdemo")) {
- return;
- }
- XposedBridge.log("Loaded app:" + loadPackageParam.packageName);
- //Hook MainActivity類的isInputOK方法,並將該方法的引數輸出至Xposed工具中
- findAndHookMethod("com.example.pengchengxiang.inputdemo.MainActivity", loadPackageParam.classLoader, "isInputOK", String.class, new XC_MethodHook() {
- protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
- XposedBridge.log("hook start");
- XposedBridge.log("param1:" + param.args[0]);
- }
- protected void afterHookedMethod(MethodHookParam param) throws Throwable {
- XposedBridge.log("hook end");
- XposedBridge.log("param1:" + param.args[0]);
- }
- });
- }
- }
注意:在實際應用過程中,你Hook的方法引數可能是目標程式自定義的類,非Android SDK提供,如"com.example.pengchengxiang.inputdemo.Test"。這裡我們可以使用方法XposedHelpers.findClass來獲取引數型別的class物件,如下:
- XposedHelpers.findAndHookMethod("com.example.pengchengxiang.inputdemo.MainActivity", loadPackageParam.classLoader, "isInputOK", String.class,
- XposedHelpers.findClass("com.example.pengchengxiang.inputdemo.Test", loadPackageParam.classLoader), new XC_MethodHook() {...}
com.example.pengchengxiang.hookdemo.Main
7.完成InputDemo和HookDemo並安裝在手機中,在XposedInstaller中啟動我們的自己開發的模組; 8.重新啟動手機,在XposedInstaller中日誌模組,檢視在InputDemo中使用XposedBridge.log輸出的日誌;
提示1:檢視日誌模組,如果報錯如下圖:
處理1:第一,檢查XposedBridgeApi-54.jar是否防在新建的lib目錄下;第二,估計Xposed作者在其框架內部也使用了BridgeApi,使用Provided依賴避免重複引用;