最近开始报 WCQ 了,名额也是死难抢,来研究一下怎么开高达。

之前写过一个传动态头像的工具,也顺便总结一下吧。

虽然一开始用的是 Fiddler,不过现在感觉好像被 mitmproxy 完爆了,就不讲 Fiddler 的部分了。

免责声明

本文仅作为个人技术学习与安全研究记录,内容基于本人账号、本人设备及本地测试环境中的调试过程整理,不代表鼓励、支持或指导任何人对第三方平台、服务或系统进行未授权访问、绕过限制、篡改数据、自动化抢占资源、干扰正常运营或破坏比赛公平性的行为。

文中涉及的抓包、代理、请求分析等内容,仅用于理解客户端与服务端交互机制、排查个人使用场景中的技术问题,以及提升安全意识。任何读者在学习相关技术时,均应遵守所在地法律法规、平台服务条款、赛事规则及基本的网络安全伦理。

本人不会提供用于绕过平台规则、批量操作、代抢名额、规避身份校验、影响他人权益或破坏系统正常运行的工具、脚本、接口参数、完整复现步骤或技术支持。若相关平台或权利方认为本文部分内容存在不当之处,可通过站内联系方式联系本人,我将及时核实并进行调整或删除。

本文不构成任何形式的攻击教程、作弊指南或规避平台规则的操作说明。请勿将本文内容用于任何未经授权或违反规则的用途,由此产生的一切法律责任、账号风险及其他后果均由行为人自行承担。

动态头像

抓取通过 mitmproxy 抓取上传头像的请求:

upload

首先这个小程序的大部分非查询类请求都有一个 signature 参数,这个是以秒为单位更新的签名,无法手动计算,所以我们只能通过截取并篡改已经生成的请求实现我们的需求。

观察请求头,请求体格式为 multipart/form-data----WebKitFormBoundary 是分隔符,用来分隔数据,后面一串随机字符串是为了防止分隔符出现在文件内容里。

观察请求体:

1
2
3
Content-Disposition: form-data; name="path"

/game/

这部分表示文件上传到 /game/ 这个目录下;

1
2
Content-Disposition: form-data; name="file"; filename="232132815.png"
Content-Type: image/png

这部分记录了文件名和文件格式。

后面部分为图片数据。

则只需要将图片数据的部分替换为我们准备的其他图片数据,就可以实现替换上传的图片。

注意要同时修改请求头中的 content-length

尽管上传后文件名仍然是原来的 .png 或者 .jpg,但图片解码器一般还是会按照图片的文件头进行解析,依然能正确识别为 GIF 并播放,这样一来就成功了。

GUI 工具化

Pyinstaller 做了一个 GUI 工具方便分发。

当然代码是 AI 写的,不过效果确实不错。

UI

我自己的 mitm 证书也打包进去了,不然用户还得装个 mitm 生成证书。

用户首次启动需要管理员权限,证书会自动安装到本地。

绕过“请使用手机登录端登录”

某一天开始,可能是为了制裁高达代抢巡回赛,小程序不让用电脑登录了。

具体来说,进小程序的时候会弹一个关不掉的弹窗,点确定就会退出小程序。

pc

之前就研究过,手机篡改流量也太麻烦了,着实让我头疼了很久。

不过巧合之中我还是发现了破解的方法:

如果之前在电脑上登录过,再在别的设备上顶号,那么会先弹出“请使用手机登录端登录”,过一会弹出“登录已过期,请重新登录!”。

info2

此时我们点“确认”然后登录,会发现居然能绕过第一个弹窗……

算了,他们程序员大概也就这水平。

那么为了能在任意情况下都能绕过这个弹窗,我们只需要想办法让他以为我被顶号了就行。

我抓住机会分析了一下被顶号的时候的流量,发现被顶号时 response 的内容特征为:

1
2
3
4
{
"code" = 10314,
"msg" = "您已经在别的设配登录了"
}

谁懂还有错别字😂

总之我们只需要随便找个包把 response 改成这个格式,就可以让他认为我被顶号了。

而进入首页固定会请求一次 https://yugiohmatchapi.***.com/v1/news 获取公告,于是成功破解。

感觉做代抢的人技术应该比我强,不过不好说能不能发现这个?

巡回赛报名

说实话写到这的时候还没有一套好的方案,让我们一起拭目以待!

之前也不是没有尝试过,不过最终的结果是账号疑似被 ban 了。。

可能是测试的时候做出太多不合法请求了,这次要多加小心!

总之我们来一步一步破解。

我要报名

首先是这个比赛信息页面:

