隨筆-88  評(píng)論-77  文章-48  trackbacks-0
          我們都知道JAVA是一種解析型語言,這就決定JAVA文件編譯后不是機(jī)器碼,而是一個(gè)字節(jié)碼文件,也就是CLASS文件。而這樣的文件是存在規(guī)律的,經(jīng)過反編譯工具是可以還原回來的。例如Decafe、FrontEnd,YingJAD和Jode等等軟件。下面是《Nokia中Short數(shù)組轉(zhuǎn)換算法》

          thread.jspa?threadID=872&tstart=0

          類中Main函數(shù)的ByteCode:

          0?ldc?#16?
          2?invokestatic?#18?
          5?astore_1
          6?return

          其源代碼是:short?[]?pixels?=?parseImage(\"/ef1s.png\");

          我們通過反編譯工具是可以還原出以上源代碼的。而通過簡(jiǎn)單的分析,我們也能自己寫出源代碼的。

          第一行:ldc?#16?
          ldc為虛擬機(jī)的指令,作用是:壓入常量池的項(xiàng),形式如下

          ldc?index

          這個(gè)index就是上面的16,也就是在常量池中的有效索引,當(dāng)我們?nèi)タ闯A砍氐臅r(shí)候,我們就會(huì)找到index為16的值為String_info,里面存了/ef1s.png.

          所以這行的意思就是把/ef1s.pn作為一個(gè)String存在常量池中,其有效索引為16。

          第二行:2?invokestatic?#18?

          invokestatic為虛擬機(jī)指令,作用是:調(diào)用類(static)方法,形式如下

          invokestatic?indexbyte1?indexbyte2

          其中indexbyte1和indexbyte2必須是在常量池中的有效索引,而是指向的類型必須有Methodref標(biāo)記,對(duì)類名,方法名和方法的描述符的引用。

          所以當(dāng)我們看常量池中索引為18的地方,我們就會(huì)得到以下信息:

          Class?Name?:?cp_info#1?

          Name?Type?:?cp_info#19?

          1?和19都是常量池中的有效索引,值就是右邊<>中的值,再往下跟蹤我就不多說了,有興趣的朋友可以去JAVA虛擬機(jī)規(guī)范。

          這里我簡(jiǎn)單介紹一下parseImage(Ljava/lang/String;)[S?的意思。

          這就是parseImage這個(gè)函數(shù)的運(yùn)行,我們反過來看看parseImage的原型就明白了

          short?[]?parseImage(String)

          那么Ljava/lang/String;就是說需要傳入一個(gè)String對(duì)象,而為什么前面要有一個(gè)L呢,這是JAVA虛擬機(jī)用來表示這是一個(gè)Object。如果是基本類型,這里就不需要有L了。然后返回為short的一維數(shù)組,也就是對(duì)應(yīng)的[S。是不是很有意思,S對(duì)應(yīng)著Short類型,而“[”對(duì)應(yīng)一維數(shù)組,那有些朋友要問了,兩維呢,那就“[[”,呵呵,是不是很有意思。

          好了,調(diào)用了函數(shù),返回的值要保存下來吧。那么就是第三行要做的事情了。

          第三行:5?astore_1

          呵呵,很簡(jiǎn)單的。但是卻有文章,也是比較容易混亂的地方。

          astore_為虛擬機(jī)指令,作用為:將當(dāng)前reference存儲(chǔ)到局部變量中去。而必須是對(duì)當(dāng)前框架的局部變量的有效索引。打個(gè)比方,可能我們這個(gè)函數(shù)中可能還要用到這個(gè)局部變量,我們可以通過來找到它。例如調(diào)用虛擬機(jī)指令:

          aload_1,就能得到該值。

          第四行:6?return

          同樣的,return也是虛擬機(jī)指令了,它的作用為:從方法返回void。

          這里也就是退出main函數(shù)。

          ----------------------------------------------------------------------------

          ok,終于啰嗦完畢了。有些朋友可能要問,這么復(fù)雜,才四行就說這么多,呵呵,可能是我這人廢話過多,當(dāng)然如果你熟悉了,一點(diǎn)就能看懂了。通過肉眼就可以反編譯程序了。目前所有的反編譯工具都無法做到完美反編譯,在有問題的地方還需要人去修正。

          好了,說了半天如何反編譯,我們就來看看如果在你的程序如果防止別人來反編譯。好不容易寫好的程序被人反編譯了,多郁悶。哈哈。工欲善其事,必先利其器,這句話用對(duì)了嗎?

          什么混淆等等的方法,我就不說了,我這里主要是要說一種通過添加代碼來在某種程度來避免當(dāng)前流行的反編譯工具對(duì)你的代碼進(jìn)行反編譯。

          方案一。

          1,首先要添加一個(gè)參數(shù)為Exception類型的函數(shù),例如這樣。

          public?static?void?Fake(Exception?e)
          {
          e.toString();
          }

          一定要有e.toString();,因?yàn)橐乐鼓愕幕煜靼褵o用的代碼過濾。

          2,然后在每個(gè)類中調(diào)用這個(gè)函數(shù),放在try...catch(Exception?e)..中的catch里面,例如:

          try
          {
          ...
          }
          catch?(Exception?e)
          {
          Fake(e);
          }

          請(qǐng)注意?,一定要放在catch才有用,其他地方無用。

          方案二。

          如果以上方法還不夠?qū)I(yè),我們?cè)賮硪粋€(gè)。呵呵~

          1,同樣的,我們定義一個(gè)類,這個(gè)類叫做AntiCrack.。名字好像有點(diǎn)大。。。代碼如下:

          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,同樣的,我們?cè)赾atch里面調(diào)用該函數(shù)。例如如下。

          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);

          }

          當(dāng)采用以上方式后,任何類只要調(diào)用了該函數(shù),生成的class反編譯后出錯(cuò),得不到結(jié)果。

          Decafe、FrontEnd和YingJAD,反編譯時(shí)都有exception,然后無法進(jìn)行下去。大家可以多測(cè)試變得反編譯工具。建議推薦用第二個(gè)方法。
          posted on 2006-04-29 09:56 崛起的程序員 閱讀(964) 評(píng)論(0)  編輯  收藏 所屬分類: 載選文章
          主站蜘蛛池模板: 贺兰县| 若尔盖县| 启东市| 霍州市| 孟连| 平舆县| 盐津县| 遂昌县| 荆州市| 简阳市| 大姚县| 聂拉木县| 曲周县| 定兴县| 平陆县| 昔阳县| 洪洞县| 罗甸县| 百色市| 武鸣县| 望奎县| 宽甸| 水富县| 榕江县| 嘉兴市| 通渭县| 华容县| 石林| 延津县| 皮山县| 吉安市| 葵青区| 广德县| 华坪县| 安平县| 崇明县| 吴江市| 获嘉县| 惠东县| 衡阳市| 凤山县|