参考网址:
http://download.oracle.com/javase/1.5.0/docs/guide/jvmti/jvmti.html#onload
http://192.9.162.55/developer/technicalArticles/J2SE/jvm_ti/
http://kenwublog.com/jvmti-tutorial-a-simple-agent
JDK安装文件:jdk-6u26-windows-i586.exe。
1、Java端调用
启动方式:随java进程启动时,自动载入共享库。
参数设置:
java-agentlib:<agent-lib-name>=<options> Sample
java-agentpath:<path-to-agent>=<options> Sample
本例使用:-agentlib:F:\jars\MCEncrypt
2、C++Dll生成
dll名称:MCEncrypt.dll。
dll类型:MFC extension DLL。
头文件目录:
D:\Program files\Java\jdk1.6.0_26\include\win32
D:\Program files\Java\jdk1.6.0_26\include\
DLL导出接口为:
① 启动加载接口:Agent_OnLoad。
② 退出卸载接口:Agent_OnUnload。
Agent_OnLoad中注册ClassFileLoadHook(class文件加载)响应事件。
实现接口为cbClassFileLoadHook。
实现代码如下:
#include <jvmti.h>
void JNICALL cbClassFileLoadHook(jvmtiEnv*jvmti_env,
JNIEnv*jni_env,
jclassclass_being_redefined,
jobjectloader,
const char*name,
jobjectprotection_domain,
jintclass_data_len,
const unsignedchar* class_data,
jint*new_class_data_len,
unsignedchar** new_class_data)
{
printf("class name=%s\n", name);
}
JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options,void *reserved)
{
jvmtiEnv *jvmti;
jvmtiError error;
// Create the JVM TI environment (jvmti).
jint result = vm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
if (result != JNI_OK) {
printf("ERROR: Unable to access JVMTI!\n");
return 1;
}
jvmtiCapabilities capabilities;
// Clear the capabilities structure and set the ones you need.
(void)memset(&capabilities,0, sizeof(capabilities));
capabilities.can_generate_all_class_hook_events = 1;
capabilities.can_tag_objects = 1;
capabilities.can_generate_object_free_events = 1;
capabilities.can_get_source_file_name = 1;
capabilities.can_get_line_numbers = 1;
capabilities.can_generate_vm_object_alloc_events = 1;
// Request these capabilities for this JVM TI environment.
error = jvmti->AddCapabilities(&capabilities);
if (error != JVMTI_ERROR_NONE) {
printf("ERROR: Unable to AddCapabilities JVMTI!\n");
return error;
}
jvmtiEventCallbacks callbacks;
// Clear the callbacks structure and set the ones you want.
(void)memset(&callbacks,0, sizeof(callbacks));
callbacks.ClassFileLoadHook = &cbClassFileLoadHook;
error = jvmti->SetEventCallbacks(&callbacks,(jint)sizeof(callbacks));
if (error!=JVMTI_ERROR_NONE)
{
printf("ERROR: Unable to SetEventCallbacks JVMTI!\n");
return error;
}
// For each of the above callbacks, enable this event.
error = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
(jthread)NULL);
if (error!=JVMTI_ERROR_NONE)
{
printf("ERROR: Unable to SetEventNotificationMode JVMTI!\n");
return error;
}
return JNI_OK; // Indicates to the VM that the agent loaded OK.
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM*vm)
{
}
注意:C++分配空间时,需采用JVM提供接口,这样分配的空间与平台无关。
封装分配空间方法:
jvmtiEnv* m_pJvmTI;//JVM环境指针,在Agent_OnLoad中调用vm->GetEnv获取
void MCAllocate(int nSize, unsigned char** mem_ptr)
{
if (m_pJvmTI != NULL)
{
jvmtiError eFlag = m_pJvmTI->Allocate(nSize, mem_ptr);
}
else
{
*mem_ptr = new unsigned char[nSize];
}
memset(*mem_ptr, 0, nSize);
}