技术中心

这里象征着我们的态度和能力

>J2ME游戏破解
发布者:中国IT实验室    信息来源:中国IT实验室    发布时间:2012-01-01      浏览次数:6751
分享到:

新浪微博

腾讯微博

QQ空间

豆瓣网

QQ好友

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入

  最近换了一个新手机samsung F488E,终于可以在自己的手机上耍耍游戏了(以前开发J2ME的游戏,都是用的公司测试机)。于是疯狂的下载了一些适合触摸屏240*320的 java游戏,其中有一款RPG游戏玩得很开心,可惜某些地方要发短信收费,一气之下动了破解的念头。以前做过J2ME的开发,熟知J2ME程序都会在最终发布的时候进行混淆编译,一是避免程序被反编译,二是可以大大的减小程序包体积。

  破解的思路很简单:找到实际调用发送接口的方法,让它始终返回“发送成功”,于是多种工具齐上阵就开始干了。

  首先需要把class文件都反编译出来,java反编译工具很多,网上评论也不尽相同,但我试过很多,面对混淆后的字节码,表现得都一样。我使用的是XJad。经过一番查找,找到这样一个方法:

  view plaincopy to clipboardprint?

  private static boolean a(String s1, String s2)

  {

  MessageConnection messageconnection;

  TextMessage textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open(s1)).newMessage("text");

  if (ad.a(messageconnection) || ad.a(textmessage))

  return false;

  textmessage.setAddress(s1);

  textmessage.setPayloadText(s2);

  messageconnection.send(textmessage);

  messageconnection.close();

  return true;

  JVM INSTR pop ;

  return false;

  }

  private static boolean a(String s1, String s2)

  {

  MessageConnection messageconnection;

  TextMessage textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open(s1)).newMessage("text");

  if (ad.a(messageconnection) || ad.a(textmessage))

  return false;

  textmessage.setAddress(s1);

  textmessage.setPayloadText(s2);

  messageconnection.send(textmessage);

  messageconnection.close();

  return true;

  JVM INSTR pop ;

  return false;

  }

  毫无疑问,这就是实际发送短信的地方了。我曾试着把所有反编译过来的java文件中的错误全部改掉,里面有很多乱七八糟的代码,最终自然是编译通过,但不能运行。

  接下来,就要针对这个方法做处理了,有两个思路:一是直接修改字节码,把上述的"return false"的地方统统改成"return true";二是在这个方法的开始加入这段代码"if(true)return true;"。这两个方法在理论上都是可行的。

  一、直接修改字节码

  要查看“return false”对应字节码需要使用JClassLib工具,JClassLib有一个可视化的界面,方便我们查看类的变量、方法、静态数据等,如下图:

  这个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包加进去,演示代码如下:

  view plaincopy to clipboardprint?

  public static void main(String[] args) throws Exception{

  ClassPool pool = ClassPool.getDefault();

  CtClass cc = pool.get("s");

  System.out.println(cc.getSuperclass().getName());

  CtMethod cm = cc.getDeclaredMethod("a", new CtClass[]{pool.get("java.lang.String"),pool.get("java.lang.String")});

  cm.insertBefore("{if(true)return true;}");

  cc.writeFile();

  }

  public static void main(String[] args) throws Exception{

  ClassPool pool = ClassPool.getDefault();

  CtClass cc = pool.get("s");

  System.out.println(cc.getSuperclass().getName());

  CtMethod cm = cc.getDeclaredMethod("a", new CtClass[]{pool.get("java.lang.String"),pool.get("java.lang.String")});

  cm.insertBefore("{if(true)return true;}");

  cc.writeFile();

  }

  其中的pool.get("s"),s就是方法所在的类名,这个地方整得很简洁,连包名都没得,呵呵,一般可能是com.pa.s。CtMethod有很多有用的方法,参考来自http://dev.csdn.net/article/53/53243.shtm 的文章可以发现,这里只使用到insertBefore,还有setBody也是很实用的。

  以下是使用setBody方法实现的方法替换:

  view plaincopy to clipboardprint?

  public static void main(String[] args) throws Exception{

  ClassPool pool = ClassPool.getDefault();

  CtClass cc = pool.get("s");

  System.out.println(cc.getSuperclass().getName());

  CtMethod cm = cc.getDeclaredMethod("a", new CtClass[]{pool.get("java.lang.String"),pool.get("java.lang.String")});

  /*

  cm.insertBefore("{if(true)return true;}");

  */

  CtMethod m2 = CtNewMethod.copy(cm, cc, null);

  cm.setName(cm.getName() + "_orig");

  //setBody第一个参数是要设置的方法体,第二个参数就是CtClass中对应的类名

  //m2.setBody("{ System.out.println("call"); return $proceed(

1 2 3
4000-880-989
(24小时热线)
联系客服
微信公众号

官方公众号

小程序

©2008-2022 CORPORATION ALL Rights Reserved. 版权所有 滇ICP备09003328号-1 滇公网安备 53011102000818号
昆明那家网络公司好,新媒体运营,网站优化,网络推广,网站建设,网页设计,网站设计,网站推广,云南网站公司,昆明新媒体公司,云南网红主播,昆明SEO公司,昆明网站建设,昆明网络推广,昆明网站优化,昆明网站推广,红河网站建设,大理网络公司,曲靖网络公司,丽江网站设计,昭通网络公司,保山大数据服务,智慧高速建设,智慧校园服务,云南IDC服务商,网络安全测评,等保测评,网站关键词排名优化服务,服务客户尽超2000余家,一切尽在奥远科技,服务电话:13888956730
Baidu
map