Gordon0918 发表于 2016-6-7 15:54

火柴人联盟签名、内购破解全攻略

小白一个,以火柴人联盟破解为例理顺下自己的思路,如果疏漏,请大牛斧正……
1、明确目标
拿到一个apk后,不要着急反编译,先在手机上试玩一下,看哪里是需要内购的以及内购的方式,手机短信验证、支付宝、微信支付等等,心中大概有个谱。以在*豆荚上下载的火柴人联盟为例,查看付费方式(苦逼的很,手机不能截屏,只能用其他手机拍照了。)如下图所示



可以看到支持多种付费方式,有话费支付和三方支付(支付宝、微信、银联,手机充值卡)。
2、验证软件是否有签名并进行破解
把apk扔到android killer中,反编译,不做任何操作,直接编译打包,安装到手机。此时运行程序,有如下提示

可以看到,二次打包后不能运行,说明它有进行签名验证。
在android killer中搜索关键字signatures,结果如下

wandoujia,wow,weibo是三方的sdk,不关心,直接看上述两个文件,发现关键字都是存在一个叫做getAPPSecretString的函数中,直接上java代码,逻辑是获取软件的签名后进行散列运算,然后返回一个字符串,我们此时几乎可以肯定这个东西是用于签名验证的。

我们大概知道了获取签名的位置是其中一个,由于软件一打开就提示是盗版,所以接下来看下主流程。入口是com.DBGame.DiabloLOL.SplashActivity;查看它的oncreate函数,发现它是调用了DiabloLOL的activity,我们主要看DiabloLOL.smali文件,oncreate函数如下
protected void onCreate(Bundle paramBundle)
{
    super.onCreate(paramBundle);
    init();
    Bluetooth.getInstance().init(this);
    this.context = this;
    BLHelper.init(this.aHandler, this);
    MobClickCppHelper.init(this);
    this.wandouGamesApi = CmgameApplication.getWandouGamesApi();
    this.wandouGamesApi.init(this);
    try
    {
      ReYun.initWithKeyAndChannelId(this, "a4d2f6135f92a14d5d86da48f095e823", BLHelper.getEmChannel());
      new AddBlackName(this);
      AddBlackName.Check();
      instance = this;
      paramBundle = ((TelephonyManager)getSystemService("phone")).getSimOperator();
      if (((paramBundle != null) && (paramBundle.trim().equals("46001"))) || (paramBundle.trim().equals("50501")))
      {
      i = 2;
      this.iFromPay = i;
      if (i != 2) {
          EMPayManager.initMerge(this, 1, 2);
      }
      MatchVSHelper.init(this.aHandler, this);
      return;
      }
    }
    catch (Exception paramBundle)
    {
      for (;;)
      {
      int i;
      paramBundle.printStackTrace();
      continue;
      if ((paramBundle != null) && (paramBundle.trim().equals("46003"))) {
          i = 1;
      } else {
          i = 0;
      }
      }
    }
}
看到一个AddBlackName.Check(); 而且addblackName正好是我们上面找到那个两个包括getAPPSecretString类中的一个,感觉棒棒哒,赶紧跟进去,代码很简单,只上关键代码
str3 = ((WifiManager)AddBlackName.mContext.getSystemService("wifi")).getConnectionInfo().getMacAddress();
          str2 = String.format("X-Em-Apk-Certifiction%s", new Object[] { utils.getAPPSecretString(AddBlackName.mContext) });
          AddBlackName.loadData(String.format("http://119.29.20.199/stickman/api/v1/sign/confirmSign?did=%s&appkey=%s&ver=%s&ch=%s&lang=%s&pkgname=%s&mac=%s&sdkver=%s&sign=%s", new Object[] { str1, AddBlackName.sKey, Integer.valueOf(i), AddBlackName.sChannel, AddBlackName.sLanguage, AddBlackName.mContext.getPackageName(), str3, "1.0.0", str2 }));


