core-lib / xjar

Spring Boot JAR 安全加密运行工具,支持的原生JAR。
Apache License 2.0
1.65k stars 471 forks source link

运行是输入密码,这样别人也可以通过密码解密代码,请问是否可以避免,谢谢 #1

Open hotcatteam opened 5 years ago

hei66 commented 5 years ago

C++代码(就一个文件,第一次写C代码,水平有限;使用VS2010编译时需要在C++路径中加入Java及mbedTLS头文件还有mbedTLS的lib) JVMTI请参考:https://github.com/sea-boat/ByteCodeEncrypt mbedTLS请参考:https://www.cnblogs.com/fudong071234/p/6591844.html

#include <iostream>
#include <string.h>

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

#include <aes.h>
#pragma comment(lib, "mbedTLS.lib")

void decrypt(int *destLen, char *src, int srcLen, unsigned char** new_class_data)
{
  // 128 bit key
  char *key = "xxxxxxxxxxxxxxxx";

  mbedtls_aes_context aes_ctx; 
  mbedtls_aes_init( &aes_ctx );  

  //设置解密密钥  
  mbedtls_aes_setkey_dec( &aes_ctx, (unsigned char *)key, 128);

  //获取块的数量
  int block = srcLen / 16;

  unsigned char* dest = *new_class_data;

  //清空
  memset(dest, 0, *destLen);

  //分块解密,每块16字节长度
  unsigned char input[16];
  unsigned char outout[16];

  int b = 0;
  while( b < block ){
      int offset = b * 16;
      int len = 0;
      if((srcLen - 16 - offset) > 0 ){
          len = 16;
      }else{
          len = srcLen-offset;
      }

      memset(input, 0 ,16);
      memset(outout, 0, 16);
      memcpy(input, &src[offset], len);

      //解密
      mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_DECRYPT, input, outout ); 
      if (b == 381) {
                        // 分块后剩余字节数
          memcpy(&dest[6096], outout, **9**);
      } else {
          memcpy(&dest[b * 16], outout, 16);
      }
      b++;
  }

  mbedtls_aes_free(&aes_ctx);
}

void JNICALL ClassDecryptHook(
  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
  )
{
  if (name && strncmp(name, "io/xjar/XLauncher", 17) == 0) {
      //动态分配内存(注意:这是XLauncher.class原始长度)
      *new_class_data_len = **6105;**
      jvmti_env->Allocate(*new_class_data_len, new_class_data);
      decrypt((int *)new_class_data_len, (char *)class_data, class_data_len, new_class_data);
  }
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
  jvmtiEnv *jvmti;
  // Create the JVM TI environment(jvmti)
  jint ret = vm->GetEnv((void **)&jvmti, JVMTI_VERSION);
  if (JNI_OK != ret)
  {
      printf("ERROR: Unable to access JVMTI!\n");
      return ret;
  }
  jvmtiCapabilities capabilities;
  (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;

  jvmtiError error = jvmti->AddCapabilities(&capabilities);
  if (JVMTI_ERROR_NONE != error)
  {
      printf("ERROR: Unable to AddCapabilities JVMTI!\n");
      return error;
  }

  jvmtiEventCallbacks callbacks;
  (void)memset(&callbacks, 0, sizeof(callbacks));

  callbacks.ClassFileLoadHook = &ClassDecryptHook;
  error = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
  if (JVMTI_ERROR_NONE != error) {
      printf("ERROR: Unable to SetEventCallbacks JVMTI!\n");
      return error;
  }

  error = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
  if (JVMTI_ERROR_NONE != error) {
      printf("ERROR: Unable to SetEventNotificationMode JVMTI!\n");
      return error;
  }

  return JNI_OK;
}

通过JVMTI来加密 XLauncher,但VMTI 只对类是由系统类加载器才能找到对应的类,而XLauncher 不是由系统加载器加载的,请问您是如何解决这个问题。

image

image

core-lib commented 5 years ago

没太明白你的问题 你说下你要达到什么目标 遇到了什么问题

Ftrybe commented 5 years ago

修改XLauncher(最直接、最笨的办法)

public class XLauncher implements XConstants {
    public final String[] args;
    public final XDecryptor xDecryptor;
    public final XEncryptor xEncryptor;
    public final XKey xKey;

    public XLauncher(String... args) throws Exception {
        this.args = args;
        String algorithm = DEFAULT_ALGORITHM;
        int keysize = DEFAULT_KEYSIZE;
        int ivsize = DEFAULT_IVSIZE;
        **String password = "xxxxxxxxxxxxxxxx";**
        String keypath = null;
 ... ...

使用命令运行jar的时候,不报错,但不会加载jar包,直接结束了。 `D:\workspace>java -agentlib:xjar -jar xxx-encrypted.jar (命令行下无任何信息) D:\workspace>

Ftrybe commented 5 years ago

修改XLauncher(最直接、最笨的办法)

public class XLauncher implements XConstants {
    public final String[] args;
    public final XDecryptor xDecryptor;
    public final XEncryptor xEncryptor;
    public final XKey xKey;

    public XLauncher(String... args) throws Exception {
        this.args = args;
        String algorithm = DEFAULT_ALGORITHM;
        int keysize = DEFAULT_KEYSIZE;
        int ivsize = DEFAULT_IVSIZE;
        **String password = "xxxxxxxxxxxxxxxx";**
        String keypath = null;
 ... ...

使用命令运行jar的时候,不报错,但不会加载jar包,直接结束了。 `D:\workspace>java -agentlib:xjar -jar xxx-encrypted.jar (命令行下无任何信息) D:\workspace>

OK. C++ 解密部分代码 //解密 mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_DECRYPT, input, outout ); if (b == 381) { // 分块后剩余字节数 memcpy(&dest[6096], outout, **9**); } else { memcpy(&dest[b * 16], outout, 16); } b++; 分块数目和输出字节需要根据生成的数据大小重新计算。本人获取得大小为6672 .b=417 if (b == 417) { // 分块后剩余字节数 memcpy(&dest[6672], outout, 0); } 成功运行

core-lib commented 5 years ago

你对C++编译方面了解吗 我目前卡在这里