Android 安全——Java环境动态加载Jar之Jar包的加密和解密
2015-06-25 16:03
567 查看
编写测试Jar包
1.类结构
2.类代码
Parent.classpackage com.wind.test; abstract class Parent { public String name() { return "Piter"; } }
Jim.class
package com.wind.test; class Jim extends Parent { public String name() { return "My father is " + super.name() + " and my name is Jim"; } }
Tom.class
package com.wind.test; class Tom extends Parent{ public String name() { return "My father is " + super.name() + " and my name is Tom"; } }
Test.class
package com.wind.test; public class Test { public void print() { Jim son1 = new Jim(); System.out.println(son1.name()); Tom son2 = new Tom(); System.out.println(son2.name()); } }
Main.class
package com.wind.main; import com.wind.test.Test; public class Main { public static void main(String[] args) { new Test().print(); } }
3.运行结果
4.打包
打包过程在上一篇文章有,这里就不赘述了。Jar包的加密类
package com.wind.load.enjar; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import com.wind.load.Base64; public class JarEncoder { private JarInputStream jis; public JarEncoder(String src) throws FileNotFoundException, IOException { this(new FileInputStream(src)); } public JarEncoder(File file) throws FileNotFoundException, IOException { this(new FileInputStream(file)); } public JarEncoder(InputStream is) throws IOException { jis = new JarInputStream(is); } /** * 通过指定的路径输出加密后的jar * @param target * @throws FileNotFoundException * @throws IOException */ public void write(String target) throws FileNotFoundException, IOException { write(new FileOutputStream(target)); } /** * 通过指定的文件输出加密后的jar * @param file * @throws FileNotFoundException * @throws IOException */ public void write(File file) throws FileNotFoundException, IOException { write(new FileOutputStream(file)); } /** * 通过指定的输出流输出加密后的jar * @param os * @throws FileNotFoundException * @throws IOException */ public void write(OutputStream os) throws FileNotFoundException, IOException { Manifest menifest = jis.getManifest(); //获取jar的Manifest信息 JarOutputStream jos = null; if(menifest == null) { jos = new JarOutputStream(os); } else { //JarInputStream的getNextJarEntry()方法无法获取Manifest信息,所以只能通过这种方式写入Manifest信息 jos = new JarOutputStream(os, menifest); } JarEntry entry = null; while((entry = jis.getNextJarEntry()) != null) { jos.putNextEntry(entry); if(entry.getName().endsWith(".class")) { //只加密class文件 4000 byte[] bytes = getBytes(jis); //读取class文件内容 byte[] enbytes = Base64.encode(bytes); //加密后的信息 jos.write(enbytes, 0, enbytes.length); //把加密后的信息写入流 } else { //其他类型的文件直接写入流 byte[] bytes = getBytes(jis); jos.write(bytes, 0, bytes.length); } jos.flush(); } jos.close(); jis.close(); } /** * 从jar输入流中读取信息 * @param jis * @return * @throws IOException */ private byte[] getBytes(JarInputStream jis) throws IOException { int len = 0; byte[] bytes = new byte[8192]; ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); while((len = jis.read(bytes, 0, bytes.length)) != -1) { baos.write(bytes, 0, len); } return baos.toByteArray(); } }
Jar包的解密类
package com.wind.load.dejar; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import com.wind.load.Base64; public class JarDecoder extends ClassLoader { private JarInputStream jis; private Map<String, ByteBuffer> entryMap; public JarDecoder(String src) throws FileNotFoundException, IOException { this(new FileInputStream(src)); } public JarDecoder(File file) throws FileNotFoundException, IOException { this(new FileInputStream(file)); } public JarDecoder(InputStream is) throws IOException { jis = new JarInputStream(is); entryMap = new HashMap<String, ByteBuffer>(); JarEntry entry = null; while((entry = jis.getNextJarEntry()) != null) { String name = entry.getName(); if(name.endsWith(".class")) { //class文件解密后再缓存 byte[] bytes = getBytes(jis); //读取class文件内容 byte[] debytes = Base64.decode(bytes); //解密class文件内容 ByteBuffer buffer = ByteBuffer.wrap(debytes); //把数据复制到ByteBuffer对象中 entryMap.put(name, buffer); //缓存数据 } else { //其他文件直接缓存 byte[] bytes = getBytes(jis); ByteBuffer buffer = ByteBuffer.wrap(bytes); entryMap.put(name, buffer); } } jis.close(); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { String path = name.replace('.', '/').concat(".class"); ByteBuffer buffer = entryMap.get(path); if(buffer == null) { return super.findClass(name); } else { byte[] bytes = buffer.array(); return defineClass(name, bytes, 0, bytes.length); } } /** * 从jar输入流中读取信息 * @param jis * @return * @throws IOException */ private byte[] getBytes(JarInputStream jis) throws IOException { int len = 0; byte[] bytes = new byte[8192]; ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); while((len = jis.read(bytes, 0, bytes.length)) != -1) { baos.write(bytes, 0, len); } return baos.toByteArray(); } /** * 关闭Decoder * @throws IOException */ public void close() throws IOException { Iterator<ByteBuffer> iterator = entryMap.values().iterator(); while(iterator.hasNext()) { ByteBuffer buffer = iterator.next(); buffer.clear(); //清空ByteBuffer对象缓存 } entryMap.clear(); //清空HashMap } }
测试类
package com.wind.load; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import com.wind.load.dejar.JarDecoder; import com.wind.load.enjar.JarEncoder; public class Main { public static void main(String[] args) { encode(); decode(); } private static void encode() { try { JarEncoder encoder = new JarEncoder("E:/test.jar"); encoder.write("E:/test_encode.jar"); System.out.println("encode success"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static void decode() { try { JarDecoder decoder = new JarDecoder("E:/test_encode.jar"); Class<?> cls = decoder.loadClass("com.wind.test.Test"); Method method = cls.getMethod("print", null); method.invoke(cls.newInstance(), null); decoder.close(); System.out.println("decode success"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } }
运行结果
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories