转至手游


坛里关于手机短信游戏破解的文章有很多,而且很有水平,令人高山仰止!实不想班门弄斧,恐招千夫所指!HALO2的推出给破解工作带来了许多便利,有必要向新手们介绍下,本人水平有限,文中不足之处请多多包涵!郑重声明:文中所引用的例子谨作为学习交流,并无它意!
  HALO2打开底下城与勇士.jar,点击"类编辑器","编辑"选项中选"全文查",搜索栏中填入"MessageConnection",搜索方式选"By total class",开始搜索!(1)



搜索结果如下:(2)



其中"类名  j  "是指该方法JAR包根目录下的j.class.
  "方法名  f  "就是指该方法名为"f" .
  "签名"是对该方法的描述,是区别于同一个class文件里同名方法唯一表述.我们反编译j.class,到这个"f"方法,它的起首行"private void f(int i1)"表明它的使用权限为"私有的"(private),public指公共的,friendly 指友好的,protected指受保护的!具体的说明请参考专业的教材.void是指该方法的返回类型,也就是别的方法调用该方法所得到的东西,void意味着什么也不返回",但也可返回一些变量值或其它结果.具体的要结合程序分析.比如"boolean"就表示它返回的就是布尔值,即真(true)和假(false).具体的说明也请参考专业的教材.括号里的(int i1)是该方法的自变量列表.自变量列表规定了我们在调用这个方法时传递给它的东西.对于本方法int i1是指:
该方法传递一个整型变量(int),变量名是i1.
  让我们双击这个搜索结果来到j.class下的private void f(int i1)方法.点击这个"f"方法(不是它的下层目录"[0]code"!!! )上面所说的东西如图3.

 


以下是反编译后程序:
  private void f(int i1)
    {
        b = i1;
        a = false;
        MessageConnection messageconnection = null;
        Object obj = null;
        if(l == 0)
        {
            h = "sms://" + d[0];
            i = "JG " + e + " " + f + "#" + g;
            l = 1;
        } else
        if(l == 1)
        {
            h = "sms://" + d[1];
            i = "62 " + e + " " + f + "#" + g;
            l = 0;
        }
        try
        {
            TextMessage textmessage;
            (textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open(h)).newMessage("text")).setPayloadText(i);
            messageconnection.send(textmessage);
        }
        catch(Exception _ex)
        {
            b = 0;
        }
        try
        {
            messageconnection.close();
        }
        catch(Exception _ex) { }
        a = true;
    }
  其中:try
        {
            TextMessage textmessage;
            (textmessage = (TextMessage)(messageconnection = (MessageConnection)Connector.open(h)).newMessage("text")).setPayloadText(i);
            messageconnection.send(textmessage);
        }
        catch(Exception _ex)
        {
            b = 0;
        }是检查是否进行了动作,如果没发送就抛出异常并将变量b赋值为0(b = 0).
 

  而下一段:
try
        {
            messageconnection.close();
        }
        catch(Exception _ex) { }
        a = true
  是检查是否完毕,如果没完毕就抛出异常,如果完毕了就将变量a赋值为 true( a = true).就是说只有a = true才可以享受到后的服务!该方法的任务就是返回ab两个变量,其他的都是多余的,都可以删除!
  HALO2的代码编辑修改后,该方法变成了:
aload_0
iload_1
putfield j/b I
aload_0
iconst_1
putfield j/a Z
return
反编译后程序:
private void f(int i1)
    {
        b = i1;
        a = true;
    }
  我们在模拟器上试验下,发现还是没破解成功!而且屏幕显示"正在购买....请稍等片刻......",
原来的一样!即是说游戏另有陷阱,所以这就是用HALO自动破解失败的原因!
  好的那我们换个角度来思考!请看以下这段文字:public static String c[] = {
        "购买成功,您的游戏币已增加5000!<br>", "购买成功,欢迎进入体验!<br>", "购买成功,杀伤力已经加倍!<br>", "购买成功,升级后能获得加倍的技能点!<br>", "购买成功,接下来打怪获得的经验值比之前增加一倍!<br>", "购买成功,接下来的强化装备属性100%成功!<br>", "隐藏职业已开启,请返回选择职业!<br>" 
  这就是成功后所显示的信息!我就想到调用这段文字的方法,看看判断短信发送成功的条件是怎样的.这个方法是静态(static)类型的,HALO2里就是<clinit>这段:
anewarray java/lang/String
dup
iconst_0
ldc "购买成功,您的游戏币已增加5000!<br>"
aastore
dup
iconst_1
ldc "购买成功,欢迎进入体验!<br>"
aastore
dup
iconst_2
ldc "购买成功,杀伤力已经加倍!<br>"
aastore
dup
iconst_3
ldc "购买成功,升级后能获得加倍的技能点!<br>"
aastore
dup
iconst_4
ldc "购买成功,接下来打怪获得的经验值比之前增加一倍!<br>"
aastore
dup
iconst_5
ldc "购买成功,接下来的强化装备属性100%成功!<br>"
aastore
dup
bipush 6
ldc "隐藏职业已开启,请返回选择职业!<br>"
aastore
putstatic j/c [Ljava/lang/String;
最后这句:"putstatic j/c [Ljava/lang/String""putstatic"我把它理解为把数据放入寄存器(堆栈?),(我没专门学过任何高级语言,只是小时候玩学习机时,接触了些FBASIC语言.不知这样解释对否?请高手不要见笑!)getstatic就应该是把数据从寄存器里取出,j/c [Ljava/lang/String就是存放以上数据的地址的标签.我们在HALO2里的类编辑器搜索j/c [Ljava/lang/String;会有两个结果,其中一个就是上面那段,不用理会.还有个d方法在j.class,即是这段:
private void d()
    {
        switch(d)
        {
        case 2: // '\002'
        default:
            break;

        case 0: // '\0'
            String s = "";
            switch(e)
            {
            case 2: // '\002'
                s = s + "购买后伤害倍数为:" + 2 * a.cF + "";
                break;

            case 4: // '\004'
                s = s + "购买后经验值倍数为:" + 2 * a.cE + "";
                break;

            case 3: // '\003'
                s = s + "购买后技能点倍数为:" + 2 * a.cG + "";
                break;
            }
            a.a(c[e] + s, b[1], b[2], b[3], b[4]);
            a(-2, 4);
            d = 1;
            return;
其中"a.a(c[e] + s, b[1], b[2], b[3], b[4]);"调用了j/c [Ljava/lang/String;具体代码为
getstatic j/c [Ljava/lang/String;意思是取出这段文字!
  这个private void d()方法又被谁调用的?我们再往上,private void d()的标签是"j/d()V".  "j"表示该方法位于JAR包根目录下的j.class."/d"表示它的方法名."()"表示调用该方法时没有东
西传递给它,所以括号里是空的."V"表示该方法返回类型是void,V就是void的缩写.或者点击图3标签前面进入常量池,"ctrl+c"复制标签(需自己添加路径和方法名),再用"ctrl+v"粘贴到搜索栏里!经过搜索发现public final void a(Graphics g1)调用了private void d()方法.如下:
public final void a(Graphics g1)
    {
        f++;
        j++;
        k++;
        g1.setFont(k.a);
        switch(c)
        {
        case 0: // '\0'
            b();
            b(g1);
            break;


        case 2: // '\002'
            c();
            c(g1);
            break;

        case 10: // '\n'
            d();
            d(g1);
            break;

        case 11: // '\013'
            e();
            e(g1);
            break;
        }
        i = 0;
    }
分析后得知:只有变量c = 10,程序才能执行private void d()方法,:
case 10: // '\n'
            d();
            d(g1);
            break;
就是说只有c = 10,程序才会认为短信发送成功!变量c的标签是 j/c I,后面的"I"表示该变量的数据类型.现在我们回到那个的方法private void f(int i1),看看变量c是如何变化的!经过搜索发现方法private void f(int i1)public final void a()调用,public final void a()又被r.classpublic final void run()调用了,run()方法是Thread(线程)类下的,可以使用threadstart方法来调用它.那我们搜索谁调用run()方法时在搜索栏里输入"invokevirtual java/lang/Thread/start()V"经过搜索发现有4个结果,分析后只有j.class下的private void e(int i1)方法调用了r.classpublic final void run().那我们看下private void e(int i1)方法:
private void e(int i1)
    {
        if(i1 == 0)
        {
            c(2);
            Thread thread;
            (thread = new r(this)).start();
            f = 0;
            return;
        }
它在(thread = new r(this)).start()前先调用了c方法(c(2);),并且给c方法传递了一个整数"2",c方法的标签是 j/c(I)V ,就是如下的方法:
private void c(int i1)
    {
        c = i1;
        d = 0;
        j = -1;
        k = -1;
    }
里面的变量c就是我们上面提到的,"c = i1;"就是变量c的值等于给c方法传递的那个整数"2".我们只要把private void e(int i1)方法里的c(2)改为c(10)就完成破解了!可能有人问private void e(int i1)方法和public final void a(Graphics g1)方法没关联啊!你只要继续搜索private void e(int i1)的调用者就发现public final void a(Graphics g1)最终调用了private void e(int i1),我就不一一介绍了!我对这个游戏有些疑问,按我的理解这个游戏哪怕是正常的也无法成功开启服务的啊!难到还有其他机关?想请教下BB,飞鹰,KIM这些高手们,这也是我用这个游戏作例子的目的!因本人水平有限,文中不足之处也请赐教!
  本来还想用雪鲤鱼的几个短信+联网收费游戏做例子,介绍下破解简单联网收费游戏的一些心得,但本文的篇幅已超出预计了,唯有等有空再发上来了,说实话,写教材太难了,打字都打得手痛了!我写这篇文章只是希望朋友们能了解下HALO2的搜索功能.对于破解的思路和方法,各人有各人的方法,目前论坛里发的破解版使用的方法就比我的好.呵呵,当时我破解是为了移植到
我的MOTO C上的,但这游戏的内存要求太高了,我的小C没法运行.dnf安全模式解除bug我就没留意到这个破解版,走了些弯路!