<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                之前我們演示過了如何在Java層Hook系統的API方法,但是我們都知道很多安全級別較高的操作我們都不會在Java層來完成,而且Java層很多的API都是通過JNI的方式在Native層完成的,所以對Java層的API方法Hook意義不是很大。本節我們就具體來說說在Android中如何使用CydiaSubstrate框架完成Native層的Hook操作。 #### **CydiaSubstrate框架針對Native層Hook的支持** 對于CydiaSubstrate框架來說,其給我們提供了類似在Java中的API方法,如在Native層的MSJavaHookClassLoad函數(類似Java中的hookClassLoad方法)、MSJavaHookMethod函數(類似Java中的hookMethod)。作者的意圖就是為了讓我們能夠在Native層使用JNI完成Java函數的Hook。其中兩個函數的具體定義如下: ~~~ /** * 通過JNI Hook Java中的ClassLoad * * @jni jni指針 * @name 待Hook的類,字符串形式 * @callback Hook后的回調 * @data 自定義參數數據 */ voidMSJavaHookClassLoad(JNIEnv *jni, constchar*name, void(*callback)(JNIEnv *, jclass, void *), void *data); /** * 通過JNI Hook Java中的指定方法 * * @jni jni指針 * @_class jclass * @methodId 待Hook方法ID * @hook Hook后待替換的函數 * @old Hook前原函數的指針 */ voidMSJavaHookMethod(JNIEnv *jni, jclass _class, jmethodID methodId, void *hook, void **old); ~~~ 上述的兩個函數確實比較有用,但是卻不是我們最想要的結果。在Native層Hook我們還是希望針對原生函數進行Hook操作。其實針對Native層的Hook原理,我們在本章的開頭已經給各位讀者介紹了。CydiaSubstrate只是針對其做了一個良好的封裝操作,讓我們更方便地使用。下面是CydiaSubstrate框架提供的Hook函數方法。 ~~~ /** 根據具體的地址路徑加載動態庫 * 類似于dlopen * * @return 動態庫ImageRef */ MSImageRef MSGetImageByName(constchar *file); /** * 根據指定庫找到其中函數的偏移量 * 類似于dlsym * * @image 指定的動態庫 * @name 指定函數的名稱 * @return 指定函數的指針(兼容ARM/Thumb)找不到返回NULL */ void *MSFindSymbol(MSImageRef image, constchar *name); /** * Hook Native層中的指定函數 * * @symbol 待Hook函數指針 * @hook Hook后待替換的函數指針 * @old Hook前函數指針 */ voidMSHookFunction(void *symbol, void *hook, void **old); ~~~ 看到上面的函數說明估計讀者們都躍躍欲試了,而且相信很多讀者已經能夠猜出如何使用CydiaSubstrate框架了。下面我們還是詳細地說明一下,除了了解其提供的API函數之外,使用CydiaSubstrate框架還需要注意的一些注意事項。 * 基于CydiaSubstrate框架的動態庫必須以“.cy.so”(系統默認是“.so”)作為后綴。 * 在AndroidManifest.xml文件中需要聲明cydia.permission.SUBSTRATE權限。 * 需要在Native C/CPP方法前添加Config配置。 ~~~ MSConfig(MSFilterExecutable, "/system/bin/app_process") ~~~ #### **通過JNI改變系統顏色** 與之前的嘗試Hook系統API小節一樣,如我們希望完成Hook Android系統中的Resources類,并將系統中的顏色都改為紫羅蘭色。思路也是一樣的,我們只需要拿到系統中Resources類的getColor方法,將其返回值做修改即可。那么我們使用原生方法實現,需要完成以下幾個步驟。 **1.在AndroidManifest.xml中聲明權限與安裝方式** 因為是系統組件代碼,我們需要設置其安裝方式是internalOnly與hasCode=“false”,這樣能夠方便CydiaSubstrate框架獲取我們的邏輯。當然還需要聲明SUBSTRATE權限,具體的操作如下AndroidManifest.xml內容所示。 ~~~ <?xml version="1.0" encoding="utf-8"?> <!-- internalOnly 系統內部安裝,禁止安裝到sd卡 --> <manifest xmlns:android="http://schemas.android.com/apk/res/android"   package="com.example.hooknative"   android:installLocation="internalOnly"   android:versionCode="1"   android:versionName="1.0" > <!-- 聲明Substrate權限 --> <uses-permission android:name="cydia.permission.SUBSTRATE" /> <uses-sdk     android:minSdkVersion="8"     android:targetSdkVersion="21" /> <!-- hasCode=false,系統組件,不運行APP中的邏輯 --> <application android:hasCode="false" > </application> </manifest> ~~~ **2.新創建項目的cpp文件,導入所需的庫** 這里我們新創建一個原生代碼文件HookNative.cy.cpp(后綴必須為.cy.cpp,編譯后則會出現.cy.so文件),并將CydiaSubstrate的庫文件libsubstrate.so、libsubstrate-dvm.so、substrate.h一起復制到jni目錄下(這里需要根據不同平臺選擇,我們這里選擇的是ARM平臺的庫),jni目錄如圖8-20所示。 ![](https://box.kancloud.cn/9f16d304e5640f64412ff74f043d8b7d_216x225.png) 當然,我們還需要編寫Makefile文件Android.mk,指定Substrate庫參與編譯,并引入一些必要的庫。內容如下所示。 ~~~ LOCAL_PATH := $(call my-dir) # substrate-dvm 庫 include $(CLEAR_VARS) LOCAL_MODULE:= substrate-dvm LOCAL_SRC_FILES := libsubstrate-dvm.so include $(PREBUILT_SHARED_LIBRARY) # substrate 庫 include $(CLEAR_VARS) LOCAL_MODULE:= substrate LOCAL_SRC_FILES := libsubstrate.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE  := HookNative.cy LOCAL_SRC_FILES := HookNative.cy.cpp LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib -llog LOCAL_LDLIBS+= -L$(LOCAL_PATH) -lsubstrate-dvm -lsubstrate include $(BUILD_SHARED_LIBRARY) ~~~ **3.載入配置文件與CydiaSubstrate入口** 在HookNative.cy.cpp代碼文件中,使用CydiaSubstrate框架的API,還需要在其中聲明一些東西,如MSConfig配置app_process的路徑,聲明MSInitialize作為一個CydiaSubstrate插件的入口。我們還會應用一些開發中必要的頭文件與LOG聲明,如這里我們的HookNative.cy.cpp內容為: ~~~ #include<android/log.h> #include<substrate.h> #define LOG_TAG "native_hook" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) // 載入配置文件 MSConfig(MSFilterExecutable, "/system/bin/app_process") // Cydia初始化入口 MSInitialize { } ~~~ **4.Hook并替換其方法** 其修改方法與上一節的Hook Java中的方法類似,我們只需要修改相關的函數完成Hook即可。如這里我們使用MSJavaHookClassLoad方法Hook系統的Resources類,并使用MSJavaHookMethod方法Hook其getColor方法,替換其方法。具體實現如下所示。 ~~~ #include<android/log.h> #include<substrate.h> #define LOG_TAG "native_hook" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) // 載入配置文件 MSConfig(MSFilterExecutable, "/system/bin/app_process") // getColor方法Hook前原函數指針 static jint (*_Resources$getColor)(JNIEnv *jni, jobject _this, ...); // getColor方法Hook后被替換的函數 static jint $Resources$getColor(JNIEnv *jni, jobject _this, jint rid) {   jint color = _Resources$getColor(jni, _this, rid); returncolor & ~0x0000ff00 | 0x00ff0000; } // Hook住Resources class的回調 static void OnResources(JNIEnv *jni, jclass resources, void*data) {   // hook其對應的getColor方法   jmethodID method = jni->GetMethodID(resources, "getColor", "(I)I"); if(method != NULL)     MSJavaHookMethod(jni, resources, method, &$Resources$getColor, &_Resources$getColor); } // Cydia初始化入口 MSInitialize {   // Hook Java中的Resources   MSJavaHookClassLoad(NULL, "android/content/res/Resources", &OnResources); } ~~~ **5.編譯、安裝、重啟驗證** 同樣,因為CydiaSubstrate是Hook Zygote進程,而且我們Hook的又是系統的Resources方法,所以我們希望驗證都需要重啟一下設備。我們可以選擇CydiaSubstrate中的軟重啟,這里我們對系統的設置頁面Hook前后都做了一個截圖,對比截圖如圖8-21所示。 :-: ![](https://box.kancloud.cn/72911d31dee8ed23679acac5457549a5_297x408.png) ![](https://box.kancloud.cn/7adf439edb2251ce81c61001112bac63_293x450.png) 本例中我們繼續之前Java中Hook的思想,完成了在原生代碼中使用JNI針對Java中的API進行Hook操作。因為CydiaSubstrate框架中的hookClassLoad方法、hookMethod方法底層實現也是如此,所以我們使用起來很類似。 #### **Hook后替換指定應用中的原生方法** 討論了太久的Java層面的API Hook工作,也舉了很多例子,本節中我們就看看如何使用CydiaSubstrate框架完成原生函數的Hook。 例如,現在我們有一個應用程序(包名為:com.example. testndklib),其主要功能就是按下界面上的“test”按鈕后,通過JNI調用Native的test函數,在系統的Log中輸入一個當前我有多少錢的整數值。界面如圖8-22所示。 :-: ![](https://box.kancloud.cn/76024283411ef6eaa9ed010dd92143e2_337x452.png) 使用JNI調用的test函數,寫在NDK庫testNDKlib中,會調用一個名叫getMoney的函數,顯示我當前有多少錢。當然,這里我們直接硬編碼了,返回值為100的整數。中間,我們還將 getMoney 函數的地址通過 Log 打印出來。testNDKlib.cpp內容如下所示。 ~~~ #include<stdio.h> #include<jni.h> #include<android/log.h> extern"C" { #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "cydia_native", __VA_ARGS__) /** * 測試函數getMoney,返回一個整數 */ int getMoney(void) {   // 打印方法函數地址   LOGI(" getMoney() function address in : %p\n", &getMoney);   return100; } // 一個JNI的test函數 jstring Java_com_example_testndklib_MainActivity_test(JNIEnv* env,     jobject thiz) {   LOGI(" I have %d money.\n", getMoney());   return0; } } ~~~ 運行一下程序,單擊“test”按鈕,拿到了系統輸出的 Log,與我們輸出的預期一樣。筆者將DDMS上輸出的Log截圖,如圖8-23所示。 :-: ![](https://box.kancloud.cn/f0b0ae64df0d509754cebd04658cb0b6_644x112.png) 現在我們希望Hook此so文件,找到其中的getMoney函數,替換它讓它給我們返回整數值999999(類似一個游戲修改金幣的外掛)。針對之前我們討論的Hook的原理,我們需要做如下幾步操作。 1. 加載原生庫,libtestNDKlib.so。 2. 找到對應的函數符號地址,MSFindSymbol。 3. 替換函數,MSHookFunction。 這里我們在完成1、2步驟的時候,我們同時也用dlopen與dlsym方式實現給大家演示一下。之前的環境配置邏輯以及權限聲明邏輯與上一個例子類似,這里我們不做贅述,直接看一下cpp文件中的內容,具體如下: ~~~ #include<android/log.h> #include<substrate.h> #include<stdio.h> #define LOG_TAG "cydia_native" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) // 初始化CydiaSubstrate MSConfig(MSFilterExecutable, "/system/bin/app_process") // 原函數指針 int (*original_getMoney)(void); /** * 替換后的函數 */ int replaced_getMoney(void) {   LOGI(" replaced_getMoney() function address in : %p\n", &replaced_getMoney);   return999999; } /** * * 找到指定鏈接庫中的函數地址 * * @libraryname 鏈接庫地址 * @symbolname 函數名 * @return 對應的函數地址 */ void* lookup_symbol(char* libraryname, char* symbolname) {   // dlopen打開指定庫,獲得句柄   void*imagehandle = dlopen(libraryname, RTLD_GLOBAL | RTLD_NOW);   if(imagehandle != NULL) {     // 獲得具體函數     void* sym = dlsym(imagehandle, symbolname);     if(sym != NULL) {       returnsym;     } else{       LOGI("(lookup_symbol) dlsym didn't work");       returnNULL;     }   } else{     LOGI("(lookup_symbol) dlerror: %s", dlerror());     returnNULL;   } } //初始化 MSInitialize {   // 獲得libtestNDKlib.so動態庫中getMoney函數的地址   MSImageRef image;   image = MSGetImageByName(       "/data/data/com.example.testndklib/lib/libtestNDKlib.so");   void* getAgeSym = MSFindSymbol(image, "getMoney");   // MSImageRef與 MSFindSymbol 也可以寫為如下所示找到getMoney函數的地址   //   // void * getAgeSym = lookup_symbol(   //     "/data/data/com.example.testndklib/lib/libtestNDKlib.so",   //     "getMoney");   // 將getMoney函數替換為 replaced_getMoney函數   MSHookFunction(getAgeSym, (void*) &replaced_getMoney,       (void**) &original_getMoney); } ~~~ 編譯后安裝到已經安裝了CydiaSubstrate框架的系統中,重啟Android設備。如果在整個系統編譯與配置沒有什么錯誤的情況下,我們發現CydiaSubstrate框架會打出Log說Loding什么什么 so 文件了。這里我們看見,LodinglibnativeHook.cy.so 說明我們之前開發的 Hook 其中的getMoney方法已經生效了,如圖8-24所示。 :-: ![](https://box.kancloud.cn/30c30d4780bd978136494c89454b1046_589x128.png) 這個時候我們繼續運行程序,進入我們剛才的test應用程序。單擊“test”按鈕,獲取調用JNI中的test函數打印我有多少錢。我們能夠在DDMS中清楚地看到,getMoney函數已經被一個名為“replace_getMoney”的函數替換了,其地址也已經被替換了。我們也看到使用替換后的值輸出為“I have 999999 money”,如圖8-25所示 :-: ![](https://box.kancloud.cn/c3a66c41a6c8cba3ed8a1c36b8c567df_516x92.png) #### **使用Hook進行廣告攔截** 對于Android操作系統我們知道,Java層都是建立在原生C/C++語言上的,特別是針對一些系統級別的API函數。上面我們演示了如何對用戶自定義函數進行Hook,下面我們演示一下如何對Native層的系統API進行Hook。 如這里我們希望對系統中的網絡請求API進行Hook,然后過濾掉一些廣告相關的請求,完成廣告攔截功能,其具體的流程如圖8-26所示。 :-: ![](https://box.kancloud.cn/6ba75dad6dbb3d6ac41cb633e1924725_487x448.png) 這里我們查看Android操作系統的POSIX定義的源碼Poxis.Java文件,發現其針對網絡請求函數的定義是在native完成的,如圖8-27所示。 :-: ![](https://box.kancloud.cn/c8eb9436a9ab5f590fabe48331631bae_651x224.png) 對于此類的問題,我們就不得不在native完成Hook與函數替換工作了。所以我們還是使用CydiaSubstrate框架,對系統的API函數connect進行Hook與替換。如下代碼所示,我們使用MSHookFunction對native層中的connect函數進行Hook替換至newConnect函數。 ~~~ #define LOG_TAG "cydia_native" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) // 初始化CydiaSubstrate MSConfig(MSFilterExecutable, "/system/bin/app_process") // 原connect函數指針 int *(*oldConnect)(int,const sockaddr *, socklen_t); int *newConnect(int socket, const sockaddr *address, socklen_t length) {   char ip[128] = { 0 };   int port = -1;   if(address->sa_family == AF_INET) {     sockaddr_in *address_in = (sockaddr_in*) address;     // 獲取 ip     inet_ntop(AF_INET, (void*) (structsockaddr*) &address_in->sin_addr, ip,128);     // 獲取端口     port = ntohs(address_in->sin_port);     // 過濾掉172.22.156.129的請求     if(strcmp(ip, "172.22.156.129") == 0) {       LOGI("發現廣告請求");       struct sockaddr_in my_addr;       int my_len = sizeof(struct sockaddr_in);       bzero(&my_addr, sizeof(my_addr));       my_addr.sin_family = AF_INET;       my_addr.sin_port = htons(80);       my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");       return oldConnect(socket, (const sockaddr*) &my_addr, sizeof(my_addr));     }     return oldConnect(socket, address, length);   } } //初始化 MSInitialize{   MSHookFunction((void*) &connect, (void*) &newConnect,(void**) &oldConnect); } ~~~ 這里我們只是簡單地將IP為172.22.156.129的請求重定向到本地127.0.0.1,即讓類似的廣告請求拿不到數據。此類方式的廣告過濾屬于比較原始暴力類型的過濾方法,但卻也簡單有效。熟悉connect的讀者應該會發現,如果已經能夠替換掉connect函數,其實我們能做到的事情遠遠比攔截一個廣告請求大得多,比如跳轉至釣魚網站,收集私密發送數據等。 #### **參考文章:** [《Android安全技術揭秘與防范》—第8章8.4節Hook原生應用程序](https://yq.aliyun.com/articles/99873?spm=5176.100239.blogcont99909.21.6fd61614MywzAl#)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看