Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 2403|回复: 0

防止Java程序源码被人偷窥应用实例

[复制链接]

该用户从未签到

发表于 2011-9-13 21:19:51 | 显示全部楼层 |阅读模式
前面介绍了如何加密和解密数据。要部署一个经过加密的应用,步骤如下:
  步骤1:创建应用。我们的例子包含一个App主类,两个辅助类(分别称为Foo和Bar)。这个应用没有什么实际功用,但只要我们能够加密这个应用,加密其他应用也就不在话下。
  步骤2:生成一个安全密匙。在命令行,利用GenerateKey工具(参见GenerateKey.java)把密匙写入一个文件: % java GenerateKey key.data
  步骤3:加密应用。在命令行,利用EncryptClasses工具(参见EncryptClasses.java)加密应用的类: % java EncryptClasses key.data App.class Foo.class Bar.class
  该命令把每一个.class文件替换成它们各自的加密版本。
  步骤4:运行经过加密的应用。用户通过一个DecryptStart程序运行经过加密的应用。DecryptStart程序如Listing 6所示。 【Listing 6:DecryptStart.java,启动被加密应用的程序】

以下是引用片段:
import java.io.*;
  import java.security.*;
  import java.lang.reflect.*;
  import javax.crypto.*;
  import javax.crypto.spec.*;
  public class DecryptStart extends ClassLoader
  {
  // 这些对象在构造函数中设置,
  // 以后loadClass()方法将利用它们解密类
  private SecretKey key;
  private Cipher cipher;
  // 构造函数:设置解密所需要的对象
  public DecryptStart( SecretKey key ) throws GeneralSecurityException,
  IOException {
  this.key = key;
  String algorithm = "DES";
  SecureRandom sr = new SecureRandom();
  System.err.println( "[DecryptStart: creating cipher]" );
  cipher = Cipher.getInstance( algorithm );
  cipher.init( Cipher.DECRYPT_MODE, key, sr );
  }
  // main过程:我们要在这里读入密匙,创建DecryptStart的
  // 实例,它就是我们的定制ClassLoader。
  // 设置好ClassLoader以后,我们用它装入应用实例,
  // 最后,我们通过Java Reflection API调用应用实例的main方法
  static public void main( String args[] ) throws Exception {
  String keyFilename = args[0];
  String appName = args[1];
  // 这些是传递给应用本身的参数
  String realArgs[] = new String[args.length-2];
  System.arraycopy( args, 2, realArgs, 0, args.length-2 );
  // 读取密匙
  System.err.println( "[DecryptStart: reading key]" );
  byte rawKey[] = Util.readFile( keyFilename );
  DESKeySpec dks = new DESKeySpec( rawKey );
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance( "DES" );
  SecretKey key = keyFactory.generateSecret( dks );
  // 创建解密的ClassLoader
  DecryptStart dr = new DecryptStart( key );
  // 创建应用主类的一个实例
  // 通过ClassLoader装入它
  System.err.println( "[DecryptStart: loading "+appName+"]" );
  Class clasz = dr.loadClass( appName );
  // 最后,通过Reflection API调用应用实例
  // 的main()方法
  // 获取一个对main()的引用
  String proto[] = new String[1];
  Class mainArgs[] = { (new String[1]).getClass() };
  Method main = clasz.getMethod( "main", mainArgs );
  // 创建一个包含main()方法参数的数组
  Object argsArray[] = { realArgs };
  System.err.println( "[DecryptStart: running "+appName+".main()]" );
  // 调用main()
  main.invoke( null, argsArray );
  }
  public Class loadClass( String name, boolean resolve )
  throws ClassNotFoundException {
  try {
  // 我们要创建的Class对象
  Class clasz = null;
  // 必需的步骤1:如果类已经在系统缓冲之中
  // 我们不必再次装入它
  clasz = findLoadedClass( name );
  if (clasz != null)
  return clasz;
  // 下面是定制部分
  try {
  // 读取经过加密的类文件
  byte classData[] = Util.readFile( name+".class" );
  if (classData != null) {
  // 解密...
  byte decryptedClassData[] = cipher.doFinal( classData );
  // ... 再把它转换成一个类
  clasz = defineClass( name, decryptedClassData,
  0, decryptedClassData.length );
  System.err.println( "[DecryptStart: decrypting class "+name+"]" );
  }
  } catch( FileNotFoundException fnfe )
  // 必需的步骤2:如果上面没有成功
  // 我们尝试用默认的ClassLoader装入它
  if (clasz == null)
  clasz = findSystemClass( name );
  // 必需的步骤3:如有必要,则装入相关的类
  if (resolve && clasz != null)
  resolveClass( clasz );
  // 把类返回给调用者
  return clasz;
  } catch( IOException ie ) {
  throw new ClassNotFoundException( ie.toString()
  );
  } catch( GeneralSecurityException gse ) {
  throw new ClassNotFoundException( gse.toString()
  );
  }
  }
  }


对于未经加密的应用,正常执行方式如下: % java App arg0 arg1 arg2
  对于经过加密的应用,则相应的运行方式为: % java DecryptStart key.data App arg0 arg1 arg2
  DecryptStart有两个目的。一个DecryptStart的实例就是一个实施即时解密操作的定制ClassLoader;同 时,DecryptStart还包含一个main过程,它创建解密器实例并用它装入和运行应用。示例应用App的代码包含在App.java、 Foo.java和Bar.java内。Util.java是一个文件I/O工具,本文示例多处用到了它。完整的代码请从本文最后下载。
  五、注意事项
  我们看到,要在不修改源代码的情况下加密一个Java应用是很容易的。不过,世上没有完全安全的系统。本文的加密方式提供了一定程度的源代码保护,但对某些攻击来说它是脆弱的。
  虽然应用本身经过了加密,但启动程序DecryptStart没有加密。攻击者可以反编译启动程序并修改它,把解密后的类文件保存到磁盘。降低 这种风险的办法之一是对启动程序进行高质量的模糊处理。或者,启动程序也可以采用直接编译成机器语言的代码,使得启动程序具有传统执行文件格式的安全性。
  另外还要记住的是,大多数JVM本身并不安全。狡猾的黑客可能会修改JVM,从ClassLoader之外获取解密后的代码并保存到磁盘,从而绕过本文的加密技术。Java没有为此提供真正有效的补救措施。
  不过应该指出的是,所有这些可能的攻击都有一个前提,这就是攻击者可以得到密匙。如果没有密匙,应用的安全性就完全取决于加密算法的安全性。虽然这种保护代码的方法称不上十全十美,但它仍不失为一种保护知识产权和敏感用户数据的有效方案。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2024-5-2 01:43 , Processed in 0.408643 second(s), 48 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表