搞笑体育 之 跑步是不可能跑步的

众所周知,高校体育就是一坨…

且不说功能如何,

你一个给大学生用的“运动”软件,

开屏一大堆广告,手机动一下就乱跳app,

跑个步还不忘给我打广告,从头打到尾,真牛…

傻*软件,吃像太难看!

跑个步还要打卡点位,真的恶心,但是,跑步是肯定不会跑的啦~

流程分析

对 APP 的网络请求进行一番抓包,整个流程比较简单:

  1. 手机点击开始体育锻炼跑,APP 发送一个请求
  2. 服务器返回当前跑步的 RunPageID 和需要经过的点位信息
  3. 开跑,记得要满足跑步要求(2公里 + 3个点)
  4. 完成跑步之后,将途径的一个个采样点进行处理,一并发给服务器,完成跑步记录上报保存。

一些细节

  • 所有请求均以 POST 方式发送
  • 所有请求的 body 中的均含有 sign 用于校验,使用的是 MD5 生成哈希值

数据结构

在每一个请求的 body 中的数据结构长这样:data=[JSON Data]&sign=[MD5 Hash]

开始跑步

URL: https://www.sportcampus.cn/api/run/runPage

1
2
3
4
5
[
"initLocation" : "121.00000,30.00000”, // 起始位置的经纬度
"type" : "1", // 不知道什么含义
"userid" : "1234567" // 当前用户的 ID
]

服务器返回的 JSON 中,ibeacongpsinfo分别对应 必经点🔴 和 途径点🟢

ibeacon 中关键信息是 major、minor和uuid,后续保存跑步记录是会用到。

gpsinfo 就是简单的字典,包含 latitudelongitude

结束跑步

URL:https://www.sportcampus.cn/api/run/saveRunV2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[
"endTime" : "2023-3-13 14:50:39",
"startTime" : "2023-3-13 14:38:15",
"userid" : "1234567",
"goal" : "2.00",
"type" : 1,
"frombp" : 0,
"runPageId" : pageID,
"buPin" : "100",
"speed" : "6'13\"",
"real" : "300", // 距离,单位(米)
"duration" : "658", // 时常,单位(秒)
"track" : [], // 跑步过程中 GPS 采样点
"bNode" : bNode, // 必经点数据🔴
"tNode" : tNode, // 途径点数据🟢
"totalNum" : "1024", // 步数
"trend" : [["x" : "0", "y" : "0"]]
]

这里只要给速度生成一个随机数,其他基本都能算出来。

途径点、必经点打卡实际上就是 bNode 和 tNode,把“想经过的”点给进去就好啦。

bNode 是一个字典数组,字典的结构如下:

1
2
3
4
5
[
"major" : String,
"minor" : String,
"uuid" : UUID
]

tNode 相对简单,也是一个字典数组,结构如下:

1
2
3
4
[
"longitude" : String,
"latitude" : String
]

track 是间隔一段时间的 GPS 采样点,也是字典数组,结构如下:

1
2
3
4
5
[
"speed" : String, // 应该是记录采样时的速度,具体单位不清楚,一般跑步在 2.0 - 3.0 左右
"longitude" : String,
"latitude" : String
]

Sign 的获取

在 GitHub 上找到了 Python 的版本,直接拿到了 key,

借助 ChatBot 得到了 Swift 版本的 MD5 哈希生成函数,

把 data 构建好之后,转为 String 传进去就好啦。

1
2
3
4
5
6
7
8
9
10
11
import CryptoKit
import Foundation

func getMD5Code(_ s: String) -> String {
let key = "lpKK*TJE8WaIg%93O0pfn0#xS0i3xE$z"
let message = key + "data" + s
let data = Data(message.utf8)
var hasher = Insecure.MD5()
hasher.update(data: data)
return hasher.finalize().map { String(format: "%02hhx", $0) }.joined()
}

如何规划路径

答:得到必经点和途径点后,手动规划。

用 SwiftUI + MapKit 做了一个 UI,在地图上标注出关键点,

接下来就是鼠标点点点!

相邻的两个点中间会补齐来实现 “GPS 间隔采样”,

当然,跑步一定不会是笔笔直的,也适当的对每一个中间点做了横纵向的随机偏移。

仍需注意的是:在过河以及转弯时要小心一些😂

跑步流程

  1. 点击跑步按钮
  2. 规划路线
  3. 点击结束跑步
  4. 等待提交…

舒服!耶!跑步是不可能跑步的啦~

项目不开源,涉及多方利益与合作,仅在我自己电脑上运行使用。

搞笑体育 之 跑步是不可能跑步的

https://liyanan2004.github.io/hack-college-sport/

作者

LiYanan

发布于

2023-03-13

更新于

2023-03-13

许可协议

评论