JAVA 利用JNI加密class文件/自定义ClassLoader 类
利用 JNI 对bytecode 加密.不影响java程序员的正常开发。
09年的时候写的,现在拿出来晒晒
————————————————————————————
混淆才是王道,如果混淆再加密就更酷了....
————————————————————————————
一、环境
a) Windows_xp_Sp2_En
b) JavaSe_1.6
c) Eeclipse.buildId_M20090917-0800
d) Tomcat_6.02
e) VS2008_Sp1
二、JAVA 程序加密关键点:
1、ClassLoader的自定义
代码:
public class MyClassLoader extends ClassLoader { /** * @param args */ private native void encrypt(); public byte[] bytes; public String classDir; private String LocalName; private boolean Flag(FileInputStream fis, ByteArrayOutputStream bos) throws Exception{ boolean Result = false; if(fis.read()==0xCA)Result=true; return Result; } @SuppressWarnings("deprecation") @Override protected Class<?> findClass(String arg0) throws ClassNotFoundException { String name; if(LocalName!=null) name=LocalName; else name=arg0; System.out.println("on my Findclass way"); String ClassName = name.substring(name.lastIndexOf('.')+1) + ".class"; String classFileName = System.getProperty("user.dir")+"\\cn\\drawingbox\\" + ClassName; try { FileInputStream fis = new FileInputStream(classFileName); ByteArrayOutputStream bos = new ByteArrayOutputStream(); fis.close(); //这里调用JNI函数进行解码 //System.getProperties().setProperties(String key,String value) //System.setProperties(arg0); System.load(classDir+"\\encrypt_main.dll"); // System.loadLibrary("encrypt_main"); MyClassLoader encypt_function= new MyClassLoader(); encypt_function.classDir=classDir; encypt_function.bytes = bos.toByteArray(); encypt_function.encrypt(); /////// LocalName=null; return defineClass(encypt_function.bytes, 0, encypt_function.bytes.length); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @Override public Class<?> loadClass(String name) throws ClassNotFoundException { // TODO Auto-generated method stub boolean Result = false; String ClassName = name.substring(name.lastIndexOf('.')+1) + ".class"; if(ClassName.equals("Foo.class")||ClassName.equals("bar.class")){ String classFileName = classDir + "\\" + ClassName; try { FileInputStream fis = new FileInputStream(classFileName); ByteArrayOutputStream bos = new ByteArrayOutputStream(); Result = Flag(fis, bos); fis.close(); bos.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } // TODO Auto-generated method stub if(Result==true) { LocalName=name; return super.loadClass("ThisIsJoy"); } else { LocalName=null; return super.loadClass(name); } } else return super.loadClass(name); }
b) Classloader的加载机制是让自己的父classloader加载如果加载不到再有自己加载。如果有父classloader会一直向上询问。
2、不影响程序的调用关系。
文件格式不能改变class文件必须是合法文件否则编译时不能后通过。可以编译不代表可以正常运行、不对class文件进行加密。只对其方法中的字节码加密,正常编译在最后发布时进行classloader包开发进行加密解密
通过Java Native Interface(JNI)的调用或的使用本地代码的方法可以实现java加密与本地信息的结合,演示中加密方法使用简单的XOR方法加密
代码:
//异或需要被加密的class的bytecode部分
第一部分为程序主体,简单调用一个类中的一个方法在控制台上打印一串字符 HelloJava代码见源程序
第二部分为自定义ClassLoader 负责加载主体程序文件。并解密其中的加密部分。详细过程见附录ClassLoader自定义和byteCode加密解密部分
2.反射调用自己调用的加载类的的方法。此方法应该是你的程序的入口函数。这样可以保证你程序的顺利运行。
代码:
Class<?> clazz = null; clazz = new MyClassLoader(System.getProperty("user.dir")+"\\cn\\drawingbox").loadClass("cn.drawingbox.Foo"); clazz.newInstance(); //clazz.forName("cn.drawingbox.Foo"); clazz.getMethod("FooFunction").invoke(null)
没有个源码。技术含量没有什么,所以就不给源码了,给个示例,key.lic 和java程序放一起就能够正确运行。key.lic不对。或没有程序都不能运行