1. 项目背景
由于jar文件可以被反编译,我们使用Java开发的一些商业代码不能得到很好的保护。本文讲述了jvmti agent技术对Java编译后的class文件进行加密处理,防止反编译,能有效保护我们的商业代码。
2. 加密
#include "encrypt.h"
extern"C" JNIEXPORT jbyteArray JNICALL Java_aurora_security_license_tool_util_EncryptUtil_encrypt(
JNIEnv * _env,
jobject _obj,
jbyteArray _buf
) {
jsize len = _env->GetArrayLength(_buf);
unsigned char* dst = (unsigned char*)_env->GetByteArrayElements(_buf, 0);
for (int i = 0; i < len; i++) {
dst[i] = dst[i] ^ getKey();
}
_env->SetByteArrayRegion(_buf, 0, len, (jbyte *)dst);
return _buf;
}
3. 解密
#include "decrypt.h"
void JNICALL
MyClassFileLoadHook(
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);
/*char buffer[8];
memset(buffer, 0, 8);
Block block, bkey;
Method method = d;
BlockFromStr(bkey, "H@ndhec123456");*/
unsigned char* my_data = *new_class_data;
//增加对class文件魔数的判断,检测class文件是否加密
//加密后class文件前四个字节为9fabefeb
if (name && strncmp(name, "aurora/", 7) == 0 && class_data[0] == 0x9f && class_data[1] == 0xab && class_data[2] == 0xef && class_data[3] == 0xeb) {
//printf("%s\n", name);
for (int i = 0; i < class_data_len; ++i)
{
my_data[i] = class_data[i] ^ getKey();
}
}
else {
for (int i = 0; i < class_data_len; ++i)
{
my_data[i] = class_data[i];
}
}
}
//agent是在启动时加载的
JNIEXPORT jint JNICALL
Agent_OnLoad(
JavaVM *vm,
char *options,
void *reserved
)
{
jvmtiEnv *jvmti;
//Create the JVM TI environment(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 = &MyClassFileLoadHook;
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;
}
return JNI_OK;
}