6yanfeibiao 发表于 2023-8-7 18:06

某麦演出app分析(一)---倒计时去除

第一次发帖,多多包涵
## 起因
疫情开放第一年的演出市场彻底疯掉,五月天北京鸟巢完全抢不到,黄牛猖狂加价,恶心羞辱真五迷,气愤无奈情绪无从发泄。
一气之下决定研究一下某麦app接口。
## 逆向信息
平台:Android
app版本:8.4.5
工具:jadx,frida
## 思路
其实想法很简单,一共两个方向
1. 在app中,等待开票提前进入选择界面或者付款界面,这样可以一定程度上比普通用户快一掉掉
2. 实现程序call api生成订单,这是最终目的


<!--more-->


## APP源码分析
### 倒计时去除
从界面上看,待开售的页面和立即购买页面是的却别是开售倒计时,从开发估计一定是会通过api获取开售时间,在前端进行倒计时。
!


通过抓包得知获取详情的api是:

```
https://acs.m.taobao.com/gw/mtop.alibaba.damai.detail.getdetail/1.2/
```

返回结构:

```
{
        "api": "mtop.alibaba.damai.detail.getdetail",
        "data": {
                "result": "......"
        },
        "ret": [
                "SUCCESS::调用成功"
        ],
        "v": "1.2"
}
```

其中`data.result`就是演出的detail数据:
!


猜测`sellStartTime`就是开始时间,用`countDown`作倒计时.尝试在APP源码中查找

!


找到一个叫做`ProjectItemDataBean`的类,看一下这个`DataBean`用来做什么
!


继续查找`countDown`的用例!


发现了`ProjectDetailItemMainFragment`,应该是View层了,查看是怎么使用!


从api 返回知道`countdown`返回的值是`591614`, 估计是秒数,所以hook一下测试:

```
let ProjectItemDataBean = Java.use(
"cn.damai.trade.newtradeorder.ui.projectdetail.projectdetailitem.bean.ProjectItemDataBean"
);

ProjectItemDataBean["setCountDown"].implementation = function (j) {
console.log(`ProjectItemDataBean.setCountDown is called: j=${j}`);
if (j > 1) {
    this["setCountDown"](5);
} else {
    this["setCountDown"](0);
}
};
```

直接把`countDown`设成5秒以内,效果是成功的
!


但是即便是倒计时小时了显示立即购买,点击立即购买按钮依然是没办法进入选择价钱页面,为什么呢?

于是我尝试查找倒计时结束之后的逻辑,在View层有一个`TimeCountDownListener`

!


这里是更新了`BuyBtnText`,还更新了` this.mProjectItemStatusHelper.m45526u(this.mProjectItemDataBean);`,所以估计在点击`立即购买`按钮还有其他数据的判断.
!


这是通过阅读代码发现有一个类叫做`ProjectItemStatusHelper.OnBottomViewClickListener`,里面的函数:

```
    public interface OnBottomViewClickListener {
      void onBuyRightNow(int i);

      void onNeedPrivilege(int i);

      void onRegister(int i);

      void onSelectSeat();

      void onSoldOut();

      void onTimingCountDown();
    }


```

在`ProjectDetailitemMainFragment`中的实现是:


```
public class C4295e0 implements ProjectItemStatusHelper.OnBottomViewClickListener {
      private static transient /* synthetic */ IpChange $ipChange;

      C4295e0() {
            ProjectDetailItemMainFragment.this = r1;
      }
                ...
                ...
                ...
      @Override //
      public void onTimingCountDown() {
            IpChange ipChange = $ipChange;
            if (AndroidInstantRuntime.support(ipChange, "-926618722")) {
                ipChange.ipc$dispatch("-926618722", new Object[]{this});
            } else {
                ProjectDetailItemMainFragment.this.processTimeCountDownClick();
            }
      }
    }

```

通过分析`processTimeCountDownClick`可知道:

```
processTimeCountDownClick()->processClickNotRefreshAfterCountDown()->getSubProjectDectailCheckData()
```

最终调用`skuRequest`再次call api获取数据:
!


