我正在做一些加密java .class文件的操作,并使用jvmti agentlib解密源数据。总是有例外。
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.ClassFormatError: Unknown constant tag 0 iin class file com/dxf/MethodTraceTest
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
我的环境:Windows7 64位,JDK1.8.0_172 x64,Visual Studio 2017,OpenSSL-win64
解密功能
int DEncrypter::Decrypte(int fileSize, const unsigned char* class_data, unsigned char* my_data)
{
int data_lenth = 0;
const int BUFFER_SIZE = 1024;
char data[BUFFER_SIZE];
memset(data, 0, sizeof(data));
int nLen = RSA_size(m_pRsaPrivate);
//write decrypt class data in file
FILE *fp;
if ((fp = fopen("d:\\com\\dxf\\MethodTraceTest.class", "ab+")) == NULL) {
printf("Open file error!");
exit(0);
}
int uReadFileSize = 0;
for (int i = 0; i < nLen; i++) {
data[i] = class_data[i];
}
while (uReadFileSize < fileSize)
{
int LastLength = (nLen);
if ((fileSize - uReadFileSize) <= (nLen))
{
LastLength = (fileSize - uReadFileSize);
}
char *pDecode = new char[nLen];
memset(pDecode, 0, nLen);
//decrypt
int Dret = RSA_private_decrypt(nLen, (const unsigned char *)data,
(unsigned char *)pDecode, m_pRsaPrivate, RSA_PKCS1_PADDING);
if (Dret >= 0)
{
data_lenth += Dret;
//write file
fwrite(pDecode, (Dret), 1, fp);
for (int i = uReadFileSize, j = 0; j < nLen; j++, i++)
{
my_data[i] = pDecode[j];
}
}
else
{
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
}
fseek(fp, 0, 2);
uReadFileSize += nLen;
//clear Buffer
memset(data, 0, sizeof(data));
delete[] pDecode;
pDecode = NULL;
for (int i = uReadFileSize, j = 0; j < nLen; j++, i++) {
data[j] = class_data[i];
}
}
fclose(fp);
CRYPTO_cleanup_all_ex_data();
RSA_free(m_pRsaPrivate);
return data_lenth;
}
类文件加载钩子
DEncrypter* dencrypter = new DEncrypter();
void JNICALL ClassLoadAgent::ClassLoadHook(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* my_data = *new_class_data;
if (name && strncmp(name, "com/dxf/", 8) == 0)
{
printf("%s\n", name);
int ret = dencrypter->Decrypte(class_data_len, class_data, my_data);
*new_class_data_len = ret;
}
else
{
for (int i = 0; i < class_data_len; ++i)
{
my_data[i] = class_data[i];
}
}
}
jvmti初始化
void ClassLoadAgent::Init(JavaVM *vm) const throw(AgentException){
jvmtiEnv *jvmti = 0;
JNIEnv* jni_env = 0;
jint ret = (vm)->GetEnv(reinterpret_cast<void**>(&jvmti), JVMTI_VERSION);
if (ret != JNI_OK || jvmti == 0) {
throw AgentException(JVMTI_ERROR_INTERNAL);
}
m_jvmti = jvmti;
}
jvmti ParseOptions
void ClassLoadAgent::ParseOptions(const char* str) const throw(AgentException)
{
if (str == 0)
return;
const size_t len = strlen(str);
if (len == 0)
return;
}
jvmti添加功能
void ClassLoadAgent::AddCapability() const throw(AgentException)
{
jvmtiCapabilities caps;
memset(&caps, 0, sizeof(caps));
//caps.can_tag_objects = 1;
caps.can_generate_all_class_hook_events = 1;
//caps.can_generate_object_free_events = 1;
//caps.can_get_source_file_name = 1;
//caps.can_get_line_numbers = 1;
//caps.can_generate_vm_object_alloc_events = 1;
jvmtiError error = m_jvmti->AddCapabilities(&caps);
CheckException(error);
}
jvmti注册事件
void ClassLoadAgent::RegisterEvent() const throw(AgentException)
{
dencrypter->InitDEncrypter();
dencrypter->OpenPrivateKeyFile("RSA_PrivateKey.key", "123456");
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.ClassFileLoadHook = &ClassLoadAgent::ClassLoadHook;
jvmtiError error;
error = m_jvmti->SetEventCallbacks(&callbacks, static_cast<jint>(sizeof(callbacks)));
CheckException(error);
error = m_jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
CheckException(error);
}
Agent OnLoad
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
cout << "Agent_OnLoad(" << vm << ")" << endl;
try{
agent = new ClassLoadAgent();
agent->Init(vm);
agent->ParseOptions(options);
agent->AddCapability();
agent->RegisterEvent();
} catch (AgentException& e) {
cout << "Error when enter Agent_OnLoad: " << e.what() << " [" << e.ErrCode() << "]";
return JNI_ERR;
}
return JNI_OK;
}