1

在非报名时间,下方按钮为“待开放”。我们希望能在任何时间都报名,则需要让它以为是可报名时间。

通过抓包可以发现,GET https://yugiohmatchapi.***.com/v1/match/info/87794responsebottom 字段表示下方按钮的状态(也太直接了吧)。

对于“开放中”的比赛,内容为:

1
2
3
4
5
6
7
8
9
10
11
"bottom": {
"type": 1,
"action": 0,
"title": {
"text": "开放中",
"signUpTotal": 0,
"alreadySignedUp": 0,
"countdown": 0,
"isReserve": false
}
}

对于可以报名的比赛,则为:

1
2
3
4
5
6
7
8
9
10
11
"bottom": {
"type": 0,
"action": 0,
"title": {
"text": "",
"signUpTotal": 0,
"alreadySignedUp": 0,
"countdown": 0,
"isReserve": false
}
}

通过修改,我们即可在任意时间点击报名按钮。

1.1

验证码与赛事协议

2

验证码其实没什么好说的,显然是调用的外部接口。

完成验证后,出现下一个窗口:

3

同时产生请求 GET https://yugiohmatchapi.***.com/v1/match/player/check/87916response

1
2
3
4
5
{
"code": 200,
"data": {},
"msg": "选手身份检验成功!"
}

不好说这一步是否有风险。理论上这一步必须是在开放报名的时间,如果不是,可能会触发风控?

以及浏览器标识最好也要换成手机版,应该。

点击“确认”后进入“赛事协议”页面:

4

这一步不会产生任何请求。在这里点击“确认”的话,就是真正发送报名请求了。

请求的格式形如 GET https://yugiohmatchapi.***.com/v1/match/signup/87916?code=,后面跟一大长串不知道干啥的 code

众所周知现在报名之后会弹出来一个排队的界面,不知道到底是在干啥,难道还有后台人工审核?(就积分赛的审核效率,我是不太信)

今天中午其实抓了一次,但我不小心把 mitm 关了,现在没法确认这一步的请求体和返回内容了。但能确定排队过程中没有任何还未返回的请求,过一定时间这个窗口会自动消失。(所以到底在排什么东西)

行动计划

事前准备

脚本启动后,可绕过电脑端检查,可提前点击报名按钮,User-Agent 伪装成手机版微信。

Plan A

提前到达验证码界面,到时间立即完成接下来的步骤。

理论上能比所有手动档玩家快 2 秒,缺点是打不过更凶的高达(如果存在)。

Plan B

直接快进到最后一步,到时间(或过几秒)点击最后的“确认”。

一定比所有人快,也可以刻意晚几秒被识别,但无法避免前一步 check 时间不对。

如果他不检测 check 的话,这个是最好的方案。

5.10 结果

同时执行了两个计划,其中 Plan B 的请求时间为 13:30:04,返回的 code40029

两边都是排队转圈然后没报上。

而整个排队过程中没有新的请求产生,也没有未返回的请求,所以还是那个问题,到底在排什么。。。

感觉有两种可能:

  1. 报名成功和失败都会显示排队,但是实际上对应的 codedata 是不一样的。
    报名成功会在一定时间后发送新的请求,或是根据返回结果直接进入付款页面,而失败就会一直原地转圈,只是故意拖时间这个防止玩家反复尝试报名增加服务器负载。
    如果是这样,就得需要抓一个报名成功的数据。。

  2. 有其他未被捕获的流量,且报名成功与否不完全依赖于报名时间。但我觉得不太可能。

感觉第一种的可能性更大。

我尝试了一下报名积分赛,报名成功返回的内容为:

1
2
3
4
5
6
7
{
"code": 200,
"data": {
"order_id": 0
},
"msg": "报名成功!"
}

我试了一下把 codemsg 进行篡改,我草,还真显示正在排队!

并且在过了一小会之后弹出:

X

并且也确实有一条新的请求:

1
2
3
4
5
6
GET https://yugiohmatchapi.***.com/v1/match/monitor/signup/87916
{
"code": 200,
"data": {},
"msg": "抱歉,当前报名人数已满,无法继续排队,感谢您的理解。"
}

结论

其实中间又试了好几天,过程就不写了,直接写结论吧。

确实是小程序账号被 ban 了。始终返回 40029

但是 Plan A 对于未被 ban 的账号是可行的。

对我而言,可能可以通过护照小号报名来实现高达补录,如果又被 ban 了就注销重新注册一个号(其实已经发生了,还未验证重新注册的号能不能报名)。

将在上海站进行尝试。