您现在的位置是:网站首页>文章详情文章详情

安卓app动态调试,内购破解滑雪大冒险

inlike2019-09-09 原创文章 浏览(1535) 评论(0) 喜欢(29)

简介内购的游戏是小米版的滑雪大冒险,比价有意思的小游戏;通过对滑雪大冒险小游戏综合运用apk逆向、java代码分析、smali分析、动态调试等基础方法。 内购破解之前的游戏,地图和道具都需要付费:

内购的游戏是小米版的滑雪大冒险,比价有意思的小游戏;通过对滑雪大冒险小游戏综合运用apk逆向、java代码分析、smali分析、动态调试等基础方法。

内购破解之前的游戏,地图和道具都需要付费:

image.png


image.png

首先还是需要使用Androidkiller对apk进行反编译,同时使用JEB获取java源码,但是在本次案例中JEB并不能反编译该apk,原因是内存太小。

因此查看该app对应的源码使用Androidkiller继承的GD-GUI软件,andkiller反编译后如图:

image.png


但是该如何下手?如何找到支付相关的模块,有几种思路:观察自带的日志信息、命令行打印出操作界面对应的页面信息,如图:

image.png

这里首先去看看日志,在点击支付的时候同时观察日志信息,还是会发现一些有价值的信息:

image.png

发现其中疑似支付相关的是:Yodo1PayHelper, startPay call ...,那我们可以查找关键词Yodo1PayHelperstartPay ,在查找之后还真有相关的类和方法:

.method public pay(Landroid/app/Activity;Ljava/util/List;Ljava/lang/String;DLjava/lang/String;Z)V
    .locals 30
    .param p1, "activity"    # Landroid/app/Activity;
    .param p3, "productId"    # Ljava/lang/String;
    .param p4, "discount"    # D
    .param p6, "extraParam"    # Ljava/lang/String;
    .param p7, "isCheckAccount"    # Z
    .annotation system Ldalvik/annotation/Signature;
        value = {
            "(",
            "Landroid/app/Activity;",
            "Ljava/util/List",
            "<",
            "Lcom/yodo1/android/sdk/constants/PayType;",
            ">;",
            "Ljava/lang/String;",
            "D",
            "Ljava/lang/String;",
            "Z)V"
        }
    .end annotation

    .prologue
    .line 116
    .local p2, "payTypes":Ljava/util/List;, "Ljava/util/List<Lcom/yodo1/android/sdk/constants/PayType;>;"
    const-string/jumbo v4, "Yodo1PayHelper, startPay call ..."

    invoke-static {v4}, Lcom/yodo1/sdk/kit/YLog;->i(Ljava/lang/String;)V

    .line 117
    new-instance v4, Ljava/lang/StringBuilder;

    invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V

    const-string/jumbo v5, "Yodo1PayHelper, startPay \u6298\u6263\u6bd4\u4f8b \uff1a "

一个带有支付字样的关键词方法pay,那这就是和支付相关的,然后再看这个方法对应的java源码,以便查找相关的逻辑:

