自定义类加载器+加密+解密 实验

自定义类加载器+加密+解密  的这个程序需要的实验步骤如下,所用的类如下:

ClassLoaderTest  类:用来做“解密实验”的类,将Test类的加密后的.class文件加载内存,并解密后,用ClassLoader.defineClass()得到Class对象,利用反射使用Test类

MyClassLoader  类:定义自己的类加载器,重写其中的findClass方法,在该方法中定义查找.class文件的默认目录,并调用EncodeDecodeClass类的解密方法,解密Test.class,然后调用父类的defineClass方法,得到Class对象。

EncodeDecodeClass   类:定义了加密和解密方法

Test  类:定义了一个普通类,这个类的正确的.class会被加密和解密

UseTest 类:用来做“加密实验”测试的类,里面使用了加密后的Test.class

1、“加密实验”

    1.0  设置好classpath的值

    1.1  先用javac正常编译Test.java(用带存储路径的方式编译带包名的类,以用来正确的到包的文件夹形式,并将类存放到正确位置),得到正确的.class文件

    1.2  先调用EncodeDecodeClass.encode()方法,对已经存在的正确的Test.class文件加密,得到Test_1.class

    1.3  用javac 正常编译UseTest.java,得到编译后的UseTest.class (这里也可以看到这个UsetTest.class文件中只包含了UseTest类的信息,并不包含它所用到的

      类Test.class的信息,即一个.class中只包含其对应的类的本类信息,不包含这个类的定义中用到的其他类的定义信息,编译器只是在编译出本类的.class文件的时候

      通过用反射加载类进内存,检查被使用类身上是否有某个方法的这个方式来检查本类的源程序.java,是否是正确的,即本类是否被正确定义了,只是检查,为的是

      保证运行的时候,可以正确的运行,运行的时候JVM会利用类加载器来动态加载类中使用的其他类的.class文件信息,来完成程序的运行)

    1.4  将Test_1.class 改名为Test.class,将原来的那个正确的Test.class删除掉

    1.5  用 java 运行UsetTest.class类,报告出异常

    实验完毕,报告出异常说明了加密实验成功!!

2、“解密实验”

   1.0   设置好classpath的值

   1.1   先用javac编译ClassLoaderTest.java,得到ClassLoaderTest.class

   1.2   再用java 运行ClassLoaderTest.class

   1.3   成功调用,打印出结果:

          

   实验完毕,打印以上信息,说明解密实验成功!!

【实际项目中,将开发好的框架(或者类)的.class文件统一进行加密,然后交给客户使用,客户如果直接拿来使用,则会出错,.class里面的数据是错误的数据,无法解析。

如果客户付费后,则可以用一个验证码的方式激活自定义的类加载器中的解密方法(if 语句判断一下用户是否获得了验证码,没有则不调用解密方法),正确加载框架中的类

,并解析他们,完成正确的使用。】

ClassLoaderTest.java

package com.heima;

import java.io.File;
import java.lang.reflect.Method;
/*自定义类加载器,对.class文件进行加载,同时编写对.class文件进行加密和解密的程序*/
/*
 *
 * 

        "Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value
        889275713 in class file com/heima/Test" ---->这个异常指的是程序中使用的已经存在的类文件(即.class文件)是有问题的。
        比如,将.class文件加密后,再在主类.class中使用这个.class文件,在类加载器ClassLoader将类从.class文件中加载到内存的对类的处理过程中,
        就会抛出这个异常。
        incompatible :不兼容的 ,矛盾的
        magic :不可思议的 ,有魔力的
 *
 */

public class ClassLoaderTest {

    public static void main(String[] args) {

        System.out.println("ok");
        try {
            Class clazz = new MyClassLoader().loadClass("com.heima.Test");
            Method method = clazz.getMethod("print");
            method.invoke(clazz.newInstance());
            System.out.println("解密调用成功!");
        } catch (Exception e) {

            e.printStackTrace();
        }

    }

}

MyClassLoader 

package com.heima;

import java.io.File;

public class MyClassLoader extends ClassLoader {

    private String path ="F:\\myclass\\";
    @Override
    protected Class findClass(String name) throws ClassNotFoundException {

        String tempName = name.replaceAll("\\.","\\\\"); //将类的完全限定名称中的包名之间的.转换为
        File file = new File(path,tempName+".class"); //拼接出正确的类名,得到正确的抽象路径名

        byte[] buf = null;
        System.out.println("***************** "+name+"  "+file.exists()); //测试信息
        System.out.println(file.toString());
        if(file.exists())
        {
            try {
                buf = EncodeDecodeClass.decode(file); //解密指定的文件,得到字节码数组
            } catch (Exception e) {
                System.out.println("类文件解密出错!");
            }
        }
        Class retVal = defineClass(name, buf, 0, buf.length); //得到Class对象

        return retVal; //返回Class类对象
    }
}

EncodeDecodeClass   

