這個累加載器(EncryptedClassLoader)有兩個基本的操作
在給定的類路徑下加密一系列Class文件並且運行一個先前加密的程序
加密後的文件很簡單
有一些極討厭的各個字節的位組成
(當然
XOR運算符不可能被加密
這只是一個范例
請多多包涵
)
通過EncryptedClassLoader來加載類需要注意一些問題
我實現的是繼承自
URLClassLoader並且重載了loadClass()和defineClass()兩個方法來實現自己的兩個功能
一個是專心於JAVA
類加載器的委托規則並且在系統類加載器做之前先加載一個經加密過的類;二是在執行defineClass()之前立即調用crypt()方法
否則會執行URLClassLoader
findClass()
執行下面的語句
>javac
d bin src/*
java src/my/secret/code/*
java
我把Main
class和MySecretClass
class進行了
加密
>java
cp bin EncryptedClassLoader
encrypt bin Main my
de
MySecretClass
encrypted [Main
class]
encrypted [my\secret\code\MySecretClass
class]
現在原先編譯的class文件已經被加密後的文件所替代了
如果我想運行原始類文件
需要使用EncryptedClassLoader來操作
>java
cp bin Main
Exception in thread
main
java
lang
ClassFormatError:
Main (Illegal constant pool type)
at java
lang
ClassLoader
defineClass
(Native Method)
at java
lang
ClassLoader
defineClass(ClassLoader
java:
)
at java
security
SecureClassLoader
defineClass
(SecureClassLoader
java:
)
at
URLClassLoader
defineClass(URLClassLoader
java:
)
at
URLClassLoader
access$
(URLClassLoader
java:
)
at
URLClassLoader$
run(URLClassLoader
java:
)
at java
security
AccessController
doPrivileged(Native Method)
at
URLClassLoader
findClass(URLClassLoader
java:
)
at java
lang
ClassLoader
loadClass(ClassLoader
java:
)
at sun
misc
Launcher$AppClassLoader
loadClass(Launcher
java:
)
at java
lang
ClassLoader
loadClass(ClassLoader
java:
)
at java
lang
ClassLoader
loadClassInternal(ClassLoader
java:
)
>java
cp bin EncryptedClassLoader
run bin Main
decrypted [Main]
decrypted [de
MySecretClass]
secret result =
現在可以確信
采用任何反編譯工具對加密後的Class文件都不會起作用的
現在添加一個可靠的密碼保護機制
把它打包成本地可執行文件
並且使其對外收費
這樣子可以嗎?當然不能這樣了
ClassLoader
defineClass():必然經過的接口
所有的類加載器必須經過明確地API把類定義傳遞到JVM裡
這就需要java
lang
ClassLoader
defineClass()方法了
類加載器的API有多個這個方法的重載
但是所有的方法都會調用defineClass(String
byte[]
int
int
ProtectionDomain)
這是一個在經過一些簡單驗證後放入到JVM裡的最終的方法
如果你想建立一個新的Class文件的話
這對於理解每個類加載器都會不可避免的調用該方法是很重要的
你只能在方法defineClass()裡把一些單調的字節數組生成Class對象
並且我們猜測這些字節數組文件會包含一些文檔格式化(查看class文件格式規范well
document.d format)的未加密的class定義
通過攔截對該方法的所有調用可以很簡單的破壞這種加密模式
並且很方便的反編譯你感興趣的Class文件
做這種攔截並不困難
實際上破壞自己建立的保護模式比用工具更加迅速的
首先
我取得基於J
SDK的java
lang
ClassLoader源文件
並修改defineClass(String
byte[]
int
int
ProtectionDomain)方法
在裡面加入其他的類
正如下面
c = defineClass
(name
b
off
len
protectionDomain);
//Intercept classes defined by the system loader and its children:
if (isAncestor (getSystemClassLoader ()
getParent ()))
{
// Choose your own dump location here [use an absolute pathname]:
final File parentDir = new File (
c:/TEMP/classes/
);
File dump = new File (parentDir
name
replace (
File
separatorChar) +
[
+
getClass ()
getName () +
@
+Long
toHexString
(System
identityHashCode (this)) +
]
class
);
dump
getParentFile ()
mkdirs ();
FileOutputStream out = null;
try
{
out = new FileOutputStream (dump);
out
write (b
off
len);
}
catch (IOException ioe)
{
ioe
printStackTrace (System
out);
}
finally
{
if (out != null) try { out
close (); }
catch (Exception ignore) {}
}
}
注意if裡的語句可以過濾系統類加載器及其子類加載器
同樣在defineClass()方法可以正常工作的情況下才能載入類
很難以相信不只有一個類加載器實例加載一個類
可通過在文件名堆裡面加入類加載器標志我還是最終把這一問題給解決了
)
最後一步是用包含java
lang
ClassLoader類的可執行文件臨時替換由JRE使用的文件rt
jar
你也可以使用
Xbootclasspath/p選項
我再一次運行加密的程序
並恢復了所有的未加密的文件
這麼說可以很容易的把
class文件正確的反編譯
我先聲明我並沒有用EncryptedClassLoader類的內部機制來完成此壯舉的
在這裡注意一點
假如我沒去使用一個系統類
我可以使用別的方法
比如自定義一個JVMPI代理來處理JVMPI_EVENT_CLASS_LOAD_HOOK事件
學習小結
我希望你能對本文有所興趣
你必須認識到得很重要的一點是在購買市面上任何反編譯工具前要三思而行
除非JVM體系結構進行改革以支持class字節碼在本地能進行譯碼轉換
你才會更好的從傳統的困惑中走出來
上演一場字節碼的改革浪潮!當然也有其他的更有效的方法
對類加載進行調試
盡可能地得到類加載的軌跡是很有價值的
特別是在類加載時你去捕獲異常情況下使用
因此
JAVA的誕生可能純粹是為了開源項目
當然
其他一些體系結構(如
NET)也正在傾向於反編譯
目前我就說說這種思想了
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27493.html