内容:
![](/icons/72924yi.gif)
、为什么要加密?
2、定制类装入器
3、加密、解密
4、应用例子
5、注意事项
参考资源
作者介绍
俞良松(
[email protected])
软件Software工程师
![](/icons/72924dou.gif)
独立顾问和自由撰稿人
2001年10月
Java
![](/icons/72924chengxu.gif)
![](/icons/72924de.gif)
源代码很容易被别人偷看
![](/icons/72924dou2.gif)
只要有
![](/icons/72924yi.gif)
个反编译器
![](/icons/72924dou.gif)
任何人都可以分析别人
![](/icons/72924de.gif)
代码
![](/icons/72924dou2.gif)
本文讨论如何在不修改原有
![](/icons/72924chengxu.gif)
![](/icons/72924de.gif)
情况下
![](/icons/72924dou.gif)
通过加密技术保护源代码
![](/icons/72924dou2.gif)
![](/icons/72924yi.gif)
、为什么要加密?
对于传统
![](/icons/72924de.gif)
C或C
![](/icons/72924jiajia.gif)
的类
![](/icons/72924de.gif)
语言来说
![](/icons/72924dou.gif)
要在Web上保护源代码是很容易
![](/icons/72924de.gif)
![](/icons/72924dou.gif)
只要不发布它就可以
![](/icons/72924dou2.gif)
遗憾
![](/icons/72924de.gif)
是
![](/icons/72924dou.gif)
Java
![](/icons/72924chengxu.gif)
![](/icons/72924de.gif)
源代码很容易被别人偷看
![](/icons/72924dou2.gif)
只要有
![](/icons/72924yi.gif)
个反编译器
![](/icons/72924dou.gif)
任何人都可以分析别人
![](/icons/72924de.gif)
代码
![](/icons/72924dou2.gif)
Java
![](/icons/72924de.gif)
灵活性使得源代码很容易被窃取
![](/icons/72924dou.gif)
但和此同时
![](/icons/72924dou.gif)
它也使通过加密保护代码变得相对容易
![](/icons/72924dou.gif)
我们唯
![](/icons/72924yi.gif)
需要了解
![](/icons/72924de.gif)
就是Java
![](/icons/72924de.gif)
ClassLoader对象
![](/icons/72924dou2.gif)
当然
![](/icons/72924dou.gif)
在加密过程中
![](/icons/72924dou.gif)
有关JavaCryptographyExtension(JCE)
![](/icons/72924de.gif)
知识也是必不可少
![](/icons/72924de.gif)
![](/icons/72924dou2.gif)
有几种技术可以“模糊”Java类文件
![](/icons/72924dou.gif)
使得反编译器处理类文件
![](/icons/72924de.gif)
效果大打折扣
![](/icons/72924dou2.gif)
然而
![](/icons/72924dou.gif)
修改反编译器使的能够处理这些经过模糊处理
![](/icons/72924de.gif)
类文件并不是什么难事
![](/icons/72924dou.gif)
所以不能简单地依赖模糊技术来保证源代码
![](/icons/72924de.gif)
安全
![](/icons/72924dou2.gif)
我们可以用流行
![](/icons/72924de.gif)
加密工具加密应用
![](/icons/72924dou.gif)
比如PGP(PrettyGoodPrivacy)或GPG(GNUPrivacyGuard)
![](/icons/72924dou2.gif)
这时
![](/icons/72924dou.gif)
最终用户在运行应用的前必须先进行解密
![](/icons/72924dou2.gif)
但解密的后
![](/icons/72924dou.gif)
最终用户就有了
![](/icons/72924yi.gif)
份不加密
![](/icons/72924de.gif)
类文件
![](/icons/72924dou.gif)
这和事先不进行加密没有什么差别
![](/icons/72924dou2.gif)
Java运行时装入字节码
![](/icons/72924de.gif)
机制隐含地意味着可以对字节码进行修改
![](/icons/72924dou2.gif)
JVM每次装入类文件时都需要
![](/icons/72924yi.gif)
个称为ClassLoader
![](/icons/72924de.gif)
对象
![](/icons/72924dou.gif)
这个对象负责把新
![](/icons/72924de.gif)
类装入正在运行
![](/icons/72924de.gif)
JVM
![](/icons/72924dou2.gif)
JVM给ClassLoader
![](/icons/72924yi.gif)
个包含了待装入类(比如java.lang.Object)名字
![](/icons/72924de.gif)
![](/icons/72924zifu.gif)
串
![](/icons/72924dou.gif)
然后由ClassLoader负责找到类文件
![](/icons/72924dou.gif)
装入原始数据
![](/icons/72924dou.gif)
并把它转换成
![](/icons/72924yi.gif)
个Class对象
![](/icons/72924dou2.gif)
我们可以通过定制ClassLoader
![](/icons/72924dou.gif)
在类文件执行的前修改它
![](/icons/72924dou2.gif)
这种技术
![](/icons/72924de.gif)
应用非常广泛——在这里
![](/icons/72924dou.gif)
它
![](/icons/72924de.gif)
用途是在类文件装入的时进行解密
![](/icons/72924dou.gif)
因此可以看成是
![](/icons/72924yi.gif)
种即时解密器
![](/icons/72924dou2.gif)
由于解密后
![](/icons/72924de.gif)
字节码文件永远不会保存到文件系统
![](/icons/72924dou.gif)
所以窃密者很难得到解密后
![](/icons/72924de.gif)
代码
![](/icons/72924dou2.gif)
由于把原始字节码转换成Class对象
![](/icons/72924de.gif)
过程完全由系统负责
![](/icons/72924dou.gif)
所以创建定制ClassLoader对象其实并不困难
![](/icons/72924dou.gif)
只需先获得原始数据
![](/icons/72924dou.gif)
接着就可以进行包含解密在内
![](/icons/72924de.gif)
任何转换
![](/icons/72924dou2.gif)
Java2在
![](/icons/72924yi.gif)
定程度上简化了定制ClassLoader
![](/icons/72924de.gif)
构建
![](/icons/72924dou2.gif)
在Java2中
![](/icons/72924dou.gif)
loadClass
![](/icons/72924de.gif)
缺省实现仍旧负责处理所有必需
![](/icons/72924de.gif)
步骤
![](/icons/72924dou.gif)
但为了顾及各种定制
![](/icons/72924de.gif)
类装入过程
![](/icons/72924dou.gif)
它还
![](/icons/72924diaoyong.gif)
![](/icons/72924yi.gif)
个新
![](/icons/72924de.gif)
findClass思路方法
![](/icons/72924dou2.gif)
这为我们编写定制
![](/icons/72924de.gif)
ClassLoader提供了
![](/icons/72924yi.gif)
条捷径
![](/icons/72924dou.gif)
减少了麻烦:只需覆盖findClass
![](/icons/72924dou.gif)
而不是覆盖loadClass
![](/icons/72924dou2.gif)
这种思路方法避免了重复所有装入器必需执行
![](/icons/72924de.gif)
公共步骤
![](/icons/72924dou.gif)
![](/icons/72924yinwei.gif)
这
![](/icons/72924yi.gif)
切由loadClass负责
![](/icons/72924dou2.gif)
不过
![](/icons/72924dou.gif)
本文
![](/icons/72924de.gif)
定制ClassLoader并不使用这种思路方法
![](/icons/72924dou2.gif)
原因很简单
![](/icons/72924dou2.gif)
如果由默认
![](/icons/72924de.gif)
ClassLoader先寻找经过加密
![](/icons/72924de.gif)
类文件
![](/icons/72924dou.gif)
它可以找到;但由于类文件已经加密
![](/icons/72924dou.gif)
所以它不会认可这个类文件
![](/icons/72924dou.gif)
装入过程将失败
![](/icons/72924dou2.gif)
因此
![](/icons/72924dou.gif)
我们必须自己实现loadClass
![](/icons/72924dou.gif)
稍微增加了
![](/icons/72924yi.gif)
些工作量
![](/icons/72924dou2.gif)
2、定制类装入器
每
![](/icons/72924yi.gif)
个运行着
![](/icons/72924de.gif)
JVM已经拥有
![](/icons/72924yi.gif)
个ClassLoader
![](/icons/72924dou2.gif)
这个默认
![](/icons/72924de.gif)
ClassLoader根据CLASSPATH环境变量
![](/icons/72924de.gif)
值
![](/icons/72924dou.gif)
在本地文件系统中寻找合适
![](/icons/72924de.gif)
字节码文件
![](/icons/72924dou2.gif)
应用定制ClassLoader要求对这个过程有较为深入
![](/icons/72924de.gif)
认识
![](/icons/72924dou2.gif)
我们首先必须创建
![](/icons/72924yi.gif)
个定制ClassLoader类
![](/icons/72924de.gif)
例子
![](/icons/72924dou.gif)
然后显式地要求它装入另外
![](/icons/72924yi.gif)
个类
![](/icons/72924dou2.gif)
这就强制JVM把该类以及所有它所需要
![](/icons/72924de.gif)
类关联到定制
![](/icons/72924de.gif)
ClassLoader
![](/icons/72924dou2.gif)
Listing1显示了如何用定制ClassLoader装入类文件
![](/icons/72924dou2.gif)
【Listing1:利用定制
![](/icons/72924de.gif)
ClassLoader装入类文件】
//首先创建
![](/icons/72924yi.gif)
个ClassLoader对象
ClassLoadermyClassLoader=
![](/icons/72924new.gif)
myClassLoader
![](/icons/72924kh.gif)
;
//利用定制ClassLoader对象装入类文件
//并把它转换成Class对象
ClassmyClass=myClassLoader.loadClass(\"mypackage.MyClass\");
//最后
![](/icons/72924dou.gif)
创建该类
![](/icons/72924de.gif)
![](/icons/72924yi.gif)
个例子
Object
![](/icons/72924new.gif)
Instance=myClass.
![](/icons/72924new.gif)
Instance
![](/icons/72924kh.gif)
;
//注意
![](/icons/72924dou.gif)
MyClass所需要
![](/icons/72924de.gif)
所有其他类
![](/icons/72924dou.gif)
都将通过
//定制
![](/icons/72924de.gif)
ClassLoader自动装入
如前所述
![](/icons/72924dou.gif)
定制ClassLoader只需先获取类文件
![](/icons/72924de.gif)
数据
![](/icons/72924dou.gif)
然后把字节码传递给运行时系统
![](/icons/72924dou.gif)
由后者完成余下
![](/icons/72924de.gif)
任务
![](/icons/72924dou2.gif)
ClassLoader有几个重要
![](/icons/72924de.gif)
思路方法
![](/icons/72924dou2.gif)
创建定制
![](/icons/72924de.gif)
ClassLoader时
![](/icons/72924dou.gif)
我们只需覆盖其中
![](/icons/72924de.gif)
![](/icons/72924yi.gif)
个
![](/icons/72924dou.gif)
即loadClass
![](/icons/72924dou.gif)
提供获取原始类文件数据
![](/icons/72924de.gif)
代码
![](/icons/72924dou2.gif)
这个思路方法有两个参数:类
![](/icons/72924de.gif)
名字
![](/icons/72924dou.gif)
以及
![](/icons/72924yi.gif)
个表示JVM是否要求解析类名字
![](/icons/72924de.gif)
标记(即是否同时装入有依赖关系
![](/icons/72924de.gif)
类)
![](/icons/72924dou2.gif)
如果这个标记是true
![](/icons/72924dou.gif)
我们只需在返回JVM的前
![](/icons/72924diaoyong.gif)
resolveClass
![](/icons/72924dou2.gif)
【Listing2:ClassLoader.loadClass
![](/icons/72924kh.gif)
![](/icons/72924de.gif)
![](/icons/72924yi.gif)
个简单实现】
publicClassloadClass(Stringname,booleanresolve)
throwsClassNotFoundException{
try{
//我们要创建
![](/icons/72924de.gif)
Class对象
Classclasz=null;
//必需
![](/icons/72924de.gif)
步骤1:如果类已经在系统缓冲的中
![](/icons/72924dou.gif)
//我们不必再次装入它
clasz=findLoadedClass(name);
![](/icons/72924if.gif)
(clasz!=null)
![](/icons/72924return.gif)
clasz;
//下面是定制部分
![](/icons/72924byte.gif)
![](/icons/72924class.gif)
Data
![](/icons/72924zhk2.gif)
=/*通过某种思路方法获取字节码数据*/;
![](/icons/72924if.gif)
(
![](/icons/72924class.gif)
Data!=null){
//成功读取字节码数据
![](/icons/72924dou.gif)
现在把它转换成
![](/icons/72924yi.gif)
个Class对象
clasz=
![](/icons/72924define.gif)
Class(name,
![](/icons/72924class.gif)
Data,0,
![](/icons/72924class.gif)
Data.length);
}
//必需
![](/icons/72924de.gif)
步骤2:如果上面没有成功
![](/icons/72924dou.gif)
//我们尝试用默认
![](/icons/72924de.gif)
ClassLoader装入它
![](/icons/72924if.gif)
(clasz
![](/icons/72924dd.gif)
null)
clasz=find
![](/icons/72924System.gif)
Class(name);
//必需
![](/icons/72924de.gif)
步骤3:如有必要
![](/icons/72924dou.gif)
则装入相关
![](/icons/72924de.gif)
类
![](/icons/72924if.gif)
(resolve&&clasz!=null)
resolveClass(clasz);
//把类返回给
![](/icons/72924diaoyong.gif)
者
![](/icons/72924return.gif)
clasz;
}catch(IOExceptionie){
throw
![](/icons/72924new.gif)
ClassNotFoundException(ie.toString
![](/icons/72924kh.gif)
);
}catch(GeneralSecurityExceptiongse){
throw
![](/icons/72924new.gif)
ClassNotFoundException(gse.toString
![](/icons/72924kh.gif)
);
}
}
Listing2显示了
![](/icons/72924yi.gif)
个简单
![](/icons/72924de.gif)
loadClass实现
![](/icons/72924dou2.gif)
代码中
![](/icons/72924de.gif)
大部分对所有ClassLoader对象来说都
![](/icons/72924yi.gif)
样
![](/icons/72924dou.gif)
但有
![](/icons/72924yi.gif)
小部分(已通过注释标记)是特有
![](/icons/72924de.gif)
![](/icons/72924dou2.gif)
在处理过程中
![](/icons/72924dou.gif)
ClassLoader对象要用到其他几个辅助思路方法:
findLoadedClass:用来进行检查
![](/icons/72924dou.gif)
以便确认被请求
![](/icons/72924de.gif)
类当前还不存在
![](/icons/72924dou2.gif)
loadClass思路方法应该首先
![](/icons/72924diaoyong.gif)
它
![](/icons/72924dou2.gif)
![](/icons/72924define.gif)
Class:获得原始类文件字节码数据的后
![](/icons/72924dou.gif)
![](/icons/72924diaoyong.gif)
![](/icons/72924define.gif)
Class把它转换成
![](/icons/72924yi.gif)
个Class对象
![](/icons/72924dou2.gif)
任何loadClass实现都必须
![](/icons/72924diaoyong.gif)
这个思路方法
![](/icons/72924dou2.gif)
find
![](/icons/72924System.gif)
Class:提供默认ClassLoader
![](/icons/72924de.gif)
支持
![](/icons/72924dou2.gif)
如果用来寻找类
![](/icons/72924de.gif)
定制思路方法不能找到指定
![](/icons/72924de.gif)
类(或者有意地不用定制思路方法)
![](/icons/72924dou.gif)
则可以
![](/icons/72924diaoyong.gif)
该思路方法尝试默认
![](/icons/72924de.gif)
装入方式
![](/icons/72924dou2.gif)
这是很有用
![](/icons/72924de.gif)
![](/icons/72924dou.gif)
特别是从普通
![](/icons/72924de.gif)
JAR文件装入标准Java类时
![](/icons/72924dou2.gif)
resolveClass:当JVM想要装入
![](/icons/72924de.gif)
不仅包括指定
![](/icons/72924de.gif)
类
![](/icons/72924dou.gif)
而且还包括该类引用
![](/icons/72924de.gif)
所有其他类时
![](/icons/72924dou.gif)
它会把loadClass
![](/icons/72924de.gif)
resolve参数设置成true
![](/icons/72924dou2.gif)
这时
![](/icons/72924dou.gif)
我们必须在返回刚刚装入
![](/icons/72924de.gif)
Class对象给
![](/icons/72924diaoyong.gif)
者的前
![](/icons/72924diaoyong.gif)
resolveClass
![](/icons/72924dou2.gif)
3、加密、解密
Java加密扩展即JavaCryptographyExtension
![](/icons/72924dou.gif)
简称JCE
![](/icons/72924dou2.gif)
它是Sun
![](/icons/72924de.gif)
加密服务软件Software
![](/icons/72924dou.gif)
包含了加密和密匙生成功能
![](/icons/72924dou2.gif)
JCE是JCA(JavaCryptographyArchitecture)
![](/icons/72924de.gif)
![](/icons/72924yi.gif)
种扩展
![](/icons/72924dou2.gif)
JCE没有规定具体
![](/icons/72924de.gif)
加密算法
![](/icons/72924dou.gif)
但提供了
![](/icons/72924yi.gif)
个框架
![](/icons/72924dou.gif)
加密算法
![](/icons/72924de.gif)
具体实现可以作为服务提供者加入
![](/icons/72924dou2.gif)
除了JCE框架的外
![](/icons/72924dou.gif)
JCE软件Software包还包含了SunJCE服务提供者
![](/icons/72924dou.gif)
其中包括许多有用
![](/icons/72924de.gif)
加密算法
![](/icons/72924dou.gif)
比如DES(DataEncryptionStandard)和Blowfish
![](/icons/72924dou2.gif)
为简单计
![](/icons/72924dou.gif)
在本文中我们将用DES算法加密和解密字节码
![](/icons/72924dou2.gif)
下面是用JCE加密和解密数据必须遵循
![](/icons/72924de.gif)
基本步骤:
步骤1:生成
![](/icons/72924yi.gif)
个安全密匙
![](/icons/72924dou2.gif)
在加密或解密任何数据的前需要有
![](/icons/72924yi.gif)
个密匙
![](/icons/72924dou2.gif)
密匙是随同被加密
![](/icons/72924de.gif)
应用
![](/icons/72924yi.gif)
起发布
![](/icons/72924de.gif)
![](/icons/72924yi.gif)
小段数据
![](/icons/72924dou.gif)
Listing3显示了如何生成
![](/icons/72924yi.gif)
个密匙
![](/icons/72924dou2.gif)
【Listing3:生成
![](/icons/72924yi.gif)
个密匙】
//DES算法要求有
![](/icons/72924yi.gif)
个可信任
![](/icons/72924de.gif)
随机数源
SecureRandomsr=
![](/icons/72924new.gif)
SecureRandom
![](/icons/72924kh.gif)
;
//为我们选择
![](/icons/72924de.gif)
DES算法生成
![](/icons/72924yi.gif)
个KeyGenerator对象
KeyGeneratorkg=KeyGenerator.getInstance(\"DES\");
kg.init(sr);
//生成密匙
SecretKeykey=kg.generateKey
![](/icons/72924kh.gif)
;
//获取密匙数据
![](/icons/72924byte.gif)
rawKeyData
![](/icons/72924zhk2.gif)
=key.getEncoded
![](/icons/72924kh.gif)
;
/*接下来就可以用密匙进行加密或解密
![](/icons/72924dou.gif)
或者把它保存
为文件供以后使用*/
doSomething(rawKeyData);
步骤2:加密数据
![](/icons/72924dou2.gif)
得到密匙的后
![](/icons/72924dou.gif)
接下来就可以用它加密数据
![](/icons/72924dou2.gif)
除了解密
![](/icons/72924de.gif)
ClassLoader的外
![](/icons/72924dou.gif)
![](/icons/72924yi.gif)
般还要有
![](/icons/72924yi.gif)
个加密待发布应用
![](/icons/72924de.gif)
独立
![](/icons/72924chengxu.gif)
(见Listing4)
![](/icons/72924dou2.gif)
【Listing4:用密匙加密原始数据】
//DES算法要求有
![](/icons/72924yi.gif)
个可信任
![](/icons/72924de.gif)
随机数源
SecureRandomsr=
![](/icons/72924new.gif)
SecureRandom
![](/icons/72924kh.gif)
;
![](/icons/72924byte.gif)
rawKeyData
![](/icons/72924zhk2.gif)
=/*用某种思路方法获得密匙数据*/;
//从原始密匙数据创建DESKeySpec对象
DESKeySpecdks=
![](/icons/72924new.gif)
DESKeySpec(rawKeyData);
//创建
![](/icons/72924yi.gif)
个密匙工厂
![](/icons/72924dou.gif)
然后用它把DESKeySpec转换成
//
![](/icons/72924yi.gif)
个SecretKey对象
SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance(\"DES\");
SecretKeykey=keyFactory.generateSecret(dks);
//Cipher对象实际完成加密操作
Ciphercipher=Cipher.getInstance(\"DES\");
//用密匙
![](/icons/72924chushi.gif)
化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE,key,sr);
//现在
![](/icons/72924dou.gif)
获取数据并加密
![](/icons/72924byte.gif)
data
![](/icons/72924zhk2.gif)
=/*用某种思路方法获取数据*/
//正式执行加密操作
![](/icons/72924byte.gif)
encryptedData
![](/icons/72924zhk2.gif)
=cipher.doFinal(data);
//进
![](/icons/72924yi.gif)
步处理加密后
![](/icons/72924de.gif)
数据
doSomething(encryptedData);
步骤3:解密数据
![](/icons/72924dou2.gif)
运行经过加密
![](/icons/72924de.gif)
应用时
![](/icons/72924dou.gif)
ClassLoader分析并解密类文件
![](/icons/72924dou2.gif)
操作步骤如Listing5所示
![](/icons/72924dou2.gif)
【Listing5:用密匙解密数据】
//DES算法要求有
![](/icons/72924yi.gif)
个可信任
![](/icons/72924de.gif)
随机数源
SecureRandomsr=
![](/icons/72924new.gif)
SecureRandom
![](/icons/72924kh.gif)
;
![](/icons/72924byte.gif)
rawKeyData
![](/icons/72924zhk2.gif)
=/*用某种思路方法获取原始密匙数据*/;
//从原始密匙数据创建
![](/icons/72924yi.gif)
个DESKeySpec对象
DESKeySpecdks=
![](/icons/72924new.gif)
DESKeySpec(rawKeyData);
//创建
![](/icons/72924yi.gif)
个密匙工厂
![](/icons/72924dou.gif)
然后用它把DESKeySpec对象转换成
//
![](/icons/72924yi.gif)
个SecretKey对象
SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance(\"DES\");
SecretKeykey=keyFactory.generateSecret(dks);
//Cipher对象实际完成解密操作
Ciphercipher=Cipher.getInstance(\"DES\");
//用密匙
![](/icons/72924chushi.gif)
化Cipher对象
cipher.init(Cipher.DECRYPT_MODE,key,sr);
//现在
![](/icons/72924dou.gif)
获取数据并解密
![](/icons/72924byte.gif)
encryptedData
![](/icons/72924zhk2.gif)
=/*获得经过加密
![](/icons/72924de.gif)
数据*/
//正式执行解密操作
![](/icons/72924byte.gif)
decryptedData
![](/icons/72924zhk2.gif)
=cipher.doFinal(encryptedData);
//进
![](/icons/72924yi.gif)
步处理解密后
![](/icons/72924de.gif)
数据
doSomething(decryptedData);
4、应用例子
前面介绍了如何加密和解密数据
![](/icons/72924dou2.gif)
要部署
![](/icons/72924yi.gif)
个经过加密
![](/icons/72924de.gif)
应用
![](/icons/72924dou.gif)
步骤如下:
步骤1:创建应用
![](/icons/72924dou2.gif)
我们
![](/icons/72924de.gif)
例子包含
![](/icons/72924yi.gif)
个App主类
![](/icons/72924dou.gif)
两个辅助类(分别称为Foo和Bar)
![](/icons/72924dou2.gif)
这个应用没有什么实际功用
![](/icons/72924dou.gif)
但只要我们能够加密这个应用
![](/icons/72924dou.gif)
加密其他应用也就不在话下
![](/icons/72924dou2.gif)
步骤2:生成
![](/icons/72924yi.gif)
个安全密匙
![](/icons/72924dou2.gif)
在命令行
![](/icons/72924dou.gif)
利用GenerateKey工具(参见GenerateKey.java)把密匙写入
![](/icons/72924yi.gif)
个文件:%javaGenerateKeykey.data
步骤3:加密应用
![](/icons/72924dou2.gif)
在命令行
![](/icons/72924dou.gif)
利用EncryptClasses工具(参见EncryptClasses.java)加密应用
![](/icons/72924de.gif)
类:%javaEncryptClasseskey.dataApp.
![](/icons/72924class.gif)
Foo.
![](/icons/72924class.gif)
Bar.
![](/icons/72924class.gif)
该命令把每
![](/icons/72924yi.gif)
个.
![](/icons/72924class.gif)
文件替换成它们各自
![](/icons/72924de.gif)
加密版本
![](/icons/72924dou2.gif)
步骤4:运行经过加密
![](/icons/72924de.gif)
应用
![](/icons/72924dou2.gif)
用户通过
![](/icons/72924yi.gif)
个DecryptStart
![](/icons/72924chengxu.gif)
运行经过加密
![](/icons/72924de.gif)
应用
![](/icons/72924dou2.gif)
DecryptStart
![](/icons/72924chengxu.gif)
如Listing6所示
![](/icons/72924dou2.gif)
【Listing6:DecryptStart.java
![](/icons/72924dou.gif)
启动被加密应用
![](/icons/72924de.gif)
![](/icons/72924chengxu.gif)
】
importjava.io.*;
importjava.security.*;
importjava.lang.reflect.*;
importjavax.crypto.*;
importjavax.crypto.spec.*;
public
![](/icons/72924class.gif)
DecryptStartextendsClassLoader
{
//这些对象在构造
![](/icons/72924hanshu.gif)
中设置
![](/icons/72924dou.gif)
//以后loadClass
![](/icons/72924kh.gif)
思路方法将利用它们解密类
privateSecretKeykey;
privateCiphercipher;
//构造
![](/icons/72924hanshu.gif)
:设置解密所需要
![](/icons/72924de.gif)
对象
publicDecryptStart(SecretKeykey)throwsGeneralSecurityException,
IOException{
this.key=key;
Stringalgorithm=\"DES\";
SecureRandomsr=
![](/icons/72924new.gif)
SecureRandom
![](/icons/72924kh.gif)
;
![](/icons/72924System.gif)
.err.pr
![](/icons/72924int.gif)
ln(\"[DecryptStart:creatingcipher]\");
cipher=Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE,key,sr);
}
//
![](/icons/72924main.gif)
过程:我们要在这里读入密匙
![](/icons/72924dou.gif)
创建DecryptStart
![](/icons/72924de.gif)
//例子
![](/icons/72924dou.gif)
它就是我们
![](/icons/72924de.gif)
定制ClassLoader
![](/icons/72924dou2.gif)
//设置好ClassLoader以后
![](/icons/72924dou.gif)
我们用它装入应用例子
![](/icons/72924dou.gif)
//最后
![](/icons/72924dou.gif)
我们通过JavaReflectionAPI
![](/icons/72924diaoyong.gif)
应用例子
![](/icons/72924de.gif)
![](/icons/72924main.gif)
思路方法
![](/icons/72924static.gif)
publicvoid
![](/icons/72924main.gif)
(Stringargs
![](/icons/72924zhk2.gif)
)throwsException{
StringkeyFilename=args[0];
StringappName=args[1];
//这些是传递给应用本身
![](/icons/72924de.gif)
参数
StringrealArgs
![](/icons/72924zhk2.gif)
=
![](/icons/72924new.gif)
String[args.length-2];
![](/icons/72924System.gif)
.
![](/icons/72924<img src=)
.gif' />copy(args,2,realArgs,0,args.length-2);
//读取密匙
![](/icons/72924System.gif)
.err.pr
![](/icons/72924int.gif)
ln(\"[DecryptStart:readingkey]\");
![](/icons/72924byte.gif)
rawKey
![](/icons/72924zhk2.gif)
=Util.readFile(keyFilename);
DESKeySpecdks=
![](/icons/72924new.gif)
DESKeySpec(rawKey);
SecretKeyFactorykeyFactory=SecretKeyFactory.getInstance(\"DES\");
SecretKeykey=keyFactory.generateSecret(dks);
//创建解密
![](/icons/72924de.gif)
ClassLoader
DecryptStartdr=
![](/icons/72924new.gif)
DecryptStart(key);
//创建应用主类
![](/icons/72924de.gif)
![](/icons/72924yi.gif)
个例子
//通过ClassLoader装入它
![](/icons/72924System.gif)
.err.pr
![](/icons/72924int.gif)
ln(\"[DecryptStart:loading\"+appName+\"]\");
Classclasz=dr.loadClass(appName);
//最后
![](/icons/72924dou.gif)
通过ReflectionAPI
![](/icons/72924diaoyong.gif)
应用例子
//
![](/icons/72924de.gif)
![](/icons/72924main.gif)
![](/icons/72924kh.gif)
思路方法
//获取
![](/icons/72924yi.gif)
个对
![](/icons/72924main.gif)
![](/icons/72924kh.gif)
![](/icons/72924de.gif)
引用
Stringproto
![](/icons/72924zhk2.gif)
=
![](/icons/72924new.gif)
String[1];
Class
![](/icons/72924main.gif)
Args
![](/icons/72924zhk2.gif)
={(
![](/icons/72924new.gif)
String[1]).getClass
![](/icons/72924kh.gif)
};
Method
![](/icons/72924main.gif)
=clasz.getMethod(\"
![](/icons/72924main.gif)
\",
![](/icons/72924main.gif)
Args);
//创建
![](/icons/72924yi.gif)
个包含
![](/icons/72924main.gif)
![](/icons/72924kh.gif)
思路方法参数
![](/icons/72924de.gif)
![](/icons/72924shuzu.gif)
ObjectargsArray
![](/icons/72924zhk2.gif)
={realArgs};
![](/icons/72924System.gif)
.err.pr
![](/icons/72924int.gif)
ln(\"[DecryptStart:running\"+appName+\".
![](/icons/72924main.gif)
![](/icons/72924kh.gif)
]\");
//
![](/icons/72924diaoyong.gif)
![](/icons/72924main.gif)
![](/icons/72924kh.gif)
![](/icons/72924main.gif)
.invoke(null,argsArray);
}
publicClassloadClass(Stringname,booleanresolve)
throwsClassNotFoundException{
try{
//我们要创建
![](/icons/72924de.gif)
Class对象
Classclasz=null;
//必需
![](/icons/72924de.gif)
步骤1:如果类已经在系统缓冲的中
//我们不必再次装入它
clasz=findLoadedClass(name);
![](/icons/72924if.gif)
(clasz!=null)
![](/icons/72924return.gif)
clasz;
//下面是定制部分
try{
//读取经过加密
![](/icons/72924de.gif)
类文件
![](/icons/72924byte.gif)
![](/icons/72924class.gif)
Data
![](/icons/72924zhk2.gif)
=Util.readFile(name+\".
![](/icons/72924class.gif)
\");
![](/icons/72924if.gif)
(
![](/icons/72924class.gif)
Data!=null){
//解密...
![](/icons/72924byte.gif)
decryptedClassData
![](/icons/72924zhk2.gif)
=cipher.doFinal(
![](/icons/72924class.gif)
Data);
//...再把它转换成
![](/icons/72924yi.gif)
个类
clasz=
![](/icons/72924define.gif)
Class(name,decryptedClassData,
0,decryptedClassData.length);
![](/icons/72924System.gif)
.err.pr
![](/icons/72924int.gif)
ln(\"[DecryptStart:decrypting
![](/icons/72924class.gif)
\"+name+\"]\");
}
}catch(FileNotFoundExceptionfnfe){
}
//必需
![](/icons/72924de.gif)
步骤2:如果上面没有成功
//我们尝试用默认
![](/icons/72924de.gif)
ClassLoader装入它
![](/icons/72924if.gif)
(clasz
![](/icons/72924dd.gif)
null)
clasz=find
![](/icons/72924System.gif)
Class(name);
//必需
![](/icons/72924de.gif)
步骤3:如有必要
![](/icons/72924dou.gif)
则装入相关
![](/icons/72924de.gif)
类
![](/icons/72924if.gif)
(resolve&&clasz!=null)
resolveClass(clasz);
//把类返回给
![](/icons/72924diaoyong.gif)
者
![](/icons/72924return.gif)
clasz;
}catch(IOExceptionie){
throw
![](/icons/72924new.gif)
ClassNotFoundException(ie.toString
![](/icons/72924kh.gif)
);
}catch(GeneralSecurityExceptiongse){
throw
![](/icons/72924new.gif)
ClassNotFoundException(gse.toString
);
}
}
}
对于未经加密
![](/icons/72924de.gif)
应用
![](/icons/72924dou.gif)
正常执行方式如下:%javaApparg0arg1arg2
对于经过加密
![](/icons/72924de.gif)
应用
![](/icons/72924dou.gif)
则相应
![](/icons/72924de.gif)
运行方式为:%javaDecryptStartkey.dataApparg0arg1arg2
DecryptStart有两个目
![](/icons/72924de.gif)
![](/icons/72924dou2.gif)
![](/icons/72924yi.gif)
个DecryptStart
![](/icons/72924de.gif)
例子就是
![](/icons/72924yi.gif)
个实施即时解密操作
![](/icons/72924de.gif)
定制ClassLoader;同时
![](/icons/72924dou.gif)
DecryptStart还包含
![](/icons/72924yi.gif)
个
![](/icons/72924main.gif)
过程
![](/icons/72924dou.gif)
它创建解密器例子并用它装入和运行应用
![](/icons/72924dou2.gif)
举例应用App
![](/icons/72924de.gif)
代码包含在App.java、Foo.java和Bar.java内
![](/icons/72924dou2.gif)
Util.java是
![](/icons/72924yi.gif)
个文件I/O工具
![](/icons/72924dou.gif)
本文举例多处用到了它
![](/icons/72924dou2.gif)
完整
![](/icons/72924de.gif)
代码请从本文最后下载
![](/icons/72924dou2.gif)
5、注意事项
我们看到
![](/icons/72924dou.gif)
要在不修改源代码
![](/icons/72924de.gif)
情况下加密
![](/icons/72924yi.gif)
个Java应用是很容易
![](/icons/72924de.gif)
![](/icons/72924dou2.gif)
不过
![](/icons/72924dou.gif)
世上没有完全安全
![](/icons/72924de.gif)
系统
![](/icons/72924dou2.gif)
本文
![](/icons/72924de.gif)
加密方式提供了
![](/icons/72924yi.gif)
定程度
![](/icons/72924de.gif)
源代码保护
![](/icons/72924dou.gif)
但对某些攻击来说它是脆弱
![](/icons/72924de.gif)
![](/icons/72924dou2.gif)
虽然应用本身经过了加密
![](/icons/72924dou.gif)
但启动
![](/icons/72924chengxu.gif)
DecryptStart没有加密
![](/icons/72924dou2.gif)
攻击者可以反编译启动
![](/icons/72924chengxu.gif)
并修改它
![](/icons/72924dou.gif)
把解密后
![](/icons/72924de.gif)
类文件保存到磁盘
![](/icons/72924dou2.gif)
降低这种风险
![](/icons/72924de.gif)
办法的
![](/icons/72924yi.gif)
是对启动
![](/icons/72924chengxu.gif)
进行高质量
![](/icons/72924de.gif)
模糊处理
![](/icons/72924dou2.gif)
或者
![](/icons/72924dou.gif)
启动
![](/icons/72924chengxu.gif)
也可以采用直接编译成机器语言
![](/icons/72924de.gif)
代码
![](/icons/72924dou.gif)
使得启动
![](/icons/72924chengxu.gif)
具有传统执行文件格式
![](/icons/72924de.gif)
安全性
![](/icons/72924dou2.gif)
另外还要记住
![](/icons/72924de.gif)
是
![](/icons/72924dou.gif)
大多数JVM本身并不安全
![](/icons/72924dou2.gif)
狡猾
![](/icons/72924de.gif)
黑客可能会修改JVM
![](/icons/72924dou.gif)
从ClassLoader的外获取解密后
![](/icons/72924de.gif)
代码并保存到磁盘
![](/icons/72924dou.gif)
从而绕过本文
![](/icons/72924de.gif)
加密技术
![](/icons/72924dou2.gif)
Java没有为此提供真正有效
![](/icons/72924de.gif)
补救措施
![](/icons/72924dou2.gif)
不过应该指出
![](/icons/72924de.gif)
是
![](/icons/72924dou.gif)
所有这些可能
![](/icons/72924de.gif)
攻击都有
![](/icons/72924yi.gif)
个前提
![](/icons/72924dou.gif)
这就是攻击者可以得到密匙
![](/icons/72924dou2.gif)
如果没有密匙
![](/icons/72924dou.gif)
应用
![](/icons/72924de.gif)
安全性就完全取决于加密算法
![](/icons/72924de.gif)
安全性
![](/icons/72924dou2.gif)
虽然这种保护代码
![](/icons/72924de.gif)
思路方法称不上十全十美
![](/icons/72924dou.gif)
但它仍不失为
![](/icons/72924yi.gif)
种保护知识产权和敏感用户数据
![](/icons/72924de.gif)
有效方案
![](/icons/72924dou2.gif)
参考资源
在运行时刻更新功能模块
![](/icons/72924dou2.gif)
介绍了
![](/icons/72924yi.gif)
个利用类库加载器ClassLoader实现在运行时刻更新部分功能模块
![](/icons/72924de.gif)
Java
![](/icons/72924chengxu.gif)
![](/icons/72924dou.gif)
并将其和C/C
![](/icons/72924jiajia.gif)
中实现同样功能
![](/icons/72924de.gif)
动态链接库方案进行了比较
![](/icons/72924dou2.gif)
Java窍门技巧105:利用JWhich掌握类路径
![](/icons/72924dou2.gif)
展示
![](/icons/72924yi.gif)
个简单
![](/icons/72924de.gif)
工具
![](/icons/72924dou.gif)
它可以清楚地确定类装载器从类路径中载入了什么Java类
![](/icons/72924dou2.gif)
要了解更多
![](/icons/72924de.gif)
Java安全信息
![](/icons/72924dou.gif)
请阅读java.sun.com
![](/icons/72924de.gif)
JavaSecurityAPI页
![](/icons/72924dou2.gif)
如何封锁您
![](/icons/72924de.gif)
(或打开别人
![](/icons/72924de.gif)
)Java代码
![](/icons/72924dou2.gif)
Java代码反编译和模糊处理
![](/icons/72924de.gif)
指南
![](/icons/72924dou2.gif)
使您
![](/icons/72924de.gif)
软件Software运行起来:摆弄数字
![](/icons/72924dou2.gif)
真正安全
![](/icons/72924de.gif)
软件Software需要精确
![](/icons/72924de.gif)
随机数生成器
![](/icons/72924dou2.gif)
下载本文代码:EncryptedJavaClass_code.zip
有关作者
俞良松
![](/icons/72924dou.gif)
软件Software工程师
![](/icons/72924dou.gif)
独立顾问和自由撰稿人
![](/icons/72924dou2.gif)
最初从事PB和Oracle开发
![](/icons/72924dou.gif)
现主要兴趣在于Internet开发
![](/icons/72924dou2.gif)
您可以通过
[email protected]和我联系
延伸阅读
最新评论