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

之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点。而且对于高级Android研发来讲,懂得更多类加载相关的东西,对开发也会有很多的帮助,比如热更新,类加密等。
其实笔者对类加密比较感兴趣,就稍稍调研了一下。类加密的其实是为了防止APP被反编译,防止反编译的方法有很多种,比如混淆,加固等。自己对类文件进行加密,并自定义类加载器也是一种办法:

首先我们的代码打包编译之后会变成难以读懂的二进制字节码,并且变成.class文件。但是简单的APP编译出来之后可以被反编译,甚至你写的代码完完全全被暴露。你的代码被抄袭,被复制都是小事,重要的其实是你们APP的商业信息有可能被泄露!
下面是一个简单的例子被反编译的场景:

所以为了不让用户轻易的反编译出源代码文件,就要对.class文件进行加密,再通过特殊的加载类的方式解密,并将这个类加载到内存中。

首先说加密,加密无非就是把.class字节码文件进行一些变换,这里面就涉及密码学的知识了!加密的方式有很多种,要想提高保密性,可以考虑DES,AES,RSA。一旦加密算法的源码被公开,其实破解也就是很简单的事情了,所以建议大家还是用高安全性的密码系统,到时候及时的更换密钥。就能一定程度上增加破解难度。

有了加密算法,接下来就是加密一个字节码文件了:

        private static File file = null;
    private static String path = null;
    // 读取已经编译好的正常的class字节码文件
    public static void readClass(String filePath) throws Exception {
        file = new File(filePath);
        path = filePath;
    }

    // 加密生成已加密的class字节码文件
    public static void encrypt() throws Exception {
        FileInputStream fis = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(path.substring(0,
                path.lastIndexOf(".class"))
                + "附件.class");
        byte[] b = new byte[1024];
        int ch = 0;
        while ((ch = fis.read(b)) != -1) {
            // 变换b
            b=crypt(b, "encrypt");
            fos.write(b, 0, ch);
        }
    }

这时候,调用readClass方法和encrypt方法,就能在原本XX.class文件的目录下生成XX附件.class。这时候,我们就使用这个副本的字节码文件,删除原来的,下次运行的时候再解密,这样就行了。

对类加密之后,需要用自己的方式把类再加载出来。正常的时候咱们写的类也需要被类加载器加载到内存中。所以,就涉及到类加载器的知识了:
系统默认三个类加载器,分别是:BootStrap,ExtClassLoader,AppClassLoader。那么这几个类加载器有什么区别呢?
首先类加载器有父子关系。BootStrap是爷爷(用C++编写,主要负责加载jre/lib/rt.jar),ExtClassLoader是爸爸(主要用于加载JRE/lib/ext/*.jar),AppClassLoader是儿子(用于负责加载ClassPath指定目录下的所有jar)。

所以我们一般写的class文件都是AppClassLoader加载的。那假如我们写了一个类,我们把这个类复制一份,放到ExtClassLoader目录下,那么类加载器会怎么加载呢?这就要提到类加载器的委托机制了。

类加载器的委托机制:当一个线程调用一个类的时候,首先用当前线程的类加载器去加载这个类,这个类加载器一开始不加载,会通知他的上一级类加载器去加载,等到了BootStrap加载器的时候,如果没有就再让调用的下级加载器去加载。如果都没有就报ClassNotFoundException异常。也可以直接指定类加载器去加载。

所以我们可以自己定义一个类加载器,让这个让这个类加载器去加载我们加密过的类。自定义类加载器需要继承ClassLoader类,并且重写findClass方法。

class MyClassLoader extends ClassLoader {
    private String path = null;

    // 设置自定义类加载器的目录
    public MyClassLoader(String path) {
        this.path = path;
    }

    /*
     * findClass和loadClass的区别?
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            File f = new File(path, name.substring(name.lastIndexOf(‘.‘) + 1)
                    + ".class");
            FileInputStream fis = new FileInputStream(f);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int ch = 0;
            while ((ch = fis.read()) != -1) {
                bos.write(ch);
            }
            byte[] buf = bos.toByteArray();
            //解密.class
            buf = Z1Encrypt.crypt(buf, "decrypt");
            fis.close();
            bos.close();
            //根据字节码返回这个类
            return defineClass(name, buf, 0, buf.length);
        } catch (Exception e) {
            throw new ClassNotFoundException(name + " is not found!");
        }
    }
}

接着我们用我们的自定义类加载器去解密加载我们加密好的字节码文件

public static void main(String[] args) throws Exception {
        /*Z1Encrypt.readClass("F:\\WorkSpace\\classLoader\\DemoTemp.class");
        Z1Encrypt.encrypt();
        */
        MyClassLoader mcl = new MyClassLoader("F:\\WorkSpace\\classLoader\\");
        Class clazz  = mcl.findClass("DemoTemp");
        Method me = clazz.getMethod("say",null);
        Object obj = clazz.newInstance();
        me.invoke(obj, null);
    }

