都想看jvm是吧
class_monitor_agent.c
#include <jni.h>
#include <jvmti.h>
#include <stdio.h>
#include <string.h>
static jvmtiEnv* jvmti = NULL;
void JNICALL ClassFileLoadHook(jvmtiEnv* jvmti, JNIEnv* 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) {
if (name != NULL) {
printf("类加载: %s\n", name);
} else {
printf("类加载: 匿名类\n");
}
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
jint result;
jvmtiCapabilities capabilities;
jvmtiEventCallbacks callbacks;
result = (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_2);
if (result != JNI_OK || jvmti == NULL) {
printf("无法获取JVM TI环境,错误码: %d\n", result);
return JNI_ERR;
}
memset(&capabilities, 0, sizeof(capabilities));
capabilities.can_retransform_classes = 1;
capabilities.can_generate_all_class_hook_events = 1;
result = (*jvmti)->AddCapabilities(jvmti, &capabilities);
if (result != JVMTI_ERROR_NONE) {
printf("无法设置JVM TI能力,错误码: %d\n", result);
return JNI_ERR;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassFileLoadHook = &ClassFileLoadHook;
result = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
if (result != JVMTI_ERROR_NONE) {
printf("无法设置JVM TI回调,错误码: %d\n", result);
return JNI_ERR;
}
result = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
if (result != JVMTI_ERROR_NONE) {
printf("无法启用类加载事件,错误码: %d\n", result);
return JNI_ERR;
}
printf("JVM TI代理初始化成功\n");
return JNI_OK;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) {
if (jvmti != NULL) {
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
}
printf("JVM TI代理卸载\n");
}
thread_trace_agent.c
#include <jni.h>
#include <jvmti.h>
#include <stdio.h>
#include <string.h>
static jvmtiEnv* jvmti = NULL;
void JNICALL ThreadStart(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
jclass thread_class = (*jni)->FindClass(jni, "java/lang/Thread");
jmethodID get_name = (*jni)->GetMethodID(jni, thread_class, "getName", "()Ljava/lang/String;");
jstring name_str = (jstring)(*jni)->CallObjectMethod(jni, thread, get_name);
const char* name = name_str ? (*jni)->GetStringUTFChars(jni, name_str, NULL) : "无名线程";
printf("[THREAD START] 名称: %s, 地址: %p\n", name, (void*)thread);
if (name_str) {
(*jni)->ReleaseStringUTFChars(jni, name_str, name);
}
}
void JNICALL ThreadEnd(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {
jclass thread_class = (*jni)->FindClass(jni, "java/lang/Thread");
jmethodID get_name = (*jni)->GetMethodID(jni, thread_class, "getName", "()Ljava/lang/String;");
jstring name_str = (jstring)(*jni)->CallObjectMethod(jni, thread, get_name);
const char* name = name_str ? (*jni)->GetStringUTFChars(jni, name_str, NULL) : "无名线程";
printf("[THREAD END] 名称: %s, 地址: %p\n", name, (void*)thread);
if (name_str) {
(*jni)->ReleaseStringUTFChars(jni, name_str, name);
}
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
jint result;
jvmtiCapabilities capabilities;
jvmtiEventCallbacks callbacks;
result = (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_2);
if (result != JNI_OK || jvmti == NULL) {
printf("无法获取JVM TI环境,错误码: %d\n", result);
return JNI_ERR;
}
memset(&capabilities, 0, sizeof(capabilities));
result = (*jvmti)->AddCapabilities(jvmti, &capabilities);
if (result != JVMTI_ERROR_NONE) {
printf("警告: 能力设置部分失败,错误码: %d\n", result);
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.ThreadStart = &ThreadStart;
callbacks.ThreadEnd = &ThreadEnd;
result = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
if (result != JVMTI_ERROR_NONE) {
printf("无法设置回调,错误码: %d\n", result);
return JNI_ERR;
}
result = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL);
if (result != JVMTI_ERROR_NONE) {
printf("无法启用线程启动事件,错误码: %d\n", result);
return JNI_ERR;
}
result = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL);
if (result != JVMTI_ERROR_NONE) {
printf("无法启用线程结束事件,错误码: %d\n", result);
return JNI_ERR;
}
printf("线程跟踪代理初始化成功\n");
return JNI_OK;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) {
if (jvmti != NULL) {
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE, JVMTI_EVENT_THREAD_START, NULL);
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE, JVMTI_EVENT_THREAD_END, NULL);
}
}
exception_trace_agent.c
#include <jni.h>
#include <jvmti.h>
#include <stdio.h>
#include <string.h>
static jvmtiEnv* jvmti = NULL;
void JNICALL ExceptionCatch(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread,
jmethodID method, jlocation location, jthrowable exception) {
jclass ex_class = (*jni)->GetObjectClass(jni, exception);
char* ex_class_name;
(*jvmti)->GetClassSignature(jvmti, ex_class, &ex_class_name, NULL);
jmethodID get_message = (*jni)->GetMethodID(jni, ex_class, "getMessage", "()Ljava/lang/String;");
jstring message_str = (jstring)(*jni)->CallObjectMethod(jni, exception, get_message);
const char* message = message_str ? (*jni)->GetStringUTFChars(jni, message_str, NULL) : "无消息";
printf("[EXCEPTION CAUGHT] 类型: %s, 消息: %s\n", ex_class_name, message);
(*jvmti)->Deallocate(jvmti, (unsigned char*)ex_class_name);
if (message_str) {
(*jni)->ReleaseStringUTFChars(jni, message_str, message);
}
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
jint result;
jvmtiCapabilities capabilities;
jvmtiEventCallbacks callbacks;
result = (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_2);
if (result != JNI_OK || jvmti == NULL) return JNI_ERR;
memset(&capabilities, 0, sizeof(capabilities));
capabilities.can_generate_exception_events = 1;
result = (*jvmti)->AddCapabilities(jvmti, &capabilities);
if (result != JVMTI_ERROR_NONE) {
printf("无法设置异常监控能力,错误码: %d\n", result);
return JNI_ERR;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.ExceptionCatch = &ExceptionCatch;
result = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
if (result != JVMTI_ERROR_NONE) return JNI_ERR;
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_EXCEPTION_CATCH, NULL);
printf("异常跟踪代理初始化成功\n");
return JNI_OK;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) {
if (jvmti != NULL) {
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION_CATCH, NULL);
}
}
object_trace_agent.c
#include <jni.h>
#include <jvmti.h>
#include <stdio.h>
#include <string.h>
static jvmtiEnv* jvmti = NULL;
void JNICALL VMObjectAlloc(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread,
jobject obj, jclass cls, jlong size) {
char* class_name;
(*jvmti)->GetClassSignature(jvmti, cls, &class_name, NULL);
if (class_name) {
printf("[ALLOC] 类: %s, 大小: %ld bytes\n", class_name, size);
(*jvmti)->Deallocate(jvmti, (unsigned char*)class_name);
}
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
jint result;
jvmtiCapabilities capabilities;
jvmtiEventCallbacks callbacks;
result = (*vm)->GetEnv(vm, (void**)&jvmti, JVMTI_VERSION_1_2);
if (result != JNI_OK || jvmti == NULL) {
printf("无法获取JVM TI环境\n");
return JNI_ERR;
}
memset(&capabilities, 0, sizeof(capabilities));
capabilities.can_generate_vm_object_alloc_events = 1;
result = (*jvmti)->AddCapabilities(jvmti, &capabilities);
if (result != JVMTI_ERROR_NONE) {
printf("无法设置能力\n");
return JNI_ERR;
}
memset(&callbacks, 0, sizeof(callbacks));
callbacks.VMObjectAlloc = &VMObjectAlloc;
result = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
if (result != JVMTI_ERROR_NONE) {
printf("无法设置回调\n");
return JNI_ERR;
}
result = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
JVMTI_EVENT_VM_OBJECT_ALLOC, NULL);
if (result != JVMTI_ERROR_NONE) {
printf("无法启用事件\n");
return JNI_ERR;
}
printf("对象跟踪代理初始化成功\n");
return JNI_OK;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM* vm) {
if (jvmti != NULL) {
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE,
JVMTI_EVENT_VM_OBJECT_ALLOC, NULL);
}
}
gbuild.sh
set -xe
export JAVA_INCLUDE_DIR=/etc/alternatives/java_sdk_24
gcc -shared -fPIC -shared -I$JAVA_INCLUDE_DIR/include -I$JAVA_INCLUDE_DIR/include/linux $1 -o lib$1.so
java -agentpath:./lib$1.so $2
usage
bash gbuild.sh <what agent.c> <what test java>
JVMTITest.java
public class JVMTITest {
static class InnerClass {
public void doSomething() {
System.out.println("内部类方法被调用");
}
}
public static void main(String[] args) {
System.out.println("主程序开始运行");
InnerClass inner = new InnerClass();
inner.doSomething();
try {
Class<?> stringClass = Class.forName("java.lang.String");
System.out.println("加载了标准类: " + stringClass.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("主程序运行结束");
try {
throw new Exception("damn");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
sample.log
- https://gitee.com/EEPPEE_admin/jvm-backend-example/blob/jni-and-hack-jvm/hackjvm_example/sample.log