生活随笔
收集整理的這篇文章主要介紹了
Android Hook Java的的一个改进版本
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄(?)[-]
Hook Java的的一個改進版本改進點一更簡單地修改java方法為本地方法改進點二方法回調避免線程安全問題最后
Hook Java的的一個改進版本
《注入安卓進程,并Hook java世界的方法》這篇好文相信大家都看這,里面所提到的方法估計大家也都試過。不過里面的所用的方法,我發現有兩個可以改進的地方。
改進點一:更簡單地修改java方法為本地方法
[cpp] view plain
copy ...????????????int?argsSize?=?calcMethodArgsSize(method->shorty);??????if?(!dvmIsStaticMethod(method))??????????argsSize++;??????????SET_METHOD_FLAG(method,?ACC_NATIVE);??????method->registersSize?=?method->insSize?=?argsSize;??????method->outsSize?=?0;??????method->jniArgInfo?=?dvmComputeJniArgInfo(method->shorty);????????????????method->insns?=?(u2*)info;????????????????method->nativeFunc?=?method_handler;??????LOGI("[+]?%s->%s?was?hooked\n",?classDesc,?methodName);??????...?? 直接把method->nativeFunc即可,無需重新調用JNIEnv的RegisterNatives方法,其中method_handler可以是下面兩種形式之一:
[cpp] view plain
copy typedef?void?(*DalvikBridgeFunc)(const?u4*?args,?JValue*?pResult,?const?Method*?method,?struct?Thread*?self);??typedef?void?(*DalvikNativeFunc)(const?u4*?args,?JValue*?pResult);?? 這樣有一個好處,就是所有java方法都可以統一指向同一個native func,而不需要像為每一個java method方法指定一個native func。
改進點二:方法回調避免線程安全問題
原來的方法,是這樣的
[cpp] view plain
copy ????uint?mlen?=?sizeof(Method);????Method?*oldMeth?=?(Method*)malloc(mlen);????memcpy(oldMeth,method,mlen);????info->odlMethod?=?oldMeth;????info->curMethod?=?method;????????????memcpy(hi->curMethod,hi->odlMethod,mlen);????jmethodID?om?=?(jmethodID)hi->curMethod;????jenv->CallVoidMethod(me,om,gDevice_Sensors);????ClassMethodHook(jenv,&baiduhookInfos[0]);?? 這個方法,其實是有線程安全問題的,其中在dalvik中,有很多方法可以直接調用Method對象,比如dvmCallMethod, dvmCallMethodA, dvmCallMethodV,dvmInvokeMethod等等。針對DalvikBridgeFunc和DalvikNativeFunc的參數,我最后選擇使用dvmInvokeMethod,這個函數的原型是這樣的:
[cpp] view plain
copy Object*?dvmInvokeMethod(Object*?obj,?const?Method*?method,?ArrayObject*?argList,?ArrayObject*?params,?ClassObject*?returnType,?bool?noAccessCheck)?? 其中,obj是this或者null(如果是static方法),method可以直接使用hook之前copy的對象,比較麻煩是argList,params和returnType的獲取。獲取argList的方法,我在Proxy.cpp中到了現成的boxMethodArgs方法,而returnType通過Reflect.h中dvmGetBoxedReturnType的方法也可以獲取,而剩下的params只能自己寫代碼了,下面是我的代碼:
[cpp] view plain
copy STATIC?ArrayObject*?dvmGetMethodParamTypes(const?Method*?method,?const?char*?methodsig){????????????size_t?argCount?=?dexProtoGetParameterCount(&method->prototype);??????STATIC?ClassObject*?java_lang_object_array?=?dvmFindSystemClass("[Ljava/lang/Object;");????????????????ArrayObject*?argTypes?=?dvmAllocArrayByClass(java_lang_object_array,?argCount,?ALLOC_DEFAULT);??????if(argTypes?==?NULL){??????????return?NULL;??????}??????????Object**?argObjects?=?(Object**)?argTypes->contents;??????const?char?*desc?=?(const?char?*)(strchr(methodsig,?'(')?+?1);??????????????????size_t?desc_index?=?0;??????size_t?arg_index?=?0;??????bool?isArray?=?false;??????char?descChar?=?desc[desc_index];??????????while?(descChar?!=?')')?{??????????????switch?(descChar)?{??????????case?'Z':??????????case?'C':??????????case?'F':??????????case?'B':??????????case?'S':??????????case?'I':??????????case?'D':??????????case?'J':??????????????if(!isArray){??????????????????argObjects[arg_index++]?=?dvmFindPrimitiveClass(descChar);??????????????????isArray?=?false;??????????????}else{??????????????????char?buf[3]?=?{0};??????????????????memcpy(buf,?desc?+?desc_index?-?1,?2);??????????????????argObjects[arg_index++]?=?dvmFindSystemClass(buf);??????????????}??????????????????desc_index++;??????????????break;??????????????case?'[':??????????????isArray?=?true;??????????????desc_index++;??????????????break;??????????????case?'L':??????????????int?s_pos?=?desc_index,?e_pos?=?desc_index;??????????????while(desc[++e_pos]?!=?';');??????????????s_pos?=?isArray???s_pos?-?1?:?s_pos;??????????????isArray?=?false;??????????????????size_t?len?=?e_pos?-?s_pos?+?1;??????????????char?buf[128]?=?{?0?};??????????????memcpy((void?*)buf,?(const?void?*)(desc?+?s_pos),?len);??????????????argObjects[arg_index++]?=?dvmFindClass(buf);??????????????desc_index?=?e_pos?+?1;??????????????break;??????????}??????????????descChar?=?desc[desc_index];??????}??????????return?argTypes;??}?? 通過上面幾個類型的獲取之后,最后再看一下整個method hook的實現,過程其實大同小異,不過直接把上述提及的向種類型信息預先獲取并保存到method->insns里頭了:
[cpp] view plain
copy extern?int?__attribute__?((visibility?("hidden")))?dalvik_java_method_hook(JNIEnv*?env,?HookInfo?*info)?{??????const?char*?classDesc?=?info->classDesc;??????const?char*?methodName?=?info->methodName;??????const?char*?methodSig?=?info->methodSig;??????const?bool?isStaticMethod?=?info->isStaticMethod;??????????jclass?classObj?=?dvmFindJNIClass(env,?classDesc);??????if?(classObj?==?NULL)?{??????????LOGE("[-]?%s?class?not?found",?classDesc);??????????return?-1;??????}??????????jmethodID?methodId?=??????????????isStaticMethod????????????????????????env->GetStaticMethodID(classObj,?methodName,?methodSig)?:??????????????????????env->GetMethodID(classObj,?methodName,?methodSig);??????????if?(methodId?==?NULL)?{??????????LOGE("[-]?%s->%s?method?not?found",?classDesc,?methodName);??????????return?-1;??????}????????????????????Method*?method?=?(Method*)?methodId;??????if(method->nativeFunc?==?method_handler){??????????LOGW("[*]?%s->%s?method?had?been?hooked",?classDesc,?methodName);??????????return?-1;??????}??????Method*?bakMethod?=?(Method*)?malloc(sizeof(Method));??????memcpy(bakMethod,?method,?sizeof(Method));????????????????info->originalMethod?=?(void?*)bakMethod;??????info->returnType?=?(void?*)dvmGetBoxedReturnType(bakMethod);??????info->paramTypes?=?dvmGetMethodParamTypes(bakMethod,?info->methodSig);????????????????int?argsSize?=?calcMethodArgsSize(method->shorty);??????if?(!dvmIsStaticMethod(method))??????????argsSize++;??????????SET_METHOD_FLAG(method,?ACC_NATIVE);??????method->registersSize?=?method->insSize?=?argsSize;??????method->outsSize?=?0;??????method->jniArgInfo?=?dvmComputeJniArgInfo(method->shorty);????????????????method->insns?=?(u2*)info;????????????????method->nativeFunc?=?method_handler;??????LOGI("[+]?%s->%s?was?hooked\n",?classDesc,?methodName);??????????return?0;??}?? 然后是method_handler的實現,這個方法是所有java方法的跳轉函數,所以在這里可以注冊callback,不過這部分邏輯我沒有做上,有興趣的朋友可以加上。
[cpp] view plain
copy STATIC?void?method_handler(const?u4*?args,?JValue*?pResult,?const?Method*?method,?struct?Thread*?self){??????HookInfo*?info?=?(HookInfo*)method->insns;???????LOGI("entry?%s->%s",?info->classDesc,?info->methodName);??????????Method*?originalMethod?=?reinterpret_cast<Method*>(info->originalMethod);??????Object*?thisObject?=?(Object*)args[0];??????????ArrayObject*?argTypes?=?dvmBoxMethodArgs(originalMethod,?args?+?1);???????pResult->l?=?(void?*)dvmInvokeMethod(thisObject,?originalMethod,?argTypes,?(ArrayObject?*)info->paramTypes,?(ClassObject?*)info->returnType,?true);??????????dvmReleaseTrackedAlloc((Object?*)argTypes,?self);??}?? 最后通過dvmInvokeMethod就可以直接調回原來的函數了。
最后
寫這個代碼,主要是因為我在工作中要注入到某個系統進程,然后要hook java中的某些方法,但用cydia和xposed感覺太笨重了,特別是xposed,里面的很多參數的boxed/unboxed都是通過jni模塊自動轉換的,整個框架已經離不開dex文件了。
所以才想自己實現一套純本地的java hook代碼,而《注入安卓進程,并Hook java世界的方法》所介紹的方法,我感覺用起來不太方便,跟cydia和xposed兩個框架的主要區別就是缺少了一個“中轉函數”,所以而有了本碼。
代碼我上傳到github,目前只有java hook,我打算把目前的hook技術都集成到這里,包括inline hook, elf hook等等。
原文地址:?http://blog.csdn.net/l173864930/article/details/39667355
總結
以上是生活随笔為你收集整理的Android Hook Java的的一个改进版本的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。