文章出處


利用 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不對。或沒有程序都不能運行

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()