Hook Java的的一個改進版本

《注入安卓進程,並Hook java世界的方法》這篇好文相信大家都看這,里面所提到的方法估計大家也都試過。不過里面的所用的方法,我發現有兩個可以改進的地方。

改進點一:更簡單地修改java方法為本地方法...

// hook method

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);

// save info to insns

method->insns = (u2*)info;

// bind the bridge func,only one line

method->nativeFunc = method_handler;

LOGI("[+] %s->%s was hooked\n", classDesc, methodName);

...

直接把method->nativeFunc即可,無需重新調用JNIEnv的RegisterNatives方法,其中method_handler可以是下面兩種形式之一:

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。

改進點二:方法回調避免線程安全問題

原來的方法,是這樣的

//hook之前先拷貝

uint mlen = sizeof(Method);

Method *oldMeth = (Method*)malloc(mlen);

memcpy(oldMeth,method,mlen);

info->odlMethod = oldMeth;

info->curMethod = method;

//回調后再拷貝回來,再通過jni->callXXXXMethod調用,之后再重新hook

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,這個函數的原型是這樣的:

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只能自己寫代碼了,下面是我的代碼:

STATIC ArrayObject* dvmGetMethodParamTypes(const Method* method, const char* methodsig){

/* count args */

size_t argCount = dexProtoGetParameterCount(&method->prototype);

STATIC ClassObject* java_lang_object_array = dvmFindSystemClass("[Ljava/lang/Object;");

/* allocate storage */

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);

/*

* Fill in the array.

*/

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里頭了:

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;

}

// backup method

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));

// init info

info->originalMethod = (void *)bakMethod;

info->returnType = (void *)dvmGetBoxedReturnType(bakMethod);

info->paramTypes = dvmGetMethodParamTypes(bakMethod, info->methodSig);

// hook method

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);

// save info to insns

method->insns = (u2*)info;

// bind the bridge func,only one line

method->nativeFunc = method_handler;

LOGI("[+] %s->%s was hooked\n", classDesc, methodName);

return 0;

}

然后是method_handler的實現,這個方法是所有java方法的跳轉函數,所以在這里可以注冊callback,不過這部分邏輯我沒有做上,有興趣的朋友可以加上。

STATIC void method_handler(const u4* args, JValue* pResult, const Method* method, struct Thread* self){

HookInfo* info = (HookInfo*)method->insns; //get hookinfo pointer from method-insns

LOGI("entry %s->%s", info->classDesc, info->methodName);

Method* originalMethod = reinterpret_cast(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等等。

hook java android_Android Hook Java的的一個改進版本相关推荐

  1. 初识Frida--Android逆向之Java层hook (二)

    目录 初识Frida--Android逆向之Java层hook (二) apk的安装与分析 流程分析 hook点分析 JavaScript代码构造与执行 0x00 hook getMac() 0x01 ...

  2. 全能Android HOOK框架 JNI NATIVE JAVA ART DALVIK

    OneHook 目前比较流行的几个安卓HOOK方案,都有功能上的欠缺,有的不支持art模式,有的不支持jni层,有的不支持侵入HOOK. 所以OneHook诞生了! 这是一个同时支持ART和Dalvi ...

  3. 全能HOOK框架 JNI NATIVE JAVA ART DALVIK

    OneHook 目前比较流行的几个安卓HOOK方案,都有功能上的欠缺,有的不支持art模式,有的不支持jni层,有的不支持侵入HOOK. 所以OneHook诞生了! 这是一个同时支持ART和Dalvi ...

  4. VirtualHook: 基于VirtualApp的Java代码hook工具

    VirtualHook: 基于VirtualApp的Java代码hook工具 nabla 2017-4-1 10:16  21442 转自 https://bbs.pediy.com/thread-2 ...

  5. Java可以hook微信吗,【第一篇】【安卓微信】HOOK微信发消息,当HOOK遇上HOOK。

    前人栽树,后人吃桃. 准备入坑 安卓 xposed hook 微信(及时通信),好吧,第一步当然是论坛里面搜索啦,像掷骰子.计步器什么的都是小孩子过家家入门级别的,当然是要搞就搞(及时通信).微信 a ...

  6. java hook技术_API Hook基本原理和实现 - - JavaEye技术网站

    hook是什么? windows系统下的编程,消息message的传递是贯穿其始终的.这个消息我们可以简单理解为一个有特定意义的整数,正如我们看过的老故事片中的"长江长江,我是黄河" ...

  7. 【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )

    Android 插件化系列文章目录 [Android 插件化]插件化简介 ( 组件化与插件化 ) [Android 插件化]插件化原理 ( JVM 内存数据 | 类加载流程 ) [Android 插件 ...

  8. Hook技术之Hook Activity

    一.Hook技术概述 Hook技术的核心实际上是动态分析技术,动态分析是指在程序运行时对程序进行调试的技术.众所周知,Android系统的代码和回调是按照一定的顺序执行的,这里举一个简单的例子,如图所 ...

  9. java 赋值md5_Hook Java API以获得MD5加密前数据

    Java实现MD5加密 在Java中,我们用MD5对数据进行加密,代码大概是这样的: import java.security.MessageDigest; import java.security. ...

最新文章

  1. 021_html文本格式化标签
  2. LINQTOSQL作为底层ORM框架后,我们的数据基类就变成了这个样子
  3. 我们需要一个时期,把我们之前的愿景用实际行动实现
  4. MongoDB日志文件过大
  5. Final Project 期末项目: PySnake
  6. SQLserver安装程序无法打开注册表项 解决办法
  7. 官网VSCode无法下载解决方法
  8. 深度学习不得不知的英文名称
  9. python莱布尼茨法计算π_python圆周率计算(带进度条)
  10. 微服务实战之春云与刀客(一)—— 微服务开篇
  11. 《机器学习》(周志华)线性回归
  12. 什么是Google PR值? 如何提高PR值?
  13. 导通压降与死区的开启电压区别
  14. NSN的MGM SW engineer面试题
  15. 并发------多线程安全
  16. 2019第十六届研究生数学建模竞赛--跨越五年从本科省二到研赛国一
  17. Win7某服务无法启动的解决
  18. 计算机照片无法打开,提示windows照片查看器无法打开此图片怎么处理
  19. eiei歌曲计算机谱,偶像练习生主题曲《eiei》歌曲歌词介绍
  20. 树莓派摄像头使用方法

热门文章

  1. 龙图 VP 李翀:数据化运营及云计算下的运维
  2. GoLang之方法与接口
  3. mysql数据类型优化
  4. 常用AT指令集 (转)
  5. hadoop等的下载地址
  6. uboot 与系统内核中 MTD分区的关系
  7. Linux根文件系统结构再认识
  8. php函数库快速记忆法_PHP速成大法
  9. JAVA mysql存数组_JAVA数组怎么存放数据库的元素
  10. mysql 不同分区 同时insert_Mysql分区表的原理和优缺点