J2ME遊戲破解心得暨反編譯位元組碼操作研究

來源:互聯網
上載者:User

      最近換了一個新手機samsung F488E,終於可以在自己的手機上耍耍遊戲了(以前開發J2ME的遊戲,都是用的公司測試機)。於是瘋狂的下載了一些適合觸控螢幕240*320的java遊戲,其中有一款RPG遊戲玩得很開心,可惜某些地方要發簡訊收費,一氣之下動了破解的念頭。以前做過J2ME的開發,熟知J2ME程式都會在最終發布的時候進行混淆編譯,一是避免程式被反編譯,二是可以大大的減小程式包體積。

破解的思路很簡單:找到實際調用發送介面的方法,讓它始終返回“發送成功”,於是多種工具齊上陣就開始幹了。

      首先需要把class檔案都反編譯出來,java反編譯工具很多,網上評論也不盡相同,但我試過很多,面對混淆後的位元組碼,表現得都一樣。我使用的是XJad。經過一番尋找,找到這樣一個方法:

private static boolean a(String s1, String s2)<br />{<br />MessageConnection messageconnection;<br />TextMessage textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open(s1)).newMessage("text");<br />if (ad.a(messageconnection) || ad.a(textmessage))<br />return false;<br />textmessage.setAddress(s1);<br />textmessage.setPayloadText(s2);<br />messageconnection.send(textmessage);<br />messageconnection.close();<br />return true;<br />JVM INSTR pop ;<br />return false;</p><p>}

      毫無疑問,這就是實際傳送簡訊的地方了。我曾試著把所有反編譯過來的java檔案中的錯誤全部改掉,裡面有很多亂七八糟的代碼,最終自然是編譯通過,但不能運行。

      接下來,就要針對這個方法做處理了,有兩個思路:一是直接修改位元組碼,把上述的"return false"的地方統統改成"return true";二是在這個方法的開始加入這段代碼"if(true)return true;"。這兩個方法在理論上都是可行的。

      一、直接修改位元組碼

      要查看“return false”對應位元組碼需要使用JClassLib工具,JClassLib有一個可視化的介面,啟動命令:java -jar jclasslib.jar,
方便我們查看類的變數、方法、待用資料等,如:

這個a方法(也許實際名稱就是sendsms)的位元組碼如下:

 0 aload_0
 1 invokestatic #42 <javax/microedition/io/Connector.open>
 4 checkcast #11 <javax/wireless/messaging/MessageConnection>
 7 dup
 8 astore_2
 9 ldc #61 <text>
11 invokeinterface #48 <javax/wireless/messaging/MessageConnection.newMessage> count 2
16 checkcast #12 <javax/wireless/messaging/TextMessage>
19 astore_3
20 aload_2
21 invokestatic #29 <ad.a>
24 ifne 34 (+10)
27 aload_3
28 invokestatic #29 <ad.a>
31 ifeq 36 (+5)
34 iconst_0
35 ireturn
36 aload_3
37 aload_0
38 invokeinterface #50 <javax/wireless/messaging/TextMessage.setAddress> count 2
43 aload_3
44 aload_1
45 invokeinterface #51 <javax/wireless/messaging/TextMessage.setPayloadText> count 2
50 aload_2
51 aload_3
52 invokeinterface #49 <javax/wireless/messaging/MessageConnection.send> count 2
57 aload_2
58 invokeinterface #47 <javax/wireless/messaging/MessageConnection.close> count 1
63 iconst_1
64 ireturn
65 pop
66 iconst_0
67 ireturn
通過尋找JVM指令集,0x03 iconst_0   將int型0推送至棧頂 ,0x04 iconst_1   將int型1推送至棧頂 ,0xac ireturn    從當前方法返回int,很明顯,63-67行就是對應的

return true;
JVM INSTR pop ;
return false;