package com.heima;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class EncodeDecodeClass {

    public static void encode(File file)throws Exception
    {
        FileInputStream fis = new FileInputStream(file);

        String name = file.getName();
        file.getPath();
        String[] strs = name.split("\\.");

        System.out.println(file.toString()+" :: "+name+" :: "+strs.length);
        name = strs[0]+"_1."+strs[1];
        file.renameTo(new File(file.getParent(),file.getName()+"_1"));

        File desFile = new File(file.getParent(),name);

        FileOutputStream fos = new FileOutputStream(desFile);
        byte[] buf = new byte[1024];
        int len = 0;
        while( (len = fis.read(buf))!=-1)
        {
            for(int i=0; i<len ;i++)
            {
                buf[i] = (byte)(buf[i]^0xff);//取反加密
            }
            fos.write(buf,0,len);
        }

        fis.close();
        fos.close();

    }
    public static byte[] decode(File file) throws Exception
    {
        FileInputStream fis = new FileInputStream(file);
        ByteArrayOutputStream dest = new ByteArrayOutputStream();

        byte[] buf = new byte[1024];
        int len = 0;
        while((len = fis.read(buf))!=-1)
        {
            for(int i=0; i<len ;i++)
            {
                buf[i] = (byte)(buf[i]^0xff); //取反解密
            }
            dest.write(buf, 0, len);
        }
        fis.close();
        System.out.println("ok");
        return dest.toByteArray();
    }
    public static void main(String[] args)
    {
        File file = new File("f:\\myclass\\com\\heima\\Test.class");
        if(file.exists())
        {
            try {
                EncodeDecodeClass.encode(file);
                System.out.println("加密成功!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Test.java

package com.heima;

public class Test {

    public void print()
    {
        System.out.println("自定义类加载器要加载类的代码,我在被要先被加密,刚刚才解密");
    }

    public static void main(String[] args) {

        System.out.println(0xff);

    }

}

UseTest.java

package com.heima;

public class UseTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Test t = new Test();
        t.print();
    }

}
时间: 2024-10-10 13:36:05

自定义类加载器+加密+解密 实验的相关文章

Android进阶:十三、自定义类加载器加载加密类文件

之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点.而且对于高级Android研发来讲,懂得更多类加载相关的东西,对开发也会有很多的帮助,比如热更新,类加密等.其实笔者对类加密比较感兴趣,就稍稍调研了一下.类加密的其实是为了防止APP被反编译,防止反编译的方法有很多种,比如混淆,加固等.自己对类文件进行加密,并自定义类加载器也是一种办法: 首先我们的代码打包编译之后会变成难以读懂的二进制字节码,并且变成.class文件.但是简单的APP编译出来之后可以被反编译,甚至你写的

Android进阶:自定义类加载器加载加密类文件

之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点.而且对于高级Android研发来讲,懂得更多类加载相关的东西,对开发也会有很多的帮助,比如热更新,类加密等.其实笔者对类加密比较感兴趣,就稍稍调研了一下.类加密的其实是为了防止APP被反编译,防止反编译的方法有很多种,比如混淆,加固等.自己对类文件进行加密,并自定义类加载器也是一种办法: 首先我们的代码打包编译之后会变成难以读懂的二进制字节码,并且变成.class文件.但是简单的APP编译出来之后可以被反编译,甚至你写的

java类加载器学习2——自定义类加载器和父类委托机制带来的问题

一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载器.如果父类加载器加载不了,依次再使用其子类进行加载.当然这类所说的父类加载器,不一定他们之间是继承的关系,有可能仅仅是包装的关系. Java之所以出现这条机制,因为是处于安全性考虑.害怕用户自己定义class文件然后自己写一个类加载器来加载原本应该是JVM自己加载的类.这样会是JVM虚拟机混乱或者

JVM类加载器原理与自定义类加载器

类加载器原理 JVM将class文件字节码文件加载到内存中, 并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class 对象,作为方法区类数据的访问入口. 类缓存 标准的Java SE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间.不过,JVM垃圾收集器可以回收这些Class过象. 类加载器数状结构 引导类加载器(bootstrap class loader) 它用来加载Java的核心库(JAVA_HOME/

Java自定义类加载器与双亲委派模型

其实,双亲委派模型并不复杂.自定义类加载器也不难!随便从网上搜一下就能搜出一大把结果,然后copy一下就能用.但是,如果每次想自定义类加载器就必须搜一遍别人的文章,然后复制,这样显然不行.可是自定义类加载器又不经常用,时间久了容易忘记.相信你经常会记不太清loadClass.findClass.defineClass这些函数我到底应该重写哪一个?它们主要是做什么的?本文大致分析了各个函数的流程,目的就是让你看完之后,难以忘记!或者说,延长你对自定义类加载器的记忆时间!随时随地想自定义就自定义!

黑马程序员——自定义类加载器

自定义类加载器是在是血的不怎明白 这里只学会了一个简单的加密解密方法 //定义一个加密方法 public static void md(InputStream inputStream,OutputStream outputStream) throws Exception{  int b = 0;  while((b = inputStream.read())!=-1){   //使用^异或,相同的为0,不同的为1,由于0xff是255,后八位都是1,   //这样就将原来的1变成了0,0变成了1

(转)JVM——自定义类加载器

背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上的大部分自定义类加载器文章,几乎都是贴一段实现代码,然后分析一两句自定义ClassLoader的原理.但是我觉得首先得把为什么需要自定义加载器这个问题搞清楚,因为如果不明白它的作用的情况下,还要去学习它显然是很让人困惑的. 首先介绍自定义类的应用场景: (1)加密:Java代码可以轻易的被反编译,如

自定义类加载器——加载任意指定目录的class文件

public class MyClassLoader extends ClassLoader{ String path;//自定义类加载器所负责的文件夹 public MyClassLoader(String path) { super(); this.path = path; } @SuppressWarnings("deprecation") @Override protected Class<?> findClass(String name) throws Class

jvm自定义类加载器

除了自定义的类加载之外,jvm存在三种类加载器,并以一种父委托的加载机制进行加载. --启动类加载器,又称根加载器,是一个native的方法,使用c++实现.在java中我们用null标识,用于加载jdk自带的类. --扩展类加载器,用于加载jdk扩展类 --系统类加载器,用于加载classpath目录下的类 上面提到的三种类加载器,是存在父子关系,即系统类加载器会委托extension加载器,如果extension加载器不能加载该类的话,再由系统类加载器进行加载.注意这里所说的父子关系不是指继