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

查看 125|回复 10
作者:6yanfeibiao   
第一次发帖,多多包涵
起因
疫情开放第一年的演出市场彻底疯掉,五月天北京鸟巢完全抢不到,黄牛猖狂加价,恶心羞辱真五迷,气愤无奈情绪无从发泄。
一气之下决定研究一下某麦app接口。
逆向信息
平台:Android
app版本:8.4.5
工具:jadx,frida
思路
其实想法很简单,一共两个方向
[ol]
  • 在app中,等待开票提前进入选择界面或者付款界面,这样可以一定程度上比普通用户快一掉掉
  • 实现程序call api生成订单,这是最终目的
    [/ol]
    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;
            }
            ...
            ...
            ...
            home.php?mod=space&uid=1892347 //
            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一下,去显示购买按钮

    倒计时, 按钮

  • fryant   

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

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

    这确实牛啊
    liuhy   

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

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

    加油,演唱会票靠你了
    ChangHJ   

    看着就很刑呀,比黄牛还刑
    fish820   

    感谢,试试看
    ikun20230721   

    感谢,试一试
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部