這5行對應的16進位值是:0x04,0xAC,0x57,0x03,0xAC,於是,用16進位編輯器開啟,尋找04AC5703AC的位置,果然不負眾望,接下來你知道怎麼做了吧,把0x03這個位置的值換成0x04,那麼這個return false不就變成return true了,呵呵。

      二、在該方法體前加直接返回true的代碼

      這個方法比上一方法更加靈活強大,使用Javassite和JClassLib相結合,甚至可以將class改得“體無完膚”,哈哈哈哈。還是以這個方法為例,通過反編譯後,知道該方法名和參數,則可以通過Javassite擷取到該方法對象,進而進行更多的處理。在eclipse建一個Java項目,把Javassite和JClassLib的jar包加進去,示範代碼如下:

public static void main(String[] args) throws Exception{</p><p>ClassPool pool = ClassPool.getDefault();<br />CtClass cc = pool.get("s");<br />System.out.println(cc.getSuperclass().getName());</p><p>CtMethod cm = cc.getDeclaredMethod("a", new CtClass[]{pool.get("java.lang.String"),pool.get("java.lang.String")});</p><p>cm.insertBefore("{if(true)return true;}");<br />cc.writeFile();</p><p>}

      其中的pool.get("s"),s就是方法所在的類名,這個地方整得很簡潔,連包名都沒得,呵呵,一般可能是com.pa.s。CtMethod有很多有用的方法,參考來自http://dev.csdn.net/article/53/53243.shtm 的文章可以發現,這裡只使用到insertBefore,還有setBody也是很實用的。

      以下是使用setBody方法實現的方法替換:

public static void main(String[] args) throws Exception{</p><p>ClassPool pool = ClassPool.getDefault();<br />CtClass cc = pool.get("s");<br />System.out.println(cc.getSuperclass().getName());</p><p>CtMethod cm = cc.getDeclaredMethod("a", new CtClass[]{pool.get("java.lang.String"),pool.get("java.lang.String")});<br />/*<br />cm.insertBefore("{if(true)return true;}");<br />*/<br />CtMethod m2 = CtNewMethod.copy(cm, cc, null);<br />cm.setName(cm.getName() + "_orig");<br />//setBody第一個參數是要設定的方法體,第二個參數就是CtClass中對應的類名<br />//m2.setBody("{ System.out.println(/"call/"); return $proceed($$);}", "s", cm.getName());<br />m2.setBody("{ return true;}", "s", cm.getName());<br />cc.addMethod(m2);<br />cc.writeFile();</p><p>}

      經過如此替換之後,該方法變成如下:

private static boolean a_orig(String s1, String s2)<br />{<br />MessageConnection messageconnection;<br />TextMessage textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open(s1)).newMessage("text");<br />if (ad.a(messageconnection) || ad.a(textmessage))<br />return false;<br />textmessage.setAddress(s1);<br />textmessage.setPayloadText(s2);<br />messageconnection.send(textmessage);<br />messageconnection.close();<br />return true;<br />JVM INSTR pop ;<br />return false;<br />}<br />private static boolean a(String s1, String s2)<br />{<br />return true;<br />}

     可見,原方法已經被新方法替換了。

     CtClass的wrtieFile方法,將更新後的位元組碼寫入class檔案。     

      但在本例中,採用insertBefore這樣產生的class,安裝到手機上後,調用該方法時出現了程式直接跳出來的現象,可能是某些改得引起了手機的不相容,而setBody方法沒有這個問題。當然,對於其他的java應用,這樣的改動應該是不會出現這樣的問題的。

      最後總結一下,破解J2ME遊戲的簡要步驟就是:

     1、反編譯class檔案,可能部分代碼不可讀,但瞄準破解的關鍵地方,針對某個類某個方法來處理;

     2、使用JClassLib分析類、方法的位元組碼,與反編譯的代碼進行比對,尋找對應的16進位值位置;或者使用Javassite修改對應的方法位元組碼,重建class檔案。

     3、對於簡單的值修改,使用16進位編輯器進行修改即可。

     以上是今天破解一個J2ME遊戲和位元組碼操作的心得,供大家參考,歡迎交流!

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.