JVMTI加密和解密Java类文件

时间:2018-12-12 09:41:23

标签: java encryption openssl bytecode-manipulation jvmti

我正在做一些加密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;
}

0 个答案:

没有答案