黑马程序员技术交流社区

标题: 令人痛苦的自定义类加载器加密与解密问题! [打印本页]

作者: 思维    时间: 2014-8-11 21:37
标题: 令人痛苦的自定义类加载器加密与解密问题!
本帖最后由 思维 于 2014-8-12 23:02 编辑

这两天学了下类加载器,使用EditPlus写了自定义类加载器进行加密与解密的代码,出现了各种问题,郁闷的不行,谁来解决下啊?问题一:运行MyClassLoader类后将加密的ClassLoaderAttachment覆盖原来的.class文件,解密时产生ClassFormortError   (注意:所有的类均在D:\JavaDemo\下)
  1. import java.io.*;
  2. import java.util.*;
  3. class MyClassLoader extends ClassLoader{
  4.         //编译:java MyClassLoader D:\JavaDemo\ClassLoaderAttachment.class D:\
  5.         public static void main(String[] args)throws Exception{
  6.                 //参数中传入加密前的目标文件和路径
  7.                 String srcPath = args[0];
  8.                 //参数中传入完成后的加密文件的路径
  9.                 String destDir = args[1];
  10.                 //创建目标文件的文件输入流对象
  11.                 FileInputStream fis = new FileInputStream(srcPath);
  12.                 //获取目标文件的文件名
  13.                 String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
  14.                 //完成后返回加密文件和路径
  15.                 String destPath = destDir+"\\"+destFileName;
  16.                 //创建加密文件的文件输出流对象
  17.                 FileOutputStream fos = new FileOutputStream(destPath);
  18.                 //对数据进行加密
  19.                 cypher(fis,fos);
  20.                 fis.close();
  21.                 fos.close();
  22.         }
  23.         //创建对数据流进行加密的方法
  24.         private static void cypher(InputStream ips,OutputStream ops)throws Exception{
  25.                 int b = -1;
  26.                 while((b = ips.read())!=-1){
  27.                         ops.write(b^0xff);
  28.                 }
  29.         }
  30.         //自定义类加载器
  31.         @Override
  32.         protected Class<?> findClass(String name)throws ClassNotFoundException{
  33.                 //获得加密文件和路径
  34.                 String classFileName = name.substring(name.lastIndexOf('.')+1)+".class";
  35.                 try{
  36.                         //创建加密文件的文件输入流对象
  37.                         FileInputStream fis = new FileInputStream(classFileName);
  38.                         //创建解密文件的字节数组输出流对象
  39.                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  40.                         //对加密数据进行解密
  41.                         cypher(fis,bos);
  42.                         fis.close();
  43.                         byte[] bytes = bos.toByteArray();
  44.                         return defineClass(null,bytes,0,bytes.length);
  45.                 }catch(Exception e){
  46.                         e.printStackTrace();
  47.                 }
  48.                 return null;
  49.         }
  50. }
  51. //创建一个需要被加密的类
  52. class ClassLoaderAttachment extends Date{
  53.         public String toString(){
  54.                 return "你好,黑马训练营!";
  55.         }
  56. }
复制代码
测试代码:
  1. import java.util.*;
  2. //对类的加密结果进行测试
  3. public class ClassLoaderTest{
  4.         public static void main(String[] args)throws Exception{
  5.                 //System.out.println(new ClassLoaderAttachment().toString());
  6.                 Class clazz =
  7.                                 new MyClassLoader().loadClass("ClassLoaderAttachment");
  8.                 Date cla1 = (Date)clazz.newInstance();
  9.                 System.out.println(cla1);
  10.                 //ClassLoaderAttachment cla1 = clazz.newInstance();
  11.                 //ClassLoaderAttchment已经被加密,无法被编译器识别,因此需要继承Date类
  12.         }
  13. }
