当前位置:   article > 正文

基于jvmti和c++实现的class加密解密(一)_myclassfileloadhook

myclassfileloadhook

    任何任务都不会平白无故的产生,都是有需求的驱动。本文主要的产生原因是公司的web项目要进行产品化。将项目卖给多家并进行防反编译,本文在写作和实现的时候用到了晚上的资源。如有原作者有需要请联系我。本人将予以注明出处。

    作为一个没有任何密码学的人,刚开始接受这个任务的时候其实我是拒绝的。但是,最后还是落到了我的头上。那么开始吧,作为一个java程序员。我的第一反应是用java进行加密base64或des之类的加密算法进行加密。虽然实现了加密,但是存在的问题是解密类不能加密,解密的密钥在解密类中写的清清楚楚。利用该方案实现加密解密的方式为,写一个加密类将所有的要加密的class都进行循环遍历加密。然后通过重新classloader实现解密。但是重新的classloader是非加密的。所以忽略该方法。

    继续进行资料的收集会发现,java从1.5版本之后提供了JNI(Java Native Interface)JAVA本地接口。可以通过c++或c进行解密。但是这个也会遇到上一个方案所面临的问题。虽然解密的密码是写在c或c++的底层。但是调用jni的类是不加密的,可以通过改写这个jni类将解密后的class保存到本地。所以这个方案也被pass了。

    继续收集资料返现,java提供了jvmti接口来监控虚拟机的运行。引用方式为在java参数中设置-agentlib: 来进行调用。到这里,我们已经接近了加密功能的一般,通过agentlib进行解密的好处是在参数中直接可以调用.dll 或.so来进行解密。不会有没加密的class的问题。通过监听class加载的方式实现,将解密后的class直接放入虚拟机中不会存在。将解密后的class保存到本地的问题。所以得操作都是在dll中进行的。

   

  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <jvmti.h>
  4. #include <jni.h>
  5. #include <jni_md.h>
  6. #include "des.h"
  7. void JNICALL
  8. MyClassFileLoadHook(
  9. jvmtiEnv *jvmti_env,
  10. JNIEnv* jni_env,
  11. jclass class_being_redefined,
  12. jobject loader,
  13. const char* name,
  14. jobject protection_domain,
  15. jint class_data_len,
  16. const unsigned char* class_data,
  17. jint* new_class_data_len,
  18. unsigned char** new_class_data
  19. )
  20. {
  21. *new_class_data_len = class_data_len;
  22. jvmti_env->Allocate(class_data_len, new_class_data);
  23. unsigned char* my_data = *new_class_data;
  24. for(int i=0; i<class_data_len; i++)
  25. my_data[i] = class_data[i];
  26. char keyBlock[8];
  27. memcpy(keyBlock,class_data+16,8);
  28. if(strstr(keyBlock,"yangmo") ) {
  29. // printf("%s\n",keyBlock);
  30. // DES_Encrypt2(class_data,my_data,class_data_len,name);
  31. int lengthLLL = 0;
  32. int b =DES_Decrypt3(class_data,my_data, class_data_len,name,lengthLLL);
  33. // printf("wwwwwwwwwwww%d\n",b);
  34. // printf("bbbbbbbbbbbbbbbbbbbbbb%s%d\n",name,b);
  35. if(b!=0)
  36. *new_class_data_len = b;
  37. }
  38. }
  39. JNIEXPORT jint JNICALL
  40. Agent_OnLoad(
  41. JavaVM *vm,
  42. char *options,
  43. void *reserved
  44. )
  45. {
  46. jvmtiEnv *jvmti;
  47. jint ret = vm->GetEnv((void **)&jvmti, JVMTI_VERSION);
  48. if(JNI_OK!=ret)
  49. {
  50. printf("ERROR: Unable to access JVMTI!\n");
  51. return ret;
  52. }
  53. jvmtiCapabilities capabilities;
  54. (void)memset(&capabilities,0, sizeof(capabilities));
  55. capabilities.can_generate_all_class_hook_events = 1;
  56. capabilities.can_tag_objects = 1;
  57. capabilities.can_generate_object_free_events = 1;
  58. capabilities.can_get_source_file_name = 1;
  59. capabilities.can_get_line_numbers = 1;
  60. capabilities.can_generate_vm_object_alloc_events = 1;
  61. jvmtiError error = jvmti->AddCapabilities(&capabilities);
  62. if(JVMTI_ERROR_NONE!=error)
  63. {
  64. printf("ERROR: Unable to AddCapabilities JVMTI!\n");
  65. return error;
  66. }
  67. jvmtiEventCallbacks callbacks;
  68. (void)memset(&callbacks,0, sizeof(callbacks));
  69. callbacks.ClassFileLoadHook = &MyClassFileLoadHook;
  70. error = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
  71. if(JVMTI_ERROR_NONE!=error){
  72. printf("ERROR: Unable to SetEventCallbacks JVMTI!\n");
  73. return error;
  74. }
  75. error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
  76. if(JVMTI_ERROR_NONE!=error){
  77. printf("ERROR: Unable to SetEventNotificationMode JVMTI!\n");
  78. return error;
  79. }
  80. return JNI_OK;
  81. }

    上面的MyClassFileLoadHook这个方法是来进行解密的。其中下面的代码是来进行判断哪些是需要解密的,哪些是不需要解密的class。(没错就是用的我的英文名字……O(∩_∩)O哈哈~开玩笑)。DES_Decrypt3是进行解密的方式要传递的参数 加密后的2进制class,返回后的解密的clss,加密之后的class长度,class名字(含有包路径),额~~无用参数(本来是想返回解密后的文件长度的但是jint类型向下传递时遇到些问题,通过方法返回值绕过了这个问题。)

if(strstr(keyBlock,"yangmo") ) {
/int lengthLLL = 0;
   int b =DES_Decrypt3(class_data,my_data, class_data_len,name,lengthLLL);
  if(b!=0)
   *new_class_data_len = b; 
   }

    因为解密的程序是要生成jvmti能识别的动态库,因此需要引入JAVA_HOME/include/和JAVA_HOME/include/win32如下图所示。本人用的是dev-c++进行开发的。vs太高大上了搞不懂。


左面为加密后的截图,右面为加密前的截图。前16个字节没有进行加密,第17-24个字节是区分class加密没加密的标识符

    这个基本就是解密的流程了,具体解密代码就不贴了。有解密必然是有加密。下篇博客就是加密了。写的有些乱望大家海涵啊!

    作为一个有追求的懒人,一直都是写博客的打算。巴特,因为人懒所以一直都没有实现。今天,写下人生之中第一批博客。算是……算是2016的年终总结好了。一个很懒会喊666的咸鱼。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号