`
weihe6666
  • 浏览: 440082 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

MethodHooker--Hook分析

阅读更多
Hook的原理是修改java层的method属性,然后注册jni函数,但是实现起来还是有点复杂,具体看下面的函数。

int Hook(){
	init();
	void* handle = dlopen("/data/local/libTest.so",RTLD_NOW);
	const char *dlopen_error = dlerror();
	if(!handle){
		DEBUG_PRINT("cannt load plugin :%s",dlopen_error);
		return -1;
	}
	SetupFunc setup = (SetupFunc)dlsym(handle,"getpHookInfo");
	const char *dlsym_error = dlerror();
	if (dlsym_error) {
		DEBUG_PRINT("Cannot load symbol 'getpHookInfo' :%s" , dlsym_error);
		dlclose(handle);
		return 1;
	}

	HookInfo *hookInfo;
	setup(&hookInfo);

	DEBUG_PRINT("Target Class:%s",hookInfo[0].tClazz);
	DEBUG_PRINT("Target Method:%s",hookInfo[0].tMethod);

	ClassMethodHook(hookInfo[0]);
	return 0;
}


1. init初始化虚拟机环境
2. 加载要注册jni函数的so文件
3. 注册jni函数,并修改java层对应的method方法属性

一、init函数
void init()
{
	g_bAttatedT = false;
	g_JavaVM = android::AndroidRuntime::getJavaVM();
}


这里通过android运行环境获得虚拟机句柄或者称之为虚拟机指针,思考一下为何能够通过android::AndroidRuntime::getJavaVM();获取虚拟机指针,为什么正常情况下写的jni函数,此语句无法通过编译。

android系统在启动时会通过init.rc启动zygote进程,而zygote进行会初始化android运行时环境,并且初始化jvm相关的环境,而所有的app程序都是通过zygote fork出来的,相应的android运行时环境和jvm环境也会与zygote相同。

那么在任意一个app的native层,都可以通过android::AndroidRuntime::getJavaVM();获取jvm指针,navite层本来就是linux系统进程的概念,可以笼统的把jvm看做是linux进程中运行的一个线程,这么一想就通了。


二、so动态库加载

linux有通用的函数dlopen、dlsym、dlclose函数来处理so动态库的加载,这里也必然使用这几个函数来加载我们需要的so库。

dlopen就不多说了,看一下dlsym
SetupFunc setup = (SetupFunc)dlsym(handle,"getpHookInfo");

这里是获取so库中getpHookInfo符号的地址,也就是获取此函数的地址,那么SetupFunc setup怎么理解呢?如果C基础比较扎实的话,这不是个问题,看一下声明:typedef int (*SetupFunc)(HookInfo**);这里定义了一个函数指针,函数指针的行为为(*函数名)(参数);


HookInfo *hookInfo;
setup(&hookInfo);

这一步就是执行函数,或者说函数的调用。


三、java层函数的hook

bool ClassMethodHook(HookInfo info){

	JNIEnv *jenv = GetEnv();

	jclass clazzTarget = jenv->FindClass(info.tClazz);
	if (ClearException(jenv)) {
		DEBUG_PRINT("ClassMethodHook[Can't find class:%s in bootclassloader",info.tClazz);

	    clazzTarget = findAppClass(jenv,info.tClazz);
	    if(clazzTarget == NULL){
	    	DEBUG_PRINT("%s","Error in findAppClass");
	    	return false;
	    }
	}

	jmethodID method = jenv->GetMethodID(clazzTarget,info.tMethod,info.tMeihodSig);
	if(method==NULL){
		DEBUG_PRINT("ClassMethodHook[Can't find method:%s",info.tMethod);
		return false;
	}

	if(isArt()){
		HookArtMethod(jenv,method);
	}else{
		HookDalvikMethod(method);
	}

    JNINativeMethod gMethod[] = {
        {info.tMethod, info.tMeihodSig, info.handleFunc},
    };

    if(info.handleFunc != NULL){
		if (jenv->RegisterNatives(clazzTarget, gMethod, 1) < 0) {
			DEBUG_PRINT("err");
			return false;
		}
    }

	DetachCurrent();
	return true;
}


这个函数是重点,这里如何hook以及如何在so中注册jni函数呢?

想要hook java层函数,先要获取此函数的Method指针,然后在对此指针进行操作。我们看一看如何获取Method句柄。

想要获取类的一些信息,比如想要获取和jvm进行沟通的渠道,这个渠道就是JNIEnv,jni句柄,

static JNIEnv *GetEnv()
{
	int status;
	JNIEnv *envnow = NULL;
	status = g_JavaVM->GetEnv((void **)&envnow, JNI_VERSION_1_4);
	if(status < 0)
	{
		status = g_JavaVM->AttachCurrentThread(&envnow, NULL);
		if(status < 0)
		{
			return NULL;
		}
		g_bAttatedT = true;
	}
	return envnow;
}



通过jvm句柄获取g_JavaVM->GetEnv((void **)&envnow, JNI_VERSION_1_4);这里有一个关键的处理就是绑定线程AttachCurrentThread(&envnow, NULL);


获取到JNIEnv后,便可以通过findClass获取类对象的句柄:jclass clazzTarget = jenv->FindClass(info.tClazz);
这是一个常用的方法,不多解。

jenv->GetMethodID(clazzTarget,info.tMethod,info.tMeihodSig)
这句是从class对象获取method属性,然后修改此method对应的属性。

四、修改Method属性

bool HookDalvikMethod(jmethodID jmethod){
	DEBUG_PRINT("HookDalvikMethod");
	Method *method = (Method*)jmethod;
	SET_METHOD_FLAG(method, ACC_NATIVE);

	int argsSize = dvmComputeMethodArgsSize(method);
    if (!dvmIsStaticMethod(method))
        argsSize++;

    method->registersSize = method->insSize = argsSize;

    if (dvmIsNativeMethod(method)) {
        method->nativeFunc = dvmResolveNativeMethod;
        method->jniArgInfo = computeJniArgInfo(&method->prototype);
    }
    return true;
}


1. 设置method 为native属性:SET_METHOD_FLAG(method, ACC_NATIVE);
2. 计算method的参数个数,如果不是static,需要添加this参数
3. 设置nativeFunc地址函数
3. 设置jniArgInfo参数信息

这里重要的点是computeJniArgInfo(&method->prototype);来计算输入参数和返回类型。

下一篇会分析jni函数的调用逻辑。
分享到:
评论

相关推荐

    apache-atlas-2.3.0-hbase-hook.tar.gz

    apache-atlas-2.3.0-hbase-hook.tar.gz Apache Atlas 框架是一组可扩展的核心基础治理服务,使企业能够有效且高效地满足 Hadoop 内的合规性要求,并允许与整个企业数据生态系统集成。这将通过使用规范和取证模型、...

    atlas hive hook 编译依赖 apache-atlas-1.2.0-hive-hook.tar.gz

    在实际使用中,你需要解压 "apache-atlas-hive-hook-1.2.0" 压缩包,然后按照官方文档的指引进行安装和配置。这可能包括编译源代码、添加依赖、修改 Hive 配置以及启动服务。通过正确配置和使用 Atlas Hive Hook,你...

    apache-atlas-2.1.0-hive-hook.tar.gz

    1. **解压文件**:首先,你需要将 "apache-atlas-hive-hook-2.1.0" 解压到一个合适的位置。 2. **配置 Atlas**:在 Atlas 的配置文件(如 `atlas-env.sh` 或 `atlas.conf`)中,添加 Hive Hook 的类路径和配置信息。...

    nvidia-container-runtime-hook-1.4.0-2.x86_64.rpm

    centos7.4+ nvidia-docker2 安装所需要的必备包之一 libnvidia-container-tools-1.0.2-1.x86_64.rpm ...nvidia-container-runtime-hook-1.4.0-2.x86_64.rpm nvidia-docker2-2.0.3-3.docker18.09.6.ce.noarch.rpm

    apache-atlas-2.2.0-hook.tar

    hook-tar/apache-atlas-2.2.0-falcon-hook.tar.gz hook-tar/apache-atlas-2.2.0-hbase-hook.tar.gz hook-tar/apache-atlas-2.2.0-hive-hook.tar.gz hook-tar/apache-atlas-2.2.0-impala-hook.tar.gz hook-tar/apache...

    NVIDIA-DOCKER-18.06版本 nvidia-container-runtime-hook_1.4.0-1_amd64.deb

    NVIDIA-DOCKER-18.06版本 nvidia-container-runtime-hook_1.4.0-1_amd64.deb

    apache-atlas-2.0.0-hive-hook.tar.gz

    这个压缩包"apache-atlas-2.0.0-hive-hook.tar.gz"包含了Apache Atlas的2.0.0版本,特别关注与Hive集成的钩子(hook)功能。Apache Atlas的主要目标是帮助企业在大数据环境中实施全面的数据治理策略,确保数据质量、...

    apache-atlas-2.0.0-hbase-hook.tar.gz

    1. **下载和解压**:首先,你需要下载提供的"apache-atlas-hbase-hook-2.0.0"压缩文件,然后将其解压到一个适当的目录。这将包含所有必要的库和配置文件。 2. **配置Apache Atlas**:在Apache Atlas的配置文件(如...

    apache-atlas-2.1.0-hbase-hook.tar.gz

    压缩包内的“apache-atlas-hbase-hook-2.1.0”文件包含了实现上述功能所需的全部组件和配置文件。安装和配置此Hook通常包括以下步骤: 1. **解压文件**:首先,你需要解压“apache-atlas-2.1.0-hbase-hook.tar.gz”...

    apache-atlas-2.2.0-falcon-hook.tar.gz

    具体到 "apache-atlas-hive-hook-2.2.0" 这个子目录,它表示 Atlas 提供了一个针对 Hive 的钩子(hook)。Hive Hook 是 Atlas 与 Hive 交互的一种方式,当用户在 Hive 中执行 DDL(数据定义语言)操作时,如创建表、...

    oci-systemd-hook-0.2.0-1.git05e6923.el7_6.x86_64.rpm

    离线安装包,亲测可用

    apache-atlas-2.3.0-hive-hook.tar.gz

    apache-atlas-2.3.0-hive-hook.tar.gz Apache Atlas 框架是一组可扩展的核心基础治理服务,使企业能够有效且高效地满足 Hadoop 内的合规性要求,并允许与整个企业数据生态系统集成。这将通过使用规范和取证模型、...

    apache-atlas-2.2.0-sqoop-hook.tar.gz

    在解压`apache-atlas-sqoop-hook-2.2.0`后,通常会包含一系列配置文件、Java类库和文档,这些内容用于安装和配置Sqoop Hook,使其能与Apache Atlas无缝对接。用户需要根据自己的环境设置这些参数,如Atlas服务器的...

    react-reacttypewriterhook用reacthooks来实现打字机的效果

    `useState` Hook用于添加状态到函数组件中,而`useEffect` Hook则用于处理副作用,如数据获取、订阅或者在组件更新后执行某些操作。 在`react-typewriter-hook`中,我们可以看到如何巧妙地结合这些Hooks来实现打字...

    apache-atlas-2.2.0-kafka-hook.tar.gz

    3. **安装 Kafka Hook**:将 `apache-atlas-kafka-hook-2.2.0` 解压后,将其 JAR 包添加到 Atlas 的类路径中。 4. **配置 Kafka Hook**:在 Atlas 的配置文件中(如 `atlas-application.properties`),配置 Kafka ...

    apache-atlas-2.1.0-kafka-hook.tar.gz

    在"apache-atlas-kafka-hook-2.1.0"这个子目录中,你可能会找到以下关键组件和文件: 1. **配置文件**:通常包括`atlas-application.properties`,这是Atlas的主要配置文件,你可以在这里设置Kafka Hook的相关参数...

    apache-atlas-2.1.0-falcon-hook.tar.gz

    Apache Atlas 是一个元数据管理框架,专为大数据环境设计,用于提供数据治理、安全和合规性...这个压缩包中的 "apache-atlas-falcon-hook-2.1.0" 文件可能是实际的集成组件,用于部署和配置在相应的 Hadoop 集群上。

    react-modal-hook:使用React Hooks来处理模态的语法糖

    npm install --save react-modal-hook 用法 使用ModalProvider为您的应用程序提供模态上下文: import React from "react" ; import ReactDOM from "react-dom" ; import { ModalProvider } from "react-modal-hook...

    Laravel开发-laravel-php-code-analysis-hook

    `laravel-php-code-analysis-hook`是一个针对Laravel开发的Git预提交钩子,它帮助开发者在提交代码前自动执行PHP代码分析工具,确保代码符合最佳实践和约定。这个项目的主要目标是通过集成PHP CodeSniffer、...

Global site tag (gtag.js) - Google Analytics