大家知道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之前的一个事件,函数接口

 



 



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, 
     0,  
     sizeof(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, 
   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; 
   



     
   // 
    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, 
   0,  
   sizeof(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. 
   
 
   
}


加密程序和解密库


 

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