获取软件签名后调用loadData函数,传进去的还有个网址,大概可以判断是进行网络验证,跟进去看看,流程也很命令,不再贴代码,大概就是构造一个http包,发到服务器,经过服务器验证,返回状态。当返回状态为1103时,认为是校验失败
          if (updateItem.getStatus() == 1103)
          {
            updateItem.setTitle(paramString.getString("authTitle"));
            updateItem.setDescription(paramString.getString("authDesc"));
          }
          PreferUtil.saveIntValue(mContext, "BLACK_ITATUS", updateItem.getStatus());
          PreferUtil.saveStrValue(mContext, "BLACK_STITLE", updateItem.getTitle());
          PreferUtil.saveStrValue(mContext, "BLACK_SMESSAGE", updateItem.getDescription());
          PreferUtil.saveStrValue(mContext, "BLACK_SURL", updateItem.getLink());
          if (updateItem.getStatus() == 1103) {
            mHandler.sendEmptyMessage(1000);
OK,知道大概流程就好办了只需要搜索1103关键字,看哪里进行修改了,修改下if跳转即可。修改方法不再赘述,感兴趣的同学可下载样本比对。修改完成后可正常运行。
3、内购破解
3.1 话费支付破解
软件签名破解完成后,接下来进行内购破解,在不少文章中可到内购破解方式是搜索payCancel、payFailed、onBilling等关键字。试着搜索了,这些关键字都有,但是修改后并没有起作用。后来想了下,这些关键字都是三方sdk中计费成功和失败的标记,而在这个软件中,包含的
三方计费sdk太多了,有移动、联通、三方支付,如下所示

大概看了下其中的逻辑,在common中的EMPayManager类initMerge方法中进行运营商判断,然后根据运营商不同实例化下面的实例,
public static void initMerge(Context paramContext, int paramInt1, int paramInt2)
{
    String str = ((TelephonyManager)paramContext.getSystemService("phone")).getSimOperator();
    if (((str != null) && (str.trim().equals("46001"))) || (str.trim().equals("50501"))) {
      EMUnicomManager.init(paramContext);
    }
    for (;;)
    {
      return;
      if ((str != null) && (str.trim().equals("46003"))) {
      EMEGamePayManager410.init(paramContext);
      } else if (paramInt2 == 0) {
      EMMMBillingManager.getInstance().init(paramContext);
      } else if (paramInt2 == 1) {
      EMMMIntenetManager.getInstance(paramContext).init(paramContext, new OnLoginFinishListener()
      {
          public void onLoginFinish(int paramAnonymousInt) {}
      });
      } else {
      EMSohuPayManager.init((Activity)paramContext);
      }
    }
}

如果修改每个计费sdk的接口会比较麻烦,我们回到主逻辑DiaboLOL,在文件开头定义了一个handler,主要代码有
EMPayManager.payMerge(DiabloLOL.this, DiabloLOL.this.PRO_ID, DiabloLOL.this.PAY_RMB, DiabloLOL.this.PAY_CODE_UNICOM, DiabloLOL.this.PAY_CODE_SMS, DiabloLOL.this.PAY_NAME, DiabloLOL.this.PAY_CODE_MM, 2, 0, null, false, "shit", new OnPayFinishListener()
          {
            public void onPayFinish(int paramAnonymous2Int)
            {
            if (paramAnonymous2Int == 1)
            {
                Log.e("test", "rechager sucess");
                DiabloLOL.this.setPayment();
                BLHelper.purchaseComplete(DiabloLOL.this.PRO_ID_Str, 1);
                BLHelper.closeShieldLayer();
            }
            for (;;)
            {
                return;
                Log.e("test", "rechager failure");
                BLHelper.closeShieldLayer();
                System.out.println("������������");
            }
            }
调用 EMPayManager的payMerge函数,新建监听器作为参数,跟进去payMerge,是根据运营商不同,调用不同计费sdk的pay接口,并把监听器传进去。如果跟进每个计费接口,会发现每个接口最终都会调用监听器的onPayFinish接口,那么
我们只需要修改onPayFinish接口,使参数恒为1即可。
3.2 三方支付破解
上一步骤搞定了话费内购,接下来在主逻辑中发现一个可疑方法 PayThird ,实现了onfailed和onSuccess方法,把onfailed中的内容全部删除,然后把onSuccess中的内容拷贝进去。测试,发现三方支付的内购也成功破解了,如下
public void PayThird(String paramString)
{
    Log.e("lihytest", "orderNum " + paramString);
    long l = this.PAY_RMB;
    this.wandouGamesApi.pay(this, this.PAY_NAME, l, paramString, new OnPayFinishedListener()
    {
      public void onPayFail(PayResult paramAnonymousPayResult)
      {
      Log.e("asd", "onPayFail");
      BLHelper.closeShieldLayer();
      }
      
      public void onPaySuccess(PayResult paramAnonymousPayResult)
      {
      Log.e("asd", "onPaySuccess");
      ReYun.setPayment("unkown", "wdj151", "RMB", DiabloLOL.this.PAY_RMB / 100.0F, 0.0F, DiabloLOL.this.PAY_NAME, 0L, 0);
      BLHelper.purchaseComplete(DiabloLOL.this.PRO_ID_Str, 2);
      BLHelper.closeShieldLayer();
      }
    });
}
打开smali代码,把onPaySucess中的部分拷贝到onPayFailed中即可。
其实。。。这个破解的有点侥幸,具体逻辑现在也没有搞明白,所以有时候运气来了挡都挡不住{:1_918:}
看下成果吧



4 总结
1、对于签名验证,有本地验证和网络验证,可以根据不联网时能不能正常运行来判断
2、对于单一模式的付费方式,最好看一下是使用的是那种计费sdk,然后取开发者网站看下该sdk的重要接口
3、对于多种模式的付费方式,查找调用计费接口的统一入口。

PS:仅供技术交流,请勿传播破解软件






1461244950 发表于 2016-6-7 22:28

其实火柴人联盟和游戏的比较好破解直接手机mt apk搜onResult方法名找到对应数据 把失败改成成功即可

再搜索侵权相关字符串 找到验证代码删除所有代码保留返回代码即可 否则闪退

再进xml里面去除sms短信发送权限 即可 完美内购去验证破解楼主的方法比较详细 多学习学习

qfwfq2015 发表于 2016-6-7 20:24

感谢发布原创作品,吾爱破解论坛因你更精彩!{:301_975:}
很久以前玩过这个游戏当时破解的方案就是 设置软件使用权限 将此程序的联网功能关闭然后就随心所欲的当单机游戏玩了买钻石 金币 英雄都不会扣费了 不知道现在这游戏是不还是这么好破解{:301_987:}

倾听回忆 发表于 2016-6-7 16:01

多谢楼主分享   如果能做个秒杀版再好不过了{:1_918:}

Gordon0918 发表于 2016-6-7 16:09

抱歉,忘记发样本链接了
http://pan.baidu.com/s/1bozuVaZ
xnu5

ghshr521 发表于 2016-6-7 16:19

感谢楼主分享多多学习!

asd9988 发表于 2016-6-7 16:31

预计应该会优秀鼓励,可惜人太少了。加油楼主。

我是小白我自豪 发表于 2016-6-7 19:40

辣么看llalaaalla

moumoe 发表于 2016-6-7 19:54

此时几乎可以肯定这个东西是用于签名验证的。 病句

a5680497 发表于 2016-6-7 20:02

赞一个,楼主威武

16zjs 发表于 2016-6-7 20:04

感谢发布原创作品,吾爱破解论坛因你更精彩!

fz74110 发表于 2016-6-7 20:08

谢谢分享,学习了
页: [1] 2 3 4
查看完整版本: 火柴人联盟签名、内购破解全攻略