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