后来成功的解密了字节码文件,并将其加载到内存中,并成功调用了相关的方法了。

以上是一个非常简单的代码加密,并自定义类加载器的方法,仅供学习其中思路和知识。

原文地址:https://blog.51cto.com/14295695/2392556

时间: 2024-10-23 22:30:04

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

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

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

自定义类加载器——加载任意指定目录的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自定义类加载器加载指定classPath下的所有class及jar

一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责JAVA_HOME/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作. 2.其他类加载器:由java实现,可以在方法区找到其Class对象.这里又细分为几个加载器 a).扩展类加载器(Extension ClassLoader):负责用于加载JAVA_HOM

通过类加载器加载资源文件

/*******************************************第一种方法***************************************************************/ public class Demo {    //资源文件可以通过类加载器的方式加载到内存中,这种方式的好处是程序不用明确制定配置文件的具体所在目录.程序可以自动的在    //src目录下搜索该文件,并加载    //采用下面这种方法还有一种弊端,就是,通过类加载器加载

Android进阶:自定义视频播放器开发(下)

上一篇文章我们主要讲了视频播放器开发之前需要准备的一个知识,TextureView,用于对图像流的处理.这篇文章开始构建一个基础的视频播放器. 一.准备工作 在之前的文章已经说过了,播放器也是一个view,我们要在这个view上播放视频流.所以我们要自定义一个简单的viewgroup,比如继承FrameLayout.还出就是布局简单,其他控件可以往上面添加.大家见过的视频播放器的控制器都是放在视频的上方的.这样就是用FrameLayout布局是最好的. class SmallVideoPlaye

spring不断重新加载所有类文件

第一次写博文,可能有点兴奋和啰嗦,先说说使用的环境:resin+spring+struts,服务器是测试用的,由运维同事维护,里面有几个项目,仅供开发的同事修改. 事情从昨天下午开始, 查看测试服务器log时,发现spring不断的加载类文件,但却没有任何错误信息提示,初步判断应该是某开发的同事修改了配置文件导致的问题,但看了一遍没发现什么问题,难道服务器作了什么动作?于是问了一名运维同事,说没作什么修改,一听心血来潮,因为这个问题可以加入我的问题库里面. 因为配置正常,怀疑是某些类加载不正常导

类加载器加载配置文件

//在resource文件夹下创建一个db.properties文件 里面存2个值: //加载该文件内容: @RunWith(SpringRunner.class) @SpringBootTest public class JestTest { @Test public void getProperties() throws IOException { //通过2种方式获取类加载器,然后可以将配置文件加载进行进来,一个是Thread类获取,另一个是字节码对象获取 ClassLoader load

Android进阶:自定义视频播放器开发(上)

随着快手,抖音,西瓜视频等视频APP的崛起,视频播放已经成为主流,此时作为Android研发的你,想要提高自己的能力还不知道怎么开发视频播放器怎么行?所以今天就带着大家一起开发一个简易播放器:SmallVideoPlayer 需求分析 我们观察一个视频播放器,可以看到视频播放器除了正在播放的视频还有很多控件,比如播放按钮,暂停按钮,播放进度条,播放计时器等.这么多控件显然无法播放视频,但是他们都在控制视频的播放.由此可见视频播放器可以分为两层,一层为视频播放器控制层,一层为真正的视频播放层. 所

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

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