复制代码
问题二:运行MyClassLoader类后将加密的ClassLoaderAttachment存入My目录下,同时删除D:\JavaDemo下的ClassLoaderAttachment,解密时产生IllegalAccessException
  1. import java.io.*;
  2. import java.util.*;
  3. class MyClassLoader extends ClassLoader{
  4.         //编译:java MyClassLoader D:\JavaDemo\ClassLoaderAttachment.class D:\
  5.         public static void main(String[] args)throws Exception{
  6.                 //参数中传入加密前的目标文件和路径
  7.                 String srcPath = args[0];
  8.                 //参数中传入完成后的加密文件的路径
  9.                 String destDir = args[1];
  10.                 //创建目标文件的文件输入流对象
  11.                 FileInputStream fis = new FileInputStream(srcPath);
  12.                 //获取目标文件的文件名
  13.                 String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
  14.                 //完成后返回加密文件和路径
  15.                 String destPath = destDir+"\\"+destFileName;
  16.                 //创建加密文件的文件输出流对象
  17.                 FileOutputStream fos = new FileOutputStream(destPath);
  18.                 //对数据进行加密
  19.                 cypher(fis,fos);
  20.                 fis.close();
  21.                 fos.close();
  22.         }
  23.         //创建对数据流进行加密的方法
  24.         private static void cypher(InputStream ips,OutputStream ops)throws Exception{
  25.                 int b = -1;
  26.                 while((b = ips.read())!=-1){
  27.                         ops.write(b^0xff);
  28.                 }
  29.         }
  30.         private String classDir;
  31.         public MyClassLoader(){
  32.                
  33.         }        
  34.         public MyClassLoader(String classDir){
  35.                 this.classDir = classDir;
  36.         }        
  37.         //自定义类加载器
  38.         @Override
  39.         protected Class<?> findClass(String name)throws ClassNotFoundException{
  40.                 //获得加密文件和路径
  41.                 String classFileName =
  42.                         classDir + "\\"  + name.substring(name.lastIndexOf('.')+1) + ".class";
  43.                 try{
  44.                         //创建加密文件的文件输入流对象
  45.                         FileInputStream fis = new FileInputStream(classFileName);
  46.                         //创建解密文件的字节数组输出流对象
  47.                         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  48.                         //对加密数据进行解密
  49.                         cypher(fis,bos);
  50.                         fis.close();
  51.                         byte[] bytes = bos.toByteArray();
  52.                         return defineClass(null,bytes,0,bytes.length);
  53.                 }catch(Exception e){
  54.                         e.printStackTrace();
  55.                 }
  56.                 return null;
  57.         }
  58. }
  59. //创建一个需要被加密的类
  60. class ClassLoaderAttachment extends Date{
  61.         public String toString(){
  62.                 return "你好,黑马训练营!";
  63.         }
  64. }
复制代码
测试代码
import java.util.*;
//对类的加密结果进行测试
public class ClassLoaderTest{
        public static void main(String[] args)throws Exception{
                //System.out.println(new ClassLoaderAttachment().toString());
                Class clazz =
                                new MyClassLoader("D:\\JavaDemo\\My").loadClass("ClassLoaderAttachment");
                Date cla1 = (Date)clazz.newInstance();
                System.out.println(cla1);
                //ClassLoaderAttachment cla1 = clazz.newInstance();
                //ClassLoaderAttchment已经被加密,无法被编译器识别,因此需要继承Date类
        }
}





捕获.JPG (179.99 KB, 下载次数: 19)

捕获.JPG

捕获1.JPG (49.35 KB, 下载次数: 19)

捕获1.JPG

作者: @for    时间: 2014-8-11 21:43
楼主高大上,领教了
作者: chensuyu    时间: 2014-8-11 21:45
.................................
作者: Bule丶    时间: 2014-8-11 21:45
楼主加油
作者: 晓风    时间: 2014-8-11 21:47
楼主很给力啊!虽然看过视频,但还是不是很清楚。
作者: 小呀嘛小二郎    时间: 2014-8-11 21:47
赞一个~~
作者: 思维    时间: 2014-8-11 21:49
求高手帮忙解决啊!:'(
作者: More    时间: 2014-8-11 21:49
我还没看   不过你可以根据异常去进行调试   一个是非法访问异常还有一个是类格式错误  你可以先排查排查
作者: 思维    时间: 2014-8-11 21:51
More 发表于 2014-8-11 21:49
我还没看   不过你可以根据异常去进行调试   一个是非法访问异常还有一个是类格式错误  你可以先排查排查 ...

