用javaagent來對java位元組碼進行變換
阿新 • • 發佈:2019-02-09
1、實現變換的函式
5、實際的實現,列印載入的類
7、關於jvm的這些hook呼叫的實現原理,請看下一篇部落格
typedef void (JNICALL *jvmtiEventClassFileLoadHook) //類位元組碼變換的回撥介面 (jvmtiEnv *jvmti_env, //註冊的jvmti JNIEnv* jni_env, //JNI環境 jclass class_being_redefined, // jobject loader, const char* name, jobject protection_domain, jint class_data_len, const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data);
2、註冊回撥事件
jint result = jvm->GetEnv((void**) &jvmti, JVMTI_VERSION_1_1); jvmtiEventCallbacks callbacks; callbacks.ClassFileLoadHook = &eventHandlerClassFileLoadHook; (*jvmtienv)->SetEventCallbacks( jvmtienv, &callbacks, sizeof(callbacks));
3、啟用類位元組碼載入的hook事件,如果不啟用,註冊的回撥函式將不會被呼叫的
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
4、啟用位元組碼變換的標記,如果不啟用,可以呼叫回撥函式,但是裡面進行的位元組碼變換將不起效
jvmtiCapabilities capabilities; memset(&capabilities, 0, sizeof(capabilities)); capabilities.can_retransform_classes = 1;
5、實際的實現,列印載入的類
#include <jvmti.h>
#include <jni.h>
#include <stdio.h>
#include <string.h>
extern "C"
JNICALL void myClassTransform//類位元組碼變換的回撥介面
(jvmtiEnv *jvmti_env, //註冊的jvmti
JNIEnv* jni_env, //JNI環境
jclass class_being_redefined, //
jobject loader,
const char* name,
jobject protection_domain,
jint class_data_len,
const unsigned char* class_data,
jint* new_class_data_len,
unsigned char** new_class_data) {
printf("Loading class %s\n", name);
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void* reserved) {
jvmtiEnv *jvmti = NULL;
jint error = jvm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_1);
//載入jvmti環境
if(error != JNI_OK) {
printf("Get env fail, errorCode=%d\n", error);
return JNI_ERR;
}
//使用位元組碼變換能力
jvmtiCapabilities capabilities;
memset(&capabilities, 0, sizeof(capabilities));
capabilities.can_retransform_classes = 1;
capabilities.can_retransform_any_class = 1;
jvmtiError e2 = jvmti->AddCapabilities(&capabilities);
if(e2 != JVMTI_ERROR_NONE) {
printf("AddCapabilities error\n");
return JNI_ERR;
}
//設定回撥
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassFileLoadHook = &myClassTransform; //設定類檔案變換的檔案控制代碼
e2 = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
if(e2 != JVMTI_ERROR_NONE) {
printf("setcallback error\n");
return JNI_ERR;
}
e2 = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
printf("Register ok\n");
return JNI_OK;
}
6、執行,注意要用g++進行編譯,如果用gcc進行編譯的,jvmti的方法呼叫,應該形如(*jvmti)->xxx(jvmti,...)
g++ -fPIC -shared -g -o test.dylib -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin/ test.cpp
javac Test.java
java -agentpath:test.dylib Test
7、關於jvm的這些hook呼叫的實現原理,請看下一篇部落格