🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## jvmti ### 原理 本质是 JVMTI 本质上是在JVM内部的许多事件进行了埋点,包括内存申请、线程创建、类加载、GC信息、方法执行等,也可以控制JVM的某些行为 C/C++实现一个JVMTI Agent,在Agent里面注册一些JVM事件的回调。当事件发生时JVMTI调用这些回调方法。Agent可以在回调方法里面实现自己的逻辑。 ### 功能 1.重新定义类 2.跟踪对象分配和垃圾回收过程 3.遵循对象的引用树,遍历堆中的所有对象 4.检查 Java 调用堆栈 5.暂停(和恢复)所有线程 ### 优点 1. Google自家推出,其稳定性和后续的维护更新可以得到保障,功能强大 ### 缺点 1. Android9.0开放 2. Debug可用 3. 影响性能 ### 实现 ### java实现 ``` //加载so  System.load(agentPath); //加载jvmti Debug.attachJvmtiAgent(agentPath,null,getClassLoader()); //系统最终从加载的库中寻找Agent\_xx方法,即回调so内部的Agent\_XX方法 ``` ![](https://img.kancloud.cn/b4/e6/b4e659568c42d292ae32a15ca9685ce8_969x516.png) ### nativa实现 ~~~ #include <jni.h> #include <string> #include "jvmti.h" #include "utils.h" jvmtiEnv *mJvmtiEnv = NULL; jlong tag = 0; //初始化工作 extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm, char *options, void *reserved) { //准备jvmti环境 vm->GetEnv(reinterpret_cast<void **>(&mJvmtiEnv), JVMTI_VERSION_1_2); //开启jvmti的能力 jvmtiCapabilities caps; //获取所有的能力 mJvmtiEnv->GetPotentialCapabilities(&caps); mJvmtiEnv->AddCapabilities(&caps); return JNI_OK; } //调用System.Load()后会回调该方法 extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env; if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } return JNI_VERSION_1_6; } void JNICALL objectAlloc(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, jobject object, jclass object_klass, jlong size) { //对象创建 } void JNICALL objectFree(jvmtiEnv *jvmti_env, jlong tag) { //对象释放 } void JNICALL methodEntry(jvmtiEnv *jvmti_env,JNIEnv* jni_env,jthread thread,jmethodID method) { //方法进入 } void JNICALL methodExit(jvmtiEnv *jvmti_env,JNIEnv* jni_env,jthread thread,jmethodID method,jboolean was_popped_by_exception, jvalue return_value) { //方法退出 } extern "C" JNIEXPORT void JNICALL Java_com_hly_memorymonitor_Monitor_agent_1init(JNIEnv *env, jclass jclazz) { //开启jvm事件监听 jvmtiEventCallbacks callbacks; memset(&callbacks, 0, sizeof(callbacks)); callbacks.MethodEntry = &methodEntry; callbacks.MethodExit = &methodExit; callbacks.VMObjectAlloc = &objectAlloc; callbacks.ObjectFree = &objectFree; //设置回调函数 mJvmtiEnv->SetEventCallbacks(&callbacks, sizeof(callbacks)); //开启监听 mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL); mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, NULL); mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL); mJvmtiEnv->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL); env->ReleaseStringUTFChars(_path, path); } extern "C" JNIEXPORT void JNICALL Java_com_hly_memorymonitor_Monitor_agent_1release(JNIEnv *env, jclass clazz) { mJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL); mJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_OBJECT_FREE, NULL); mJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_ENTRY, NULL); mJvmtiEnv->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, NULL); } ~~~ 1.在Agent\_OnAttach()内部初始化,准备jvmti环境,开启及获取能力; 2.在xx\_agent\_1init()内部,开启jvmti事件监听,设置需要关注的回调(该回调在jvmti.h内部有详细的定义,设置需要关注的即可,本案例关注了JVMTI\_EVENT\_VM\_OBJECT\_ALLOC、JVMTI\_EVENT\_OBJECT\_FREE、JVMTI\_EVENT\_OBJECT\_FREE、JVMTI\_EVENT\_METHOD\_EXIT),执行SetEventNotificationMode JVMTI\_ENABLE 开启监听; 3.在xx\_agent\_1release()内部,执行SetEventNotificationMode JVMTI\_DISABLE 关闭监听; ## epic 原理是通过修改ArtMethod的入口函数,把入口函数的前8个字节修改为一段跳转指令,跳转到执行hook操作的函数,原理跟阿里的热修复框架AndFix差不多,如下图所示。 ![](https://img.kancloud.cn/b9/6d/b96d6504a2eb9a6ffa636e31b0cd7ffd_1240x850.png) 1. 受限于 inline hook 本身,短方法 (Thumb-2 下指令小于 8 个字节,ARM64 小于 16 字节) 无法支持。 2. 被完全内联的方法不支持。 # 参考资料 [ASM hook隐私方法调用,防止App被下架](https://juejin.cn/post/7043399520486424612) [我为Dexposed续一秒——论ART上运行时 Method AOP实现](https://weishu.me/2017/11/23/dexposed-on-art/) [Android JVMTI实现应用内存动态检测](https://www.jianshu.com/p/ab7bbc319dd9)