内容简介:之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点。而且对于高级Android研发来讲,懂得更多类加载相关的东西,对开发也会有很多的帮助,比如热更新,类加密等。其实笔者对类加密比较感兴趣,就稍稍调研了一下。类加密的其实是为了防止APP被反编译,防止反编译的方法有很多种,比如混淆,加固等。自己对类文件进行加密,并自定义类加载器也是一种办法:首先我们的代码打包编译之后会变成难以读懂的二进制字节码,并且变成.class文件。但是简单的APP编译出来之后可以被反编译,甚至你写的代码完完全全被
之前面试的时候有许多面试官问类加载器相关的问题,所以这是一个很重要的知识点。而且对于高级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); } 复制代码
后来成功的解密了字节码文件,并将其加载到内存中,并成功调用了相关的方法了。
以上是一个非常简单的代码加密,并自定义类加载器的方法,仅供学习其中思路和知识。
喜欢的话记得点个赞的
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 介绍同步加载、异步加载、延迟加载[原创]
- 加密原理详解:对称式加密 VS 非对称式加密
- .net加载失败的程序集重新加载
- 虚拟机类加载机制:类加载时机
- 探秘类加载器和类加载机制
- 编码、摘要和加密(三)——数据加密
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Is Parallel Programming Hard, And, If So, What Can You Do About
Paul E. McKenney
The purpose of this book is to help you understand how to program shared-memory parallel machines without risking your sanity.1 By describing the algorithms and designs that have worked well in the pa......一起来看看 《Is Parallel Programming Hard, And, If So, What Can You Do About 》 这本书的介绍吧!