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