我們都知道JAVA是一種解析型語言,這就決定JAVA文件編譯后不是機器碼,而是一個字節碼文件,也就是CLASS文件。而這樣的文件是存在規律的,經過反編譯工具是可以還原回來的。例如Decafe、FrontEnd,YingJAD和Jode等等軟件。下面是《Nokia中Short數組轉換算法》
thread.jspa?threadID=872&tstart=0
類中Main函數的ByteCode:
0?ldc?#16?
2?invokestatic?#18?
5?astore_1
6?return
其源代碼是:short?[]?pixels?=?parseImage(\"/ef1s.png\");
我們通過反編譯工具是可以還原出以上源代碼的。而通過簡單的分析,我們也能自己寫出源代碼的。
第一行:ldc?#16?
ldc為虛擬機的指令,作用是:壓入常量池的項,形式如下
ldc?index
這個index就是上面的16,也就是在常量池中的有效索引,當我們去看常量池的時候,我們就會找到index為16的值為String_info,里面存了/ef1s.png.
所以這行的意思就是把/ef1s.pn作為一個String存在常量池中,其有效索引為16。
第二行:2?invokestatic?#18?
invokestatic為虛擬機指令,作用是:調用類(static)方法,形式如下
invokestatic?indexbyte1?indexbyte2
其中indexbyte1和indexbyte2必須是在常量池中的有效索引,而是指向的類型必須有Methodref標記,對類名,方法名和方法的描述符的引用。
所以當我們看常量池中索引為18的地方,我們就會得到以下信息:
Class?Name?:?cp_info#1?
Name?Type?:?cp_info#19?
1?和19都是常量池中的有效索引,值就是右邊<>中的值,再往下跟蹤我就不多說了,有興趣的朋友可以去JAVA虛擬機規范。
這里我簡單介紹一下parseImage(Ljava/lang/String;)[S?的意思。
這就是parseImage這個函數的運行,我們反過來看看parseImage的原型就明白了
short?[]?parseImage(String)
那么Ljava/lang/String;就是說需要傳入一個String對象,而為什么前面要有一個L呢,這是JAVA虛擬機用來表示這是一個Object。如果是基本類型,這里就不需要有L了。然后返回為short的一維數組,也就是對應的[S。是不是很有意思,S對應著Short類型,而“[”對應一維數組,那有些朋友要問了,兩維呢,那就“[[”,呵呵,是不是很有意思。
好了,調用了函數,返回的值要保存下來吧。那么就是第三行要做的事情了。
第三行:5?astore_1
呵呵,很簡單的。但是卻有文章,也是比較容易混亂的地方。
astore_為虛擬機指令,作用為:將當前reference存儲到局部變量中去。而必須是對當前框架的局部變量的有效索引。打個比方,可能我們這個函數中可能還要用到這個局部變量,我們可以通過來找到它。例如調用虛擬機指令:
aload_1,就能得到該值。
第四行:6?return
同樣的,return也是虛擬機指令了,它的作用為:從方法返回void。
這里也就是退出main函數。
----------------------------------------------------------------------------
ok,終于啰嗦完畢了。有些朋友可能要問,這么復雜,才四行就說這么多,呵呵,可能是我這人廢話過多,當然如果你熟悉了,一點就能看懂了。通過肉眼就可以反編譯程序了。目前所有的反編譯工具都無法做到完美反編譯,在有問題的地方還需要人去修正。
好了,說了半天如何反編譯,我們就來看看如果在你的程序如果防止別人來反編譯。好不容易寫好的程序被人反編譯了,多郁悶。哈哈。工欲善其事,必先利其器,這句話用對了嗎?
什么混淆等等的方法,我就不說了,我這里主要是要說一種通過添加代碼來在某種程度來避免當前流行的反編譯工具對你的代碼進行反編譯。
方案一。
1,首先要添加一個參數為Exception類型的函數,例如這樣。
public?static?void?Fake(Exception?e)
{
e.toString();
}
一定要有e.toString();,因為要防止你的混淆器把無用的代碼過濾。
2,然后在每個類中調用這個函數,放在try...catch(Exception?e)..中的catch里面,例如:
try
{
...
}
catch?(Exception?e)
{
Fake(e);
}
請注意?,一定要放在catch才有用,其他地方無用。
方案二。
如果以上方法還不夠專業,我們再來一個。呵呵~
1,同樣的,我們定義一個類,這個類叫做AntiCrack.。名字好像有點大。。。代碼如下:
public?class?AntiCrack
{
private?AntiCrack()
{
}
public?static?Throwable?Fake(Throwable?throwable,?Throwable?throwable1)
{
try
{
throwable.getClass().getMethod(\"initCause\",?new?Class[]?{
java.lang.Throwable.class
}).invoke(throwable,?new?Object[]?{
throwable1
});
}
catch(Exception?exception)?{?}
return?throwable;
}
}
2,同樣的,我們在catch里面調用該函數。例如如下。
try
{
//your?code?here?
}
catch(IOException?ioexception)
{
IllegalArgumentException?illegalargumentexception?=?new?IllegalArgumentException(ioexception.toString());
AntiCrack.fake(illegalargumentexception,?ioexception);
throw?illegalargumentexception;
}
或者也可以這樣
public?class?AntiException?extends?Exception
{
public?AntiException()
{
}
public?AntiException(String?s)
{
super(s);
}
public?AntiException(String?s,?Throwable?throwable)
{
super(s);
AntiCrack.fake(this,?throwable);
}
}
然后在你的程序里面?
try
{
}
catch(IoException?e)
{
throw?new?AntiException(ioexception.toString(),?ioexception);
}
當采用以上方式后,任何類只要調用了該函數,生成的class反編譯后出錯,得不到結果。
Decafe、FrontEnd和YingJAD,反編譯時都有exception,然后無法進行下去。大家可以多測試變得反編譯工具。建議推薦用第二個方法。
posted on 2006-04-29 09:56
崛起的程序員 閱讀(963)
評論(0) 編輯 收藏 所屬分類:
載選文章