c
复制代码
#include <jni.h>
#include <jvmti.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static jvmtiEnv *jvmti = NULL;
// 处理类签名(Lxxx/xxx; -> xxx/xxx)
static char* process_class_signature(const char *signature) {
if (signature == NULL || *signature != 'L') {
return strdup(signature ? signature : "");
}
size_t len = strlen(signature);
char *processed = (char*)malloc(len - 1);
if (processed) {
strncpy(processed, signature + 1, len - 2);
processed[len - 2] = '\0';
}
return processed;
}
// 方法进入回调
void JNICALL MethodEntryCallback(
jvmtiEnv *jvmti,
JNIEnv *env,
jthread thread,
jmethodID method
) {
jclass declaring_class;
jvmtiError err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &declaring_class);
if (err != JVMTI_ERROR_NONE) {
fprintf(stderr, "GetMethodDeclaringClass failed: %d\n", err);
return;
}
char *class_signature, *class_generic;
err = (*jvmti)->GetClassSignature(jvmti, declaring_class, &class_signature, &class_generic);
if (err != JVMTI_ERROR_NONE) {
fprintf(stderr, "GetClassSignature failed: %d\n", err);
return;
}
char *class_name = process_class_signature(class_signature);
char *method_name, *method_signature, *method_generic;
err = (*jvmti)->GetMethodName(jvmti, method, &method_name, &method_signature, &method_generic);
if (err != JVMTI_ERROR_NONE) {
fprintf(stderr, "GetMethodName failed: %d\n", err);
free(class_name);
(*jvmti)->Deallocate(jvmti, (unsigned char*)class_signature);
(*jvmti)->Deallocate(jvmti, (unsigned char*)class_generic);
return;
}
printf("[JVM HACK] 调用方法: %s.%s%s\n", class_name, method_name, method_signature);
free(class_name);
(*jvmti)->Deallocate(jvmti, (unsigned char*)class_signature);
(*jvmti)->Deallocate(jvmti, (unsigned char*)class_generic);
(*jvmti)->Deallocate(jvmti, (unsigned char*)method_name);
(*jvmti)->Deallocate(jvmti, (unsigned char*)method_signature);
(*jvmti)->Deallocate(jvmti, (unsigned char*)method_generic);
}
// Agent初始化(适配JDK 24)
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
// 获取JVM TI环境(使用JDK 24支持的最新版本)
jint ret = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1_2);
if (ret != JNI_OK || jvmti == NULL) {
fprintf(stderr, "获取JVM TI环境失败,错误码: %d\n", ret);
return ret;
}
// JDK 24中,方法信息访问能力通过can_access_method_data统一声明
jvmtiCapabilities capabilities;
memset(&capabilities, 0, sizeof(capabilities));
capabilities.can_generate_method_entry_events = 1; // 允许生成方法进入事件
#if 0 // not working on jdk24
//capabilities.can_access_method_data = 1; // 允许访问方法数据(替代旧版本的细粒度成员)
#endif
jvmtiError err = (*jvmti)->AddCapabilities(jvmti, &capabilities);
if (err != JVMTI_ERROR_NONE) {
fprintf(stderr, "添加JVM TI功能失败,错误码: %d\n", err);
return err;
}
// 注册回调
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.MethodEntry = &MethodEntryCallback;
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
if (err != JVMTI_ERROR_NONE) {
fprintf(stderr, "设置事件回调失败,错误码: %d\n", err);
return err;
}
// 启用方法进入事件
err = (*jvmti)->SetEventNotificationMode(
jvmti,
JVMTI_ENABLE,
JVMTI_EVENT_METHOD_ENTRY,
NULL
);
if (err != JVMTI_ERROR_NONE) {
fprintf(stderr, "启用事件通知失败,错误码: %d\n", err);
return err;
}
printf("[JVM HACK] 代理加载成功,开始监控方法调用...\n");
return JNI_OK;
}