JAVA 类文件保护分析与研究
第二,加密过的 Class 文件在使用之前需先对其进行解密。
Java 虚拟机有默认的类加载器,但是若要它根据用户提供的密码解密代码就难以做到, 此时需要通过自定义 ClassLoader 类来完成加密类的装载。自定义的 ClassLoader 首先找到被 加密过的类,然后进行解密,最后将解密后的类装载到 JVM 中。这里我的自定义 ClassLoader 如下:
ClassLoader appLoader=new EncryptedClassLoader(EncryptedClassLoader.class.getClassLoader(), new File(args));
Thread.currentThread().setContextClassLoader(appLoader);
final Class app = appLoader.loadClass(args);
其中参数 args传入的是方法所在的工程名,args为主函数所在的类名。
在加载类后,系统的默认 findClass()并未对加载的类作任何处理,由于 Class 文件已被
加密过,此时若运用系统方法 findClass()则会抛出 ClassNotFoundException()的异常,所 以这里需要重构我自己的 findClass()方法:
protected Class findClass(final String name) throws ClassNotFoundException {
final String classResource = name.replace('.', '/') + ".class"; final URL classURL = getResource(classResource); InputStream in = null;
File file = new File(classURL.getPath());
byte[] classBytes = new byte[(int)file.length()]; FileInputStream fin = new FileInputStream(file); fin.read(classBytes);
……
classBytes = decrypt(classBytes); //解密
……
return defineClass(name, classBytes, 0, classBytes.length);
}
在这个函数中,我运用 decrypt(classBytes);方法对所有的加密 Class 文件进行解密,并 在其中调用方法 public static byte[] symmetricEncrypto(byte[] key, byte[] byteSource){}将解密 后的 Class 文件保存直原文件处,保持文件目录级别不变, key 为解密密钥,byteSource 为待
解密的 byte 型文件。至此,已完成对类文件的加密和解密,经过测试,功能已实现,Class
文件无法被反编译。但为进一步加强程序的安全性,我做了如下的处理。
第三,对包 含有关键信 息的方法进 行代码混淆 处理 。在 上述内容中 ,方 法 symmetricEncrypt(byte[] key, byte[] classData) 包含有加密 所用到的 算法,自 定义的 ClassLoader 包含有关键信息,findClass(final String name)以及 decrypt(classBytes);中包含有解 密信息,由于它们本身不是被加密的,因此它可能成为黑客最先攻击的目标。如果相关的解密密钥和算法被攻克,那么被加密的类也很容易被解密。所以这里我对这些关键代码进行代 码混淆。代码混淆是对代码进行重新组织和处理,使得处理后的代码与处理前的代码完成相 同的功能,但是混淆后的代码很难被反编译。代码混淆有符号混淆、数据混淆、控制混淆和 预防性混淆。这里我采用数据混淆对关键代码进行处理。
public static byte[] symmetricEncrypt(byte[] key, byte[] classData) {…};处理如下:
//rawKey,byteSource 为 symmetricEncrypt(byte[], byte[])的待传入参数
byte[] tempkey = null;
tempkey [0] = 0x00;
for (int i = 0; i < key.length; i++)
tempkey [i+1] = key[i];
tempkey [key.length + 1] = 0x11;
byte[] source = null;
source[0] = 0x00;
for(int i = 0; i < classData.length; i++) source[i+1] = classData[i]; source[classData.length + 1] = 0x11;
public static byte[] symmetricEncrypt(byte[]tempkey, byte[]source) {
//取 tempkey 和 source 的除第一个和最后一个 byte 的值
......
}
对 public Class loadClass(final String tempname, final boolean resolve){}方法进行处理:
String tempname = "abcdefg" + name ; //name:loadClass 的第一个待传入参数
public Class loadClass(final String tempname, final boolean resolve){ String name = tempname.substring(11,tempname.length());
......
}
对 findClass(String name){}方法进行处理:
//name 为 findClass(String name)待传入参数,先做如下处理
addname = name + "01357924680";
protected Class findClass(final String addname){
name = addname.substring(0,addname.length()-11);
...... //fingClass 其他工作
}
int len; //len = 待传文件 file 的长度:file.length()
byte[] classBytes = new byte[(int) len]; classBytes[len + 1] = 0x00; classBytes[len + 2] = 0x11;
//classBytes 作为 decrypt(byte[] classBytes)的传入参数
private static byte[] decrypt(final byte[] classBytes){
byte[] data = new byte[(int)classByte.lengt - 2];
for(int i = 0; i < data.length; i++)
data[i] = classBytes[i];
...... //解密工作
}
5. 结论
本文介绍了我针对 Java 类文件设计的保护方法,在众多方法中,我选择了对 Class 文件 进行加密这一思想,加密之后又对包含重要信息的方法进行代码混淆处理,这样就对文件起 到了双重保护的作用。经过在 Windows 平台上测试,效果良好,难以反编译,起到了很好 的保护作用。