private void pay(final Activity paramActivity, final String paramString1, final PayAdapterBase paramPayAdapterBase, final ProductData paramProductData, final String paramString2, final PayType paramPayType)
  {
    YLog.i("Yodo1PayHelper, pay call ...");
    if ((paramPayType == PayType.channel) && (paramPayAdapterBase.needLogin(paramActivity)) && (!Yodo1UserCenter.isLogin()))
    {
      YLog.i("Yodo1PayHelper, 支付之前必须先登录, 正在自动唤起登录方法");
      callLoginFunction(paramActivity, paramString1, new Yodo1ResultCallback()
      {
        public void onResult(Yodo1ResultCallback.ResultCode paramAnonymousResultCode, String paramAnonymousString)
        {
          YLog.i("Yodo1PayHelper, pay callback, resultCode = " + paramAnonymousResultCode + ", msg = " + paramAnonymousString);
          if (paramAnonymousResultCode == Yodo1ResultCallback.ResultCode.Success)
          {
            Yodo1UserCenter.getUser().setIsLogin(true);
            Yodo1PayHelper.this.pay(paramActivity, paramString1, paramPayAdapterBase, paramProductData, paramString2, paramPayType);
            return;
          }
          Yodo1PayHelper.this.purchased(205"", paramProductData, paramPayType);
        }
      });
      return;
    }
    final ChannelPayInfo localChannelPayInfo = toChannelPayInfo(createOrderId(paramActivity, paramPayAdapterBase), paramProductData, paramString2);
    final User localUser = Yodo1UserCenter.getUser();
    final Element localElement = Yodo1ProductFactory.getInstance().getProductElement(paramProductData.getProductId());
    localChannelPayInfo.setChannelFid(localElement.getAttribute("fid" + paramString1));
    String str = paramPayAdapterBase.createOrderExtra(localChannelPayInfo, localUser);
    YLog.d("Yodo1PayHelper, pay, createOrderExtra = " + str);
    showLoading(paramActivity);
    this.pay_time = 0L;
    placeOrderByOps(paramActivity, paramPayAdapterBase, paramString1, localChannelPayInfo, str, paramPayType, new Yodo1OpsCallback()
    {
      public void onResult(Yodo1OpsCallback.ResultCode paramAnonymousResultCode, String paramAnonymousString)
      {
        YLog.d("Yodo1PayHelper, pay createOrder callback, resultCode = " + paramAnonymousResultCode + ", msg = " + paramAnonymousString);
        if (System.currentTimeMillis() - Yodo1PayHelper.this.pay_time < 60000L)
        {
          YLog.e("Yodo1PayHelper,  " + paramString1 + "支付回调两次 ");
          return;
        }
        Yodo1PayHelper.this.pay_time = System.currentTimeMillis();
        Yodo1PayHelper.this.hideLoading(paramActivity);
        boolean bool = paramPayAdapterBase.createOrderByOpsCallback(paramAnonymousResultCode.value(), paramAnonymousString, paramActivity, localChannelPayInfo, localElement, paramString2, localUser);
        if (paramAnonymousResultCode == Yodo1OpsCallback.ResultCode.Success)
        {
          localChannelPayInfo.setResponse(paramAnonymousString);
          paramActivity.runOnUiThread(new Runnable()
          {
            public void run()
            {
              final String str = Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId();
              Yodo1PayHelper.6.this.val$productData.setOrderId(str);
              Yodo1PayHelper.6.this.val$productData.setPaytime(System.currentTimeMillis());
              Yodo1PayHelper.this.saveProductDatatoLocal(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$channelPayInfo);
              Yodo1PayHelper.6.this.val$payAdapter.pay(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$channelPayInfo, Yodo1PayHelper.6.this.val$payElement, Yodo1PayHelper.6.this.val$extraParam, Yodo1PayHelper.6.this.val$channelUser, new ChannelSDKCallback()
              {
                public void onResult(int paramAnonymous3Int1, int paramAnonymous3Int2, String paramAnonymous3String)
                {
                  YLog.i("Yodo1PayHelper, pay channelpay callback, status = " + paramAnonymous3Int1 + ", errorCode = " + paramAnonymous3Int2 + ", params = " + paramAnonymous3String);
                  Yodo1ResultCallback.ResultCode localResultCode = Yodo1ResultCallback.ResultCode.Failed;
                  if (RegexUtils.isJson(paramAnonymous3String)) {
                    Yodo1PayHelper.6.this.val$productData.setExtras(paramAnonymous3String);
                  }
                  switch (paramAnonymous3Int1)
                  {
                  default
                    Yodo1PayHelper.this.removeProductDatatoLocal(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$productData);
                    if (paramAnonymous3Int2 == 301)
                    {
                      Yodo1PayHelper.this.startPay(Yodo1PayHelper.6.this.val$activity, PayType.carriers, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$extraParam);
                      return;
                    }
                    break;
                  case 1
                    YLog.i("Yodo1PayHelper, 正在查询订单状态");
                    Yodo1PayHelper.this.showLoading(Yodo1PayHelper.6.this.val$activity);
                    if (Yodo1PayHelper.6.this.val$payAdapter.needQueryOrder(Yodo1PayHelper.6.this.val$activity))
                    {
                      Yodo1PayHelper.this.queryOrderByOps(Yodo1PayHelper.6.this.val$activity, str, new Yodo1OpsCallback()
                      {
                        public void onResult(Yodo1OpsCallback.ResultCode paramAnonymous4ResultCode, String paramAnonymous4String)
                        {
                          YLog.d("Yodo1PayHelper, pay queryOrder, resultCode = " + paramAnonymous4ResultCode + ", msg = " + paramAnonymous4String);
                          Yodo1PayHelper.this.hideLoading(Yodo1PayHelper.6.this.val$activity);
                          if (Yodo1PayHelper.6.this.val$payAdapter.queryOrderByOpsCallback(paramAnonymous4ResultCode.value(), paramAnonymous4String, Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$channelPayInfo, Yodo1PayHelper.6.this.val$payElement, Yodo1PayHelper.6.this.val$extraParam, Yodo1PayHelper.6.this.val$channelUser)) {
                            return;
                          }
                          if (paramAnonymous4ResultCode == Yodo1OpsCallback.ResultCode.Success)
                          {
                            Yodo1PayHelper.this.purchased(1, Yodo1PayHelper.6.1.1.this.val$orderId, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                            Yodo1PayHelper.this.removeProductDatatoLocal(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$productData);
                            return;
                          }
                          if (paramAnonymous4ResultCode == Yodo1OpsCallback.ResultCode.Payment_Omissive)
                          {
                            Yodo1PayHelper.this.purchased(203, Yodo1PayHelper.6.1.1.this.val$orderId, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                            return;
                          }
                          Yodo1PayHelper.this.purchased(0, Yodo1PayHelper.6.1.1.this.val$orderId, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                        }
                      });
                      return;
                    }
                    if (Yodo1PayHelper.6.this.val$payAdapter.needVerifyOrder(Yodo1PayHelper.6.this.val$activity))
                    {
                      YLog.i("Yodo1PayHelper, 订单状态校验成功");
                      Yodo1PayHelper.this.hideLoading(Yodo1PayHelper.6.this.val$activity);
                      Yodo1PayHelper.this.purchased(1, str, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                      Yodo1PayHelper.this.removeProductDatatoLocal(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$productData);
                      return;
                    }
                    YLog.i("Yodo1PayHelper, 正在提交订单状态");
                    Yodo1PayHelper.this.submitOrderByOps(Yodo1PayHelper.6.this.val$activity, str, Yodo1PayHelper.6.this.val$payType, new Yodo1OpsCallback()
                    {
                      public void onResult(Yodo1OpsCallback.ResultCode paramAnonymous4ResultCode, String paramAnonymous4String)
                      {
                        YLog.d("Yodo1PayHelper, pay submitOrder, resultCode = " + paramAnonymous4ResultCode + ", msg = " + paramAnonymous4String);
                        Yodo1PayHelper.this.hideLoading(Yodo1PayHelper.6.this.val$activity);
                        if (Yodo1PayHelper.6.this.val$payAdapter.queryOrderByOpsCallback(paramAnonymous4ResultCode.value(), paramAnonymous4String, Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$channelPayInfo, Yodo1PayHelper.6.this.val$payElement, Yodo1PayHelper.6.this.val$extraParam, Yodo1PayHelper.6.this.val$channelUser)) {
                          return;
                        }
                        if (paramAnonymous4ResultCode == Yodo1OpsCallback.ResultCode.Success)
                        {
                          Yodo1PayHelper.this.purchased(1, Yodo1PayHelper.6.1.1.this.val$orderId, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                          Yodo1PayHelper.this.removeProductDatatoLocal(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$productData);
                          return;
                        }
                        if (paramAnonymous4ResultCode == Yodo1OpsCallback.ResultCode.Payment_Omissive)
                        {
                          Yodo1PayHelper.this.purchased(203, Yodo1PayHelper.6.1.1.this.val$orderId, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                          return;
                        }
                        Yodo1PayHelper.this.purchased(0, Yodo1PayHelper.6.1.1.this.val$orderId, Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                      }
                    });
                    return;
                  case 2
                    Yodo1PayHelper.this.removeProductDatatoLocal(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$productData);
                    if (paramAnonymous3Int2 == 208)
                    {
                      YLog.i("Yodo1PayHelper,  这是已购买的商品,购买成功");
                      Yodo1PayHelper.this.purchased(1, Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId(), Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                      return;
                    }
                    Yodo1PayHelper.this.purchased(2, Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId(), Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                    return;
                  }
                  switch (paramAnonymous3Int2)
                  {
                  }
                  while (paramAnonymous3Int2 == 208)
                  {
                    YLog.i("Yodo1PayHelper,  这是已购买的商品,购买成功");
                    Yodo1PayHelper.this.purchased(1, Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId(), Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                    return;
                    paramAnonymous3Int2 = 205;
                    continue;
                    paramAnonymous3Int2 = 3;
                  }
                  Yodo1PayHelper.this.purchased(paramAnonymous3Int2, Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId(), Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                }
              });
            }
          });
          return;
        }
        if (bool)
        {
          YLog.w("Yodo1PayHelper, createOder, error msg = " + paramAnonymousString);
          localChannelPayInfo.setResponse(paramAnonymousString);
          paramActivity.runOnUiThread(new Runnable()
          {
            public void run()
            {
              Yodo1PayHelper.6.this.val$payAdapter.pay(Yodo1PayHelper.6.this.val$activity, Yodo1PayHelper.6.this.val$channelPayInfo, Yodo1PayHelper.6.this.val$payElement, Yodo1PayHelper.6.this.val$extraParam, Yodo1PayHelper.6.this.val$channelUser, new ChannelSDKCallback()
              {
                public void onResult(int paramAnonymous3Int1, int paramAnonymous3Int2, String paramAnonymous3String)
                {
                  YLog.i("Yodo1PayHelper, pay channelpay callback, status = " + paramAnonymous3Int1 + ", errorCode = " + paramAnonymous3Int2 + ", params = " + paramAnonymous3String);
                  Yodo1PayHelper.this.purchased(paramAnonymous3Int2, Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId(), Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                }
              });
            }
          });
          return;
        }
        Yodo1PayHelper.this.purchased(206, localChannelPayInfo.getOrderId(), paramProductData, paramPayType);
      }
    });
  }

这段代码很长,逻辑又相对混乱直接看java源码分析逻辑是比较困难的,那就只有先看看代码中的一些提示信息,比如:这是已购买的商品,购买成功。

  if (paramAnonymous3Int2 == 208)
                    {
                      YLog.i("Yodo1PayHelper,  这是已购买的商品,购买成功");
                      Yodo1PayHelper.this.purchased(1, Yodo1PayHelper.6.this.val$channelPayInfo.getOrderId(), Yodo1PayHelper.6.this.val$productData, Yodo1PayHelper.6.this.val$payType);
                      return;
                    }

这里有很明显的逻辑逻辑判断,但是我们依旧无法知道这部分是佛在支付成功的前提下执行,或者不管支付成功或失败都会效验一下。

这种情况下要么修改smali代码然后打包运行一下,要么就动态调试一下设置一个断点,看该处逻辑是否被执行。

在Androidstudio中导入反编译后的项目目录,然后设置好断点;接着在smali源码的AndroidManifest.xml文件中,application标签下设置android:debuggable="true",然后打包安装。

安装后在adb命令下设置转发:

adb forward tcp:8700 jdwp:pid

pid是对应的apk进程号,通过下面命令获得:

adb shell "ps -ef | grep packagename"

接下来就是在Androidstudio中设置远程调试端口:

image.png

然后点击运行apk,在点击debug,可以看见当我们取消支付后会停在我们设置的断点处:

image.png

以及一些堆栈信息都可以找到,可以分析出是经过了之前的逻辑代码,并且在支付不成功的情况下是跳过了的,我们只需要找到对应smali逻辑修改一下即可,最后效果如图:

image.png

在支付界面点击返回即可,购买成功!
安卓逆向更像是一场瞎猫碰上死耗子的奇遇。


很赞哦! ( 29)
    《Python实战进阶》
    None
    None
    夏至已深

站点信息

  • 建站时间:2019-5-24
  • 网站程序:like in love
  • 主题模板《今夕何夕》
  • 文章统计:104条
  • 文章评论:***条
  • 微信公众号:扫描二维码,关注我们
  • 个人微信公众号