黑马程序员技术交流社区
标题:
用类加载器将代码加密的3个步骤
[打印本页]
作者:
浅木头
时间:
2015-1-26 19:54
标题:
用类加载器将代码加密的3个步骤
代码1
package day02;
import java.util.Date;
public class ClassLoaderTest {
/**
* @param args
* 如何对类加载器加密?
* 1,三个类,一个类加载器的类,一个运行类,一个附件类(输出语句的)
* 2,在工程下新建一个目录,准备放新的附件类
* 3,将附件类放入这个目录——在MyClassLoader中右键Run As,选择Other...
* 先选择主要运行类为MyClassLoader,然后输入两个传入的参数
* 第一个参数是附件类的class文件所在路径,在bin文件夹里,获取其绝对路径
* 这里有个技巧,就是将MyClassLoader.class拖到运行对话框,就可得到。
* 第二个参数是刚才在工程下新建的目录名字,如lib。
* 点击Apply和确定
* 4,左键选中lib,按下F5刷新,应该会出来这个新的附件class文件,这个类就是已经加密的类
* 5,正常的效果是在运行类中运行附件类,应该能输出语句,但要让它不能,操作如下:
* a,找出旧的没加密的附件类class文件完整路径,复制
* b,在MyClassLoader下Run As:
* 先选择主要的类为MyClassLoader
* 再设置参数,第一个是刚才复制的旧的文件路径,第二个是lib
* 这样就表示,如果运行,是可以正常的,因为附件类class文件是没加密的
* 6,如果想看到异常现象,就将已加密的class文件覆盖掉bin目录下的class文件,再运行就报错:
* Exception in thread "main" java.lang.ClassFormatError: Truncated class file
* 7,如果要功能完善,步骤如下:
* MyClassLoader类继承ClassLoader,覆盖findClass方法(protected),其中包含解密算法
在运行类中加载原来存放已加密的附件类的目录下的附件类,这样就等于解密了
再创建新附件类的实例,运行即可
*
*
*
*如果把附件类删除,则可能需要重启MyEclipse,重新导入父类类加载器
*父类类加载器只能加载带包名的类
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//System.out.println(new ClassLoaderAttachment().toString());
//用自定义的类加载器加载放于mylib01目录下的ClassLoaderAttachment类,生成后已经解密,因为再次运行了一次加密算法
//如果loadClass的目录写成day02.ClassLoaderAttachment则无法读取
//只有写成ClassLoaderAttachment才可以读取
//因为父类只能读取day02目录下的附件类,我们的目的就是不让父类读到,
//从而可以用自己自定义的类加载器。所以,如果传入父类的目录,就无法使用自定义的类加载器了。
/**
* 知识点:对于这个例子来说,父类会查找/practice.javaEnhance/src/day02
* 目录下的所有jar包和目录,也就是classPath,一般的类,父类也就是AppClassLoader。
* 所以会查找这个。而我们只要保证这个classPath下没有,就可以用自定义
* 的类加载器了。自定义的类加载器可以加载指定目录。指定的目录就是
* new MyClassLoader("mylib01")里的mylib01。里面只有一个文件。
*
*/
Class clazz = new MyClassLoader("mylib01").loadClass("ClassLoaderAttachment");
//创建一个新附件类的实例
Date d1 = (Date)clazz.newInstance();
//打印信息
System.out.println(d1);
}
}
代码2
package day02;
import java.util.Date;
public class ClassLoaderAttachment extends Date {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public String toString(){
return "Welcome,my friend!";
}
}
代码3
package day02;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//继承类加载器
public class MyClassLoader extends ClassLoader{
/**
* 自定义一个加载器,带有加密功能
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*// TODO Auto-generated method stub
//获取ClassLoaderTest01类的对应的类加载器的名字
System.out.println(MyClassLoader.class.getClassLoader().getClass()
.getName());
//获取System类的对应的类加载器,因为特殊,所以不能获取名字
System.out.println(System.class.getClassLoader());
//将ClassLoaderTest01对应的类加载器记录下来
ClassLoader classLoader = MyClassLoader.class.getClassLoader();
//倒序打印类加载器的层次(对于classLoader来说)
while(classLoader!=null){
System.out.println(classLoader.getClass().getName());
classLoader = classLoader.getParent();
}
System.out.println(classLoader);*/
/**
* *——————————————————————————————————
* * ——————————————————————————————————
* * ——————————————————————————————————
* * ——————————————————————————————————
*/
//正常情况下,可以打印出来ClassLoaderAttachment的覆盖的toString方法
//但需要让ClassLoaderAttachment的方法打印不出来,则需要继续操作
//定义源路径(包括文件名)
String srcPath = args[0];
//定义目标目录(不包括文件名)
String destDir = args[1];
//将源文件的完整名称传入输入流
FileInputStream fis = new FileInputStream(srcPath);
//获取目标文件的文件名:用源文件路径的最后一个下划线往后切出来子串
String destFileName = srcPath.substring(srcPath.lastIndexOf("\\")+1);
//获取目标文件的路径:用目录和下划线加上获取的文件名
String destPath = destDir+"\\"+destFileName;
//用输出流输出
FileOutputStream fos = new FileOutputStream(destPath);
fis.close();
fos.close();
}
//定义加密方法,异或
private static void cypher(InputStream ips,OutputStream ops) throws Exception{
int b = -1;
while((b = ips.read())!=-1){
ops.write(b ^ 0xff);//异或一下,解密也是这个密钥
}
}
@Override
//重写findClass方法,如果继承类加载器则必须重写
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
//获取class文件的完整文件路径
String classFileName = classDir+"\\"+".class";
try {
//输入流
FileInputStream fis = new FileInputStream(classFileName);
//输出流用字节数组输出
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//再用一次加密算法,相当于解密
cypher(fis,bos);
//关闭输入流
fis.close();
//新建缓冲区
byte[] bytes = bos.toByteArray();
//将字节数组组合成一个class文件返回,用defineClass方法
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.findClass(name);
}
private String classDir;
public MyClassLoader(){
}
public MyClassLoader(String classDir) {
super();
this.classDir = classDir;
}
}
作者:
温晓慧
时间:
2015-1-26 21:18
这个好,这一部分听得真的是很难理解,谢谢分享
作者:
浅木头
时间:
2015-1-27 13:20
温晓慧 发表于 2015-1-26 21:18
这个好,这一部分听得真的是很难理解,谢谢分享
谢谢支持,我也是刚学完没多长时间,如果有什么错误还望指教~
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2