JAVA Class文件加密小探

背景

我们基于TrueLicense实现了license的校验。这块网上资料很多,在此就不加以介绍了。今天主要想说一说机器指纹的问题。

主要包括如下两部分:

1、指纹的采集生成

2、指纹的校验

我们所做的一切都是防君子不防小人,任何东东都有破解的方式方法,能做的只是增加其难度。项目中的开发语言使用的是java,由于java的跨平台特性,jvm加载执行的是字节码,字节码有一套规范,很容易进行反编译。基于此,我们做了如下工作:

指纹采集

使用go语言采集机器指纹信息,机器指纹是线下采集,采集的信息需要进行加密,我们使用的是的AES对称加密。目前支持:

/*****************************

*arm架构,Linux version 4.19.90-9.ky10.aarch64 (YHKYLIN-OS@kernel-rpmbuild-amd64) (gcc version 7.3.0 (GCC)) #1 SMP Sun Apr 26 11:05:59 CST 2020

*amd64架构,CentOS Linux release 7.2.1511 (Core)

******************************/

采集上来的密文,通过解密工具解密获取到明文,然后作为license的扩展参数加密存储(sm2)。

对Licencse管理类进行加密

基于JVM Tool Interface对加密的类进行解密

加密和解密是对应的。由于C或者C++加解密基本都需要依赖第三方软件,其间,我们尝试了基于openssl的rsa、des加密,结果都不仅如人意,主要还是依赖太多,我们的需求很简单,想使用一个简单且不依赖第三方库的算法,于是我们打算使用tea算法,简单高效。然后选择了xxtea-c尝试对class文件进行加密。

新建C++工程

xxtea-c github地址:github.com/xxtea/xxtea...

将xxtea.c、xxtea.h拷贝到BytecodeCrypto cpp工程下,我在windows下使用的是Microsoft Visual Studio Community 2019。安装好后,配置好环境变量就可以使用cl命令了。

编写BytecodeCrypto.cpp文件

头文件:

arduino 复制代码
#include "BytecodeCrypto.h
"#include "xxtea.h"
#include <jni.h>
#include <jvmti.h>
#include <jni_md.h>

BytecodeCrypto.h里面主要定义了加密方法,后面供java调用。xxtea.h为xxtea-c工程的头文件,主要定义了xtea的加解密方法。jni、jvmti、jni_md为jvm相关的头文件。

核心加密逻辑:

scss 复制代码
Java_cn_cuiot_dmp_util_BytecodeCrypto_encrypt(JNIEnv * env, jclass cla, jbyteArray j_array){ 
       char* dst = (char*)env->GetByteArrayElements(j_array, 0);        
       int len_arr = env->GetArrayLength(j_array);        
       size_t len;        
       unsigned char* encrypt_data = (unsigned char*)xxtea_encrypt(dst, len_arr, XXTEA_SECRET, &len);        
       jbyteArray c_result = env->NewByteArray(len);        
       env->SetByteArrayRegion(c_result, 0, len, (jbyte*)encrypt_data);        
       return c_result;
}

核心解密逻辑:

ini 复制代码
void JNICALL BytecodeCryptoHook(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, "cn/cuiot/dmp/crypto", 19) == 0) {
                  size_t len;                  
                  unsigned char* decrypt_data = (unsigned char*)xxtea_decrypt(class_data, class_data_len, XXTEA_SECRET, &len);                  
                  *new_class_data_len = len;                  
                  jvmti_env->Allocate(len, new_class_data);                  
                  unsigned char* _data = *new_class_data;                 
                  for (int i = 0; i < class_data_len; i++){                       
                   _data[i] = decrypt_data[i];                  
                  }        
        }else {                 
                  *new_class_data_len = class_data_len;                  
                  jvmti_env->Allocate(class_data_len, new_class_data);                 
                  unsigned char* _data = *new_class_data;                 
                  for (int i = 0; i < class_data_len; i++){
                         _data[i] = class_data[i];                  
                  }                
         }
}

生成xxtea lib文件

由于xxtea-c是c代码,我们主程序是c++代码,所以事先需要生成lib文件。分别执行如下命令:

bash 复制代码
cl /EHsc -LDd xxtea.clib xxtea.obj /out:xxtea.lib

编译C++代码

perl 复制代码
cl /EHsc -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LDd BytecodeCrypto.cpp xxtea.lib

生产的dll文件就是我们需要的。

编写加密JAVA类BytecodeCrypto.java

ini 复制代码
public class BytecodeCrypto {
   static {
         System.load("D:\\mf\\BytecodeCrypto\\BytecodeCrypto\\BytecodeCrypto\\BytecodeCrypto.dll");
   }
    public native static byte[] encrypt(byte[] text);    
    public static void main(String[] args) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            String fileName = "D:\\mf\\Crypto.jar";
            File srcFile = new File(fileName);
            File dstFile = new File(fileName.substring(0, fileName.indexOf(".")) + "_encrypted.jar");
            FileOutputStream dstFos = new FileOutputStream(dstFile);JarOutputStream dstJar = new JarOutputStream(dstFos);
            JarFile srcJar = new JarFile(srcFile);
            for (Enumeration<JarEntry> enumeration = srcJar.entries(); enumeration.hasMoreElements();) {
                JarEntry entry = enumeration.nextElement();
                InputStream is = srcJar.getInputStream(entry);
                int len;
                while ((len = is.read(buf, 0, buf.length)) != -1) {
                    baos.write(buf, 0, len);
                }
                byte[] bytes = baos.toByteArray();
                String name = entry.getName();
                if (name.startsWith("cn/xxx/yyy/crypto/Crypto.class")) {
                    try {
                            bytes = BytecodeCrypto.encrypt(bytes);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                }
                JarEntry ne = new JarEntry(name);
                dstJar.putNextEntry(ne);
                dstJar.write(bytes);
                baos.reset();
                }
                srcJar.close();
                dstJar.close();
                dstFos.close();
                System.out.println("encrypt finished");
        } catch (Exception e) {
        e.printStackTrace();
}
}
}

配置好dll文件路径和加密前jar路径。执行main方法,会输出加密后的jar包:

Crypto_encrypted.jar,你可以使用反编译工具查看下是否已加密成功。

执行加密jar

arduino 复制代码
java -agentpath:"**\BytecodeCrypto.dll" -jar Crypto_encrypted.jar

如果一切顺利的话,将会执行main class的main方法。

相关推荐
cdut_suye8 分钟前
解锁函数的魔力:Python 中的多值传递、灵活参数与无名之美
java·数据库·c++·人工智能·python·机器学习·热榜
逍遥德1 小时前
java Map Set List 扩容机制
java·开发语言·list
高山上有一只小老虎1 小时前
mybatisplus实现分页查询
java·spring boot·mybatis
nbsaas-boot1 小时前
基于 Java 21 ScopedValue 的多租户动态数据源完整实践
java·开发语言
2301_780669861 小时前
线程安全、线程同步(三种加锁方式)、线程池(两种创建线程池方式、线程池处理Runnable任务、线程池处理Callable任务)、并发/并行
java
liuc03171 小时前
Java项目关于不同key的读取
java·开发语言
yaoxin5211231 小时前
296. Java Stream API - 二元操作符与“单位元“
java·服务器·windows
罗伯特_十三1 小时前
Spring AI ChatModel 使用记录
java·人工智能·spring
毕设源码-朱学姐1 小时前
【开题答辩全过程】以 基于SpringBoot的律师事务所管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
菜宾1 小时前
java-seata基础教学
java·开发语言·adb