基於jvmti方式加密java


    大家知道java是以虛擬機的方式運行以.class結尾的字節碼文件,虛擬機要解析class文件,必然有一套解析方案,相對應的就可以通過字節碼還原java源代碼,flash的as也是一樣,辛辛苦苦寫完的代碼,人家用一個工具反編譯,一切就都沒有秘密了...悲劇啊!

    最好的解決方案莫過於直接改虛擬機,在這里不考慮通用性,公司的服務器只能用改過的虛擬機是沒有問題的,無奈通過兩天的搗鼓在linux下安裝openjdk,本人放棄了,編譯openjdk出現各種問題,需要的很多相關庫在網上下過來編譯不通過,只有放棄了,應該是跟本人用的linux版本有關,向那些編譯過openjdk的朋友致敬!!!

    退而求其次,只有用jvmti了.

    jvmti是JDK提供的一套用於開發JVM監控, 問題定位與性能調優工具的通用編程接口(API)。
通過jvmti,我們可以開發各式各樣的JVMTI Agent。這個Agent的表現形式是一個以c/c++語言編寫的動態共享庫。

jvmti Agent原理: java啟動或運行時,動態加載一個外部基於JVM TI編寫的dynamic module到Java進程內,然后觸發JVM源生線程Attach Listener來執行這個dynamic module的回調函數。在函數體內,你可以獲取各種各樣的VM級信息,注冊感興趣的VM事件,甚至控制VM的行為。

  jvmti正好提供了一個加載class之前的一個事件,函數接口

 

 
typedef  void (JNICALL  *jvmtiEventClassFileLoadHook)
    (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);
 
    jvmtiEventCallbacks callbacks;
     //  Clear the callbacks structure and set the ones you want.
    ( void)memset(&callbacks, 0sizeof(callbacks));
    callbacks.ClassFileLoadHook = &cbClassFileLoadHook;//注冊函數,這是咋們關心的
    error = jvmti->SetEventCallbacks(&callbacks,(jint) sizeof(callbacks));

事情就比較簡單了,在cbClassFileLoadHook函數里解密加密后的buffer,賦給new_class_data,new_class_data_len就行了

一個是buffer,一個是數據buffer的大小,事情是不是相當的簡單了...

有一點注意,在這里你不能new 一個buffer返回給虛擬機,否則這個buffer誰管理啊 什么時候釋放?

通過虛擬機來申請buffer

 

m_pJvmTI->Allocate(newlen,new_class_data);

 

好了,就這么簡單,貼出關鍵代碼:

 

#include <jni.h>
#include <jvmti.h>


jvmtiEnv* m_pJvmTI =NULL;

void JNICALL cbClassFileLoadHook(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)

{

    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;

    }

    m_pJvmTI =jvmti;

    jvmtiCapabilities capabilities;

     //  Clear the capabilities structure and set the ones you need.

    ( void)memset(&capabilities, 0sizeof(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, 0sizeof(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.

}
 
 

 參考資料:

http://java.sun.com/developer/technicalArticles/J2SE/jvm_ti/

http://docs.oracle.com/javase/1.5.0/docs/guide/jvmti/jvmti.html

 

加密程序和解密庫

http://files.cnblogs.com/lancao008/declass.rar

 

ps:

真正用在公司是java服務器的話,可以考慮寫個配置文件通過網卡mac地址通過算法生成一個序列號,在動態庫里算出序列號比較,如果不正確就不加載,然后把動態庫加密,以防很容易就反匯編看出來!!!

 

linux下編譯:

g++ -I${JAVA_HOME}/include/ -I${JAVA_HOME}/include/linux declass.cpp -shared -o libdeclass.so -m32

 

附上說明

 

Hello 為java .class文件
windows
java -agentlib:c:\jvm\deClass Hello
deClass就是deClass.dll,注意不需要加.dll

tomcat
修改tomcat的bin目錄下catalina.bat
set JAVA_OPTS=-agentlib:c:\jvm\deClass

linux下

拷貝libdeclass.so到/lib下
java -agentlib:declass Hello

tomcat:
修改catalina.sh

JAVA_OPTS =-agentlib:declass

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM