dll代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" #include <iostream> #include <jni_md.h> #include <jni.h> #include <jvmti.h> #include <string.h> #include <stdio.h> #include "com_example_javajnicall_JniCall.h" using namespace std; void encode(char *str ,int len) { unsigned int m = strlen(str); printf("wait encode len %d arg len %d\n",m ,len); for (int i = 0; i < len; i++) { str[i] = str[i] + k; } /*for (int i = 0; i < m; i++) { str[i] = str[i] + k; }*/ } void decode(char *str,int len) { unsigned int m = strlen(str); for (int i = 0; i < len; i++) { str[i] = str[i] - k; } /*for (int i = 0; i < m; i++) { str[i] = str[i] - k; }*/ } extern"C" JNIEXPORT jbyteArray JNICALL Java_com_example_javajnicall_JniCall_encrypt(JNIEnv * env, jclass cla, jbyteArray text,jint len) { printf("call it!"); char* dst = (char*)env->GetByteArrayElements(text, 0); encode(dst, len); //env->SetByteArrayRegion(text, 0, strlen(dst), (jbyte *)dst); env->SetByteArrayRegion(text, 0, len, (jbyte *)dst); return text; } void JNICALL ClassDecryptHook( jvmtiEnv *jvmti_env, JNIEnv *jni_env, 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 ) { *new_class_data_len = class_data_len; jvmti_env->Allocate(class_data_len, new_class_data); unsigned char* _data = *new_class_data; // com/example/javajvmtiloader/scope/Test2 if (name && strncmp(name, "com/far/demo/Test2", 38) == 0 ) { printf("find it len:%d\n", class_data_len); for (int i = 0; i < class_data_len; i++){ _data[i] = class_data[i]; } decode((char*)_data, class_data_len); }else { for (int i = 0; i < class_data_len; i++){ _data[i] = class_data[i]; } } } JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) { return JNI_OK; } JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) { } JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM * vm, char * options, void * reserved) { jvmtiEnv *jvmti; jint ret = vm->GetEnv((void **)&jvmti, JVMTI_VERSION); if (JNI_OK != ret) { printf("ERROR: Unable to access JVMTI!\n"); return ret; } jvmtiCapabilities capabilities; (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; jvmtiError error = jvmti->AddCapabilities(&capabilities); if (JVMTI_ERROR_NONE != error) { printf("ERROR: Unable to AddCapabilities JVMTI!\n"); return error; } jvmtiEventCallbacks callbacks; (void)memset(&callbacks, 0, sizeof(callbacks)); callbacks.ClassFileLoadHook = &ClassDecryptHook; error = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks)); if (JVMTI_ERROR_NONE != error) { printf("ERROR: Unable to SetEventCallbacks JVMTI!\n"); return error; } error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); if (JVMTI_ERROR_NONE != error) { printf("ERROR: Unable to SetEventNotificationMode JVMTI!\n"); return error; } printf("jvmti oj8k\n"); return JNI_OK; }View Code
com_example_javajnicall_JniCall.h
这个头文件是用javac生成的,实际上这个DLL可以分成两个,我偷懒搞一成一个了
一个用于加密(Java Jni调用),一个用于jvm加载时解密(java agent),对于给jvm加载的dll 包含解密方法即可
坑点
springboot的jar包格式导致不触发jvmti的fIleLoad事件
springboot项目jar包结构
正常的Jar包结构
要想触发jvmti中的fileLoad的事件,必须是正常的jar包格式
springboot是把用户写的类单独放到boot-inf目录下,springboot自己去加载,所以触发不了fileLoad事件!
win下编译的dll 不需要dllMain函数
开始一直以为需要dllmain函数,其实不需要!
想单独加密一个java文件,结果有两个class?
这是因为用了内部类或者lamda方法
标签:java,jar,jvmti,len,char,str,data,class From: https://www.cnblogs.com/cfas/p/16835902.html