类格式错误,说明解密失败了!非法访问异常,目测是路径上出问题了!就是不知道怎么解决啊?:'(
作者: More    时间: 2014-8-11 23:13
思维 发表于 2014-8-11 21:51
类格式错误,说明解密失败了!非法访问异常,目测是路径上出问题了!就是不知道怎么解决啊? ...

是高新技术上讲的吗  等我看过视频一起探讨探讨
作者: 乐此不疲    时间: 2014-8-12 00:20
试试   args[1] 输入改成  D:\JavaDemo  
作者: 我行我SHOW‰    时间: 2014-8-12 00:40
过来学习一下,对类加载不是很熟~~~
作者: a6511631    时间: 2014-8-12 10:17
本帖最后由 a6511631 于 2014-8-12 10:21 编辑

首先classPath下不要放ClassLoaderAttachment.class,不然类加载器会先去加载它,而不会去自定义加载,
你如果放了的话就会报你说的那个ClassFormatError。
我估计你后来没有放了,接下来就报了IllegalAccessException是不是?
解决方法:给ClassLoaderAttachment类加上修饰符public。这个异常代表非法访问,就是因为权限不够。一个类文件不能有多个public修饰的类,你把它另外做一个.java类文件吧。
建议:
你仔细看MyClassLoader的构造方法,这里loadClass()需要用到MyClassLoader其中的findClass()
而findClass()方法中需要一个参数classDir,这个参数哪里定义的?就是在构造时定义,你这里没有给它传参数,最好加上路径。
顺便一提的是,loadClass()方法的参数,这个类名ClassLoaderAttachment应该要加上包名,但是你写这个程序的时候没有建包,就不用写了。建议以后写上报名
PS:我才不会告诉你我又去复习类加载器捣鼓了半个小时。

作者: 怀念黑海岸    时间: 2014-8-12 10:22
我表示这部分还没看到。。。
作者: 思维    时间: 2014-8-12 10:35
本帖最后由 思维 于 2014-8-12 10:45 编辑
a6511631 发表于 2014-8-12 10:17
首先classPath下不要放ClassLoaderAttachment.class,不然类加载器会先去加载它,而不会去自定义加载,
你 ...

还有一点问题就是:自定义类加载器加载的类必须是public的,缺省的都不行?
作者: a6511631    时间: 2014-8-12 10:43
思维 发表于 2014-8-12 10:35
还有一点问题就是:自定义类加载器加载的类必须是public的吗?

你去测试一下吧,我说了你也记不住
作者: 思维    时间: 2014-8-12 10:44
a6511631 发表于 2014-8-12 10:17
首先classPath下不要放ClassLoaderAttachment.class,不然类加载器会先去加载它,而不会去自定义加载,
你 ...

classPath下存放ClassLoaderAttachment,AppClassLoader作为发起者,委托给父类加载器进行加载,当加载到AppClassLoader时均无法加载ClassLoaderAttachment,不会再向下由自定义加载器去加载,目测这是张孝祥老师关于MySrvlet的那个知识点啊!:D
作者: 思维    时间: 2014-8-12 10:46
a6511631 发表于 2014-8-12 10:43
你去测试一下吧,我说了你也记不住

说说呗!看看我哪些东西还没学到!:D
作者: alee    时间: 2014-8-12 10:58
这部分内容却是有点恶心,楼主多看看吧
作者: a6511631    时间: 2014-8-12 11:07
思维 发表于 2014-8-12 10:46
说说呗!看看我哪些东西还没学到!

外部类的访问修饰符只有public、default(不写即默认为default)。自定义的类加载器在加载类字节码的时候,它们在同一个包中吗?众所周知,不在同一个包就只能访问public修饰的类。通常情况下,不在。因为自定义加载时这个包下的classPath中不会放那个类字节码文件。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2