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);
  }
a)  Classloader 是个抽象类 其中通过覆盖findclass来改变文件搜索地址。已达到在任何父classloader加载不到的情况才会由他加载。
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)
a)  根据文件格式查找到文件中的方法实现的bytecode进行加密。加密bytecode不会影响class文件的格式。且所有的文件能在VM加载运行之前总认为他是合法的。可以顺利加载的。


没有个源码。技术含量没有什么,所以就不给源码了,给个示例,key.lic 和java程序放一起就能够正确运行。key.lic不对。或没有程序都不能运行
原文地址:https://www.cnblogs.com/langtianya/p/3459726.html