Android Hook (1) Dexposed原理
生活随笔
收集整理的這篇文章主要介紹了
Android Hook (1) Dexposed原理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文地址:http://www.zhaoxiaodan.com/android/Android-Hook(1)-dexposed%E5%8E%9F%E7%90%86.html
dexposed?這個項目相當不錯, 之前就想著怎么動態替換jvm中的代碼, 一直沒有思路; 現在好好學習一下
準備源碼庫
因為dexposed其實是用了dvm和art調用class的方式來做的, 而dvm和art的頭文件什么的在android源碼中, 所以下一份源碼, 具體辦法見上一個博文:?準備android源碼庫
最簡單的hook
Demo1中有個test函數, 在調用hook之前正常返回”11111”; 調用hook之后, 卻返回”newTestMethod”, 被我們給修改了
public class Demo1 {String TAG = "===[hookdemo]===";public static String staticTest(String param1){return "staticTest";}public String test(String param1){return "11111";}public void demo(){String param1 = "param1";Log.d(TAG, "===========before hook test:" + this.test(param1));hook(Demo1.class, "test", "(Ljava/lang/String;)Ljava/lang/String;");Log.d(TAG, "===========after hook test:" + this.test(param1));Log.d(TAG, "===========before hook staticTest:" + this.staticTest(param1));hook(Demo1.class, "staticTest", "(Ljava/lang/String;)Ljava/lang/String;");Log.d(TAG, "===========after hook staticTest:" + this.staticTest(param1));}private native void hook(Class<?> clazzToHook, String methodName, String methodSig); }ndk 中的部分
#include <jni.h> #include "log.h" #include "Dalvik.h"static void showMethodInfo(const Method* method) {//看看method的各個屬性都是啥:LOGD("accessFlags:%d",method->accessFlags);LOGD("clazz->descriptor:%s",method->clazz->descriptor);LOGD("clazz->sourceFile:%s",method->clazz->sourceFile);LOGD("methodIndex:%d",method->methodIndex);LOGD("name:%s",method->name);LOGD("shorty:%s",method->shorty); }/** * 使用jni GetMethodID 方法獲取jmethodID 強制轉為 Method 的hook 方法 示例 */ static void newTestMethod(const u4* args, JValue* pResult,const Method* method, struct Thread* self) {// args 是原來函數的參數數組, 原來test函數只有一個String型參數// 并且要注意, 如果是不是static函數, 下標0 是函數所在類的實例obj// 在dvm中Object, jni 中的jobject 和 java 中的 Object類 都不是同一個東西// String類對應StringObject// 取出參數打印出來看看StringObject* param1 = NULL;if(dvmIsStaticMethod(method))param1 = (StringObject*)args[0];elseparam1 = (StringObject*)args[1];LOGD("param1:%s",dvmCreateCstrFromString(param1));//JValue 是個union ,要返回int 就 pResult->i=1; 返回Object對象就 pResult->l = ojb;// 但是, 在dvm中的Object, jni 中的jobject 和 java 中的 Object類 都不是同一個東西// 所以, 我們這里使用dvm的函數來創建一個StringObject*pResult->l = dvmCreateStringFromCstr("newTestMethod");// 一般情況應該使用宏 : RETURN_XXX(result);return; }extern "C" JNIEXPORT void JNICALL Java_com_zhaoxiaodan_hookdemo_Demo1_hook(JNIEnv *env, jobject instance, jobject clazzToHook,jstring methodName_, jstring methodSig_) {const char *methodName = env->GetStringUTFChars(methodName_, 0);const char *methodSig = env->GetStringUTFChars(methodSig_, 0);jmethodID methodIDToHook = env->GetMethodID((jclass) clazzToHook,methodName,methodSig);// 找不到有可能是個staticif(nullptr == methodIDToHook){env->ExceptionClear();methodIDToHook = env->GetStaticMethodID((jclass) clazzToHook,methodName,methodSig);}if(methodIDToHook != nullptr){//主要在這里替換//jmethodID 在dvm里實際上就是個Method 結構體Method* method = (Method*) methodIDToHook;//看看method的各個屬性都是啥:showMethodInfo(method);//設置Method 的 accessFlags 為 枚舉型// ACC_NATIVE 表示 這個method 切換成了一個native 方法// 這個枚舉 在 dalvik/libdex/DexFile.h// 類似:// ACC_PUBLIC = 0x00000001, // class, field, method, ic// ACC_PRIVATE = 0x00000002, // field, method, ic// ACC_PROTECTED = 0x00000004, // field, method, icSET_METHOD_FLAG(method, ACC_NATIVE);//既然是一個native方法, 那就把 nativeFunc 指針指向我們的hook, 用來替換test的新方法method->nativeFunc = &newTestMethod;// registersSize是函數棧大小, insSize是參數占用大小// 如果是native方法, 就沒有額外開銷了// 所有開銷就是參數占用, 所以把它設置成跟參數占用空間method->registersSize=method->insSize;//未知method->outsSize=0;}env->ReleaseStringUTFChars(methodName_, methodName);env->ReleaseStringUTFChars(methodSig_, methodSig); }運行之后得到:
/===[hookdemo]===﹕ ===========before hook test:11111 /[---hookdemo---]﹕ accessFlags:1 /[---hookdemo---]﹕ clazz->descriptor:Lcom/zhaoxiaodan/hookdemo/MainActivity; /[---hookdemo---]﹕ clazz->sourceFile:MainActivity.java /[---hookdemo---]﹕ methodIndex:334 /[---hookdemo---]﹕ name:test /[---hookdemo---]﹕ shorty:LL /[---hookdemo---]﹕ param1:param1 /===[hookdemo]===﹕ ===========after hook test:newTestMethod /===[hookdemo]===﹕ ===========before hook staticTest:staticTest /dalvikvm﹕ GetMethodID: not returning static method Lcom/zhaoxiaodan/hookdemo/MainActivity;.staticTest (Ljava/lang/String;)Ljava/lang/String; /[---hookdemo---]﹕ accessFlags:9 /[---hookdemo---]﹕ clazz->descriptor:Lcom/zhaoxiaodan/hookdemo/MainActivity; /[---hookdemo---]﹕ clazz->sourceFile:MainActivity.java /[---hookdemo---]﹕ methodIndex:0 /[---hookdemo---]﹕ name:staticTest /[---hookdemo---]﹕ shorty:LL /[---hookdemo---]﹕ param1:param1 /===[hookdemo]===﹕ ===========after hook staticTest:newTestMethod原理就是, Method結構體表示了一個java層函數, 而其中的accessFlags屬性如果是ACC_NATIVE , dvm在call 原java層函數的時候, 則會轉向調用 屬性nativeFunc 所指向的函數
所以我們把不是native的java層函數的accessFlags強制改為ACC_NATIVE, 然后把nativeFunc 指向我們的新函數, 則完成了方法的修改
只不過, 這里使用native方法替換了java層的原方法
參考文章
- 編譯屏障和內存屏障?: 需要設置的 ANDROID_SMP 是啥 ?
- Dalvik虛擬機JNI方法的注冊過程分析
總結
以上是生活随笔為你收集整理的Android Hook (1) Dexposed原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android SO逆向2-实例分析
- 下一篇: Android Hook (2) Jav