在`ProjectDetailItemMainFragment.onReturnSkuBeanDataSuccess()`中可以看到,原来点击按钮之后会再次获取`skuBean`,然后判断里面的`itemBuyBtnBean.btnStatus`是否等于106和倒计时是否等于0,最终运行`popupSkuByPerformInfo()`

```
public void onReturnSkuBeanDataSuccess(SkuBean skuBean) {
      long j;
      ...
      ...
      int i = itemBuyBtnBean.btnStatus;
      if (i != 230 && i != 231) {
            this.mSkuBean = skuBean;
      } else {
            this.mSkuBean = null;
      }
      ...
      ...
      if (itemBuyBtnBean.btnStatus == 106) {
            ...
            ...
      }
      updateCountDownVisibility(false, false);
      updateMemberPromptCountDownVisibility(false, false);
      ProjectItemStatusHelper projectItemStatusHelper2 = this.mProjectItemStatusHelper;
      if (projectItemStatusHelper2 != null) {
            projectItemStatusHelper2.m45526u(this.mProjectItemDataBean);
            updatePageUT();
            if (!this.mProjectItemStatusHelper.m45535l()) {
                cancelCountDown();
                displayProjectNotExistPage();
                return;
            }
            this.mPurchaseType = -1;
            popupSkuByPerformInfo();
      }
    }

```

通过其他正常可购买的api返回得知,"立即购买"的`status`是`204`,所以,我们可以通过抓包或者hook修改`skubean`中`itemBuyBtnBean.btnStatus`为`204`.

我是通过Hook修改:

```
C42703["onSuccess"].overload(
"cn.damai.commonbusiness.seatbiz.sku.qilin.bean.SkuBean"
).implementation = function (skubean) {
var result = updateSkuBean(skubean);
this["onSuccess"](result);
};
function updateSkuBean(skubean) {
var json = Java.use("com.alibaba.fastjson.JSON");
var a = JSON.parse(json["toJSONString"](skubean));
a.itemBuyBtn.btnStatus = 204;
var result = json["parseObject"](JSON.stringify(a), skubean.getClass());
return result;
}
```

如果一切正常最后会运行`openSkuActivity()`进入到下一个选购界面
!
然而进入了选择场次票档界面,底部的按钮依然是"提交开售提醒",不是立即购买.
## 后续
这里继续看下有无办法Hook一下,去显示购买按钮

<!--MyCopyright-->

: https://www.lqcoding.com/usr/uploads/2023/07/3834209357.png
: https://www.lqcoding.com/usr/uploads/2023/07/3834209357.png
: https://www.lqcoding.com/usr/uploads/2023/07/4036187215.png
: https://www.lqcoding.com/usr/uploads/2023/07/761677531.png
: https://www.lqcoding.com/usr/uploads/2023/07/2803475015.png
: https://www.lqcoding.com/usr/uploads/2023/07/2129693879.png
: https://www.lqcoding.com/usr/uploads/2023/07/73720788.gif
: https://www.lqcoding.com/usr/uploads/2023/07/3641927101.png
: https://www.lqcoding.com/usr/uploads/2023/07/2026437160.png
: https://www.lqcoding.com/usr/uploads/2023/07/3999693623.png
: https://www.lqcoding.com/usr/uploads/2023/07/3219827417.gif

白水饮 发表于 2023-8-8 14:54

提示下,将renderingType的值由2改为1即可

fryant 发表于 2023-8-8 23:28

其实你搞这么多不如直接用直达二维码

liuhy 发表于 2023-8-8 13:02

这确实牛啊

liuhy 发表于 2023-8-8 13:05

进入提交订单页面,不是可以直接使用bp链接吗

restartxie 发表于 2023-8-8 13:13

这个有办法破除黑号机制吗

huangnzd 发表于 2023-8-8 14:21

加油,演唱会票靠你了

ChangHJ 发表于 2023-8-8 14:50

看着就很刑呀,比黄牛还刑:lol

ikun20230721 发表于 2023-8-8 15:57

感谢,试一试

lv3389 发表于 2023-8-8 16:15

怎么样,成功了吗

qinshuaizhi 发表于 2023-8-8 16:20

很刑,的确很刑,哈哈
页: [1] 2 3 4 5
查看完整版本: 某麦演出app分析(一)---倒计时去除