hook java android_Android Hook Java的的一個改進版本

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等等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/267409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VB6转换C#2010函数替换

VB6转换C#2010函数替换 VB6 ---------------->C#2010 1、InStr(strKey, " ")-->strKey.IndexOf(" ") InStr([start, ]string1, string2[, compare]) 返回指定一字符串在另一字符串中最先出现的位置。在字符串string1中,从start开始找stri…

C#读写文本文件

C#中读写文本文件.txt文件既可以用File类也可用StreamReader、StreamWrite类。这两种方法都需要引用using System.IO命名空间。 下面分别给出例子: 1.File类写入文本文件: 1 private void btnTextWrite_Click(object sender, EventArgs e)2 …

java redirect 跨域_如何解决跨域重定向携带参数的问题?不使用将参数拼接在重定向url末尾的方式...

如何解决跨域重定向携带参数的问题?不使用将参数拼接在重定向url末尾的方式需求,项目A在服务器A上,需要重定向到服务器B上项目B,并且需要携带参数,参数对用户不可见,所以不可以将参数拼接在重定向url后面&a…

RichTextBox的使用

WPF里面虽然很多形式上跟Winform一样,但是控件的使用上面还是会有很多诧异。RichTextBox就是一个例子,是的,在WPF里面对这个控件可以做很多Winform很难做的效果出来。比如在对RichTextBox插入图片,winform时代除了用复制粘贴这种借…

前端自动化测试工具:SlimerJS、phantomJS 和 CasperJS

对于富客户端的 Web 应用页面,自动登录、页面修改、抓取页面内容、屏幕截图、页面功能测试…面对这些需求,使用后端语言需要花费不少的精力才能实现。此时 SlimerJS、phantomJS 或 CasperJS 或许是更好的一种选择。 一、PhantomJS 和 SlimerJS PhantomJS…

java 封装 继承 堕胎_Java的继承、封装和多态

一、继承继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。继承的特性子类拥有父类非 private 的属性、方法。子类可以拥有自己的属性和方法,即子类…

HTML5学习笔记简明版(4):新元素之video,audio,meter,datalist,keygen,output

video 通过<video>标签&#xff0c;我们可以抛弃最近不怎么讨好的Flash&#xff0c;直接在页面中播放视频文件。视频文件自然是最符合语义化的文件格式&#xff0c;但该元素标签同样支持音频与图片。 过去(及目前)&#xff0c;我们通常要使用类似下面这样繁冗丑陋的代码来…

P2782 友好城市

题目描述 有一条横贯东西的大河&#xff0c;河有笔直的南北两岸&#xff0c;岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸&#xff0c;而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市&#xff0c;但…

五个在线图形工具创建简单的设计元素

有很多网站可以为图形元素生成提供服务&#xff0c;但获得非常好的工具并不容易。这就是为什么我共享五个在线的图形工具的原因 Logotype Maker 这是一个简单而自由的做标志的Web工具&#xff0c;它可以帮助您创建一个标志 BgPatterns BgPatterns按几次按键&#xff0c;做背景图…

java shape类_Java——Shape类

Description定义一个形状类Shape&#xff0c;提供计算周长getPerimeter()和面积getArea()的函数定义一个子类正方形类Square继承自Shape类&#xff0c;拥有边长属性&#xff0c;提供构造函数&#xff0c;能够计算周长getPerimeter()和面积getArea()定义一个子类长方形类Rectang…

sulin Python3.6爬虫+Djiago2.0+Mysql --实例demo

1.切换到项目目录下&#xff0c;启动测试服务器 manage.py runserver 192.168.0.108:8888 2.设置相关配置 项目目录展示如下&#xff1a; beauty>settings.py 修改 2.1 添加app到应用程序中 2.2 设置模板路径 2.3 配置数据为mysql 2.4设置静态文件路径 2.5设置漏油 3.beau…

dubbo的invoke命令_dubbo 调试服务telnet命令

1.概述在我们使用dubbo实现分布式布局时&#xff0c;如果我们想测试我们刚写好的service层服务是否正确时&#xff0c;通常要将service层和web层同时开启&#xff0c;通过浏览器调用controller层端口&#xff0c;达到测试service层的目的。有时&#xff0c;这样的测试方法过于麻…

18个不常见的C#关键字,您使用过几个?

18个不常见的C#关键字&#xff0c;您使用过几个&#xff1f;1、__arglist 让我们先从__arglist开始。 __arglist是用来给方法传送参数。通常我们是通过函数头部指定的参数列表给方法传递参数的。如果我们想要给方法传递一组新的参数&#xff0c;我们需要重载方法。如果我们想…

C指针详解

前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运…

java collection api_Java Stream和Collection比较:何时以及如何从Java API返回?

向您展示一些可以非常方便地使用Java Stream流的场景以及如何使用它们的示例。本文基于标准Java库java.util.stream。它既与反应流无关&#xff0c;也与诸如Vavr之类的其他流实现无关。另外&#xff0c;我将不介绍诸如并行执行之类的流的高级细节。首先&#xff0c;让我们简要讨…

依赖属性

项目的WF中用到了依赖属性, 有点晕, 不明白, 先来段代码: public static DependencyProperty IsSignInProperty DependencyProperty.Register("IsSignIn", typeof(System.String), typeof(StateMachineWF.WF1)); [DesignerSerializationVisibilityAttribute(Designe…

[UE4]集合:TSet容器

一、TSet<T>是什么 UE4中&#xff0c;除了TArray动态数组外&#xff0c;还提供了各种各样的模板容器。这一节&#xff0c;我们就介绍集合容器——TSet<T>。类似于TArray<T>&#xff0c;尖括号里面的T是模板类型&#xff0c;可以是任何C类型。一个集合表示了一…

【汇总】flash单个文件上传

之前有朋友给我发送email&#xff0c;询问我是否有单个文件上传的源代码&#xff0c;因为当时写这个好像是在09年&#xff0c;所以放哪了一时也没找着。后来整理硬盘的时候&#xff0c;找到了源码&#xff0c;所以决定来个汇总&#xff08;之前写过的关于flashjs上传文件的例子…

2018.3.24 struct

好了今天听完了struct&#xff0c;感觉也差不多了&#xff0c;后面的视频不想听了&#xff0c;io啊预处理啊什么的用时候现学就好了。主要是就这么光听却没有作业可做真的有点不爽。 明天开始15-213&#xff0c;反正手头也有c primer plus了&#xff0c;后面遇到什么问题看书就…

一直苦于没有好的资产管理软件,GLPI能解决吗?

一直苦于没有好的资产管理软件&#xff0c;正好看到网上文章有介绍glpi资产管理开源软件 在此做个记录&#xff0c;有时间一定要测试一下 &#xff08;1&#xff09;资产管理工具GLPI 官网 http://www.glpi-project.org/ GLPI是法语Gestionnaire libre de parc informatique的…