### 简介：

这是(3.4.8)云运动代跑脚本，可以进行云运动全自动代跑。

**比下面提示更重要的提示**：

1. 作者大三了，没有跑步任务，完全失去的对脚本debug的能力，只能处理通信问题。但是我还是会尝试继续维护一段时间，不过问题信息收集依赖各位通过issue提供。

2. [issue](https://github.com/Zirconium233/yunForNewVersion/issues/70) 确定错误原因是踩点要求改成3个了，之前是2个，地图录入时候大多数都是按2个的，所以错误。

      - 解决方法1：自己跑几个通过的，然后history.py抓下来直接用就行。
      - 解决方法2：编辑tasklist的json文件，把关键点ManageList都改成Y，把踩点数从2都改成5。
      - (不用担心轨迹不过关键点，服务器不会去验证你到底踩没踩点，你说什么服务器信什么)
 



**重要提示**：云运动时隔1年，3.4.7 终于对加密方式下手了，新的加密逻辑和解决方案可以在 [issue#48](https://github.com/Zirconium233/yunForNewVerison/issues/48) 找到。

1. **现在我们对cipherKey只有加密能力，没有解密能力，只能使用自己提供的固定的Key和服务器通信**。这个问题理论上无法解决，因为云运动工程师拍脑袋发现，非对称加密中客户端只用负责加密就行了，不需要解密能力。所以`libcrs-sdk.so`没有提供正确的PrivateKey。这个问题无解，除非你能手撕非对称加密(能做到这个你就无敌了)。

2. **以后怎么抓包**：

   - **如何获取历史记录**：`python history.py`，api细节可以参考 [这个](./history.md)

   - **如何获取api接口**：这个抓包也是可以的，软件不可能加密访问的URL。参数的填写参考封包内容

3. **TODO**

   - 提供自动随机sm4Key通讯功能
   
   - 封装抓历史记录功能(Done)

4. 常见问题：[常见问题](./questions.md)





### 更新记录：

- 2025/3/16:
   1. 封装抓历史记录功能。


- 2025/2/25:
   1. 修复3.4.7版本公钥密钥变换问题，脚本基本功能已经恢复。


- 2024/12/3: 
   1. 合并xiaocheng4097代码，提供登录功能支持，可以不抓包直接登录。

   2. 增加自动版本检查，现在会自动检查`config.ini`里面的`app_edition`版本信息，如果小于3.4.5会自动更新最低可运行版本3.4.5，高版本不会更改(截至12/3日，最新版本为3.4.5)。过低的版本会导致服务返回错误信息，详见[issue#35](https://github.com/Zirconium233/yunForNewVersion/issues/35)。

- 2024/10/28:
   1. 合并laizhangtu代码，现在代理工具可以批量抓取config了。

- 2024/10/18:
   1. 修改并合并xiaochen4097代码，提供随机偏移添加功能(路线改变效果并不明显，所以也不会鬼畜)。

   2. 有人测试发现ios版本也可以直接抓包token和deviceId，uuid使用当前代码，虽然很逆天但是真的过了。(还是不建议使用iOS登录信息跑本脚本)

- 2024/10/12: 
   1. 合并ANormalDD代码，提供屯溪路校区地图和自动抓包(配置教程见proxy.md)支持。

   2. 允许传递参数执行`main.py`，提供`./tools/EasyAutoRunServer/run.sh`批量并行运行多个config的任务，配合crontab即可定时批量运行跑步任务(挂一个云服务器上就可以全自动)。

- 2024/9/21：其实我什么都没干，然后它自己又能过了，实锤了是学校服务器问题。

   <img src="./image/pass.png" alt="image" style="zoom:50%;" />

   注意事项：
   1. 新版本**无需填写config里面的utc和sign参数**(留空就行，直接把那2行删了会报错)，脚本会自动生成utc，然后和uuid计算得到sign。详见 [issue#1](https://github.com/Zirconium233/yunForNewVerison/issues/1)
   2. finish包500的问题自己好了，不知道是学校服务器是草台班子还是采用即时生成utc方法解决的。现在finish返回的是code 200。


- 2024/9/10：给points添加了时间戳数据，目前已经通过splitPointCheating接口测试，finish包还没过测试(神tm要求大二在2月到7月跑步，穿越时空是吧，看上去学校忘记调时间了)

- 2024/5/3：更新随机提速脚本，用python复现了[Ma-minghao/Yunyundong (github.com)](https://github.com/Ma-minghao/Yunyundong)，因为原作者说python不熟...

   <img src="./image/paceChanger.png" alt="image" style="zoom:50%;" />

- ~~2024/5/2：更新了一个小工具，用java实现了端到端的解密，[Source code](https://github.com/Zirconium233/JavaSmDecryptToy)，各位再也不用麻烦费事的找在线解密网页了。~~（3.4.7失效，私钥不对，当然如果有人能拿到正确的私钥还是能用的）

   <img src="./image/javaTool.png" alt="image" style="zoom:50%;" />

   

- 2024/4/3：更新多图随机打表模式，现在可以随机选择多套图中的一套来跑步了，同时也更新了定时系统，现在可以直接输入时间，自动随机选图打表。

- 2024/3/31：更新main.py，现在打表模式再也不需要高德地图key了。顺便给了一个计数器工具，帮助各位自动7:30晨跑(但是你还是要支付电脑放一夜的电费)

- 2024/3/14：添加打表模式，修复路径问题。(可惜finish返回500的问题还是没解决，不过不影响用，就是看着难受)

   <img src="./image/goodMap.jpg" alt="image" style="zoom:50%;" />



### 使用方法：

**概览：**

1. `pip install -r requirements.txt`
2. 配置`config.ini`文件(自己抓包或者详见(proxy.md)，只填uuid, token, device_id, device_name 4个就行)
3. `python history.py` 拿历史记录(有预置的可以直接跑，外校区需要配置)
4. `pyhton main.py`(可以附带参数)
5. 按照提示操作即可

**细节：**

1. 
   - headers: 3.0.0新版本补充了utc，uuid，sign等参数(*3.3.1只需要uuid了，utc和sign可以自动生成，不建议写死*)，同token和deviceId一样需要获取，建议抓包获取，登录功能未经过测试，不保证功能。
   
   - 快速模式：无需等待直接通过，不过没有轨迹，但是程序算你过(不是实在没时间别用，被人工干了别找我.jpg)
   
2. 配置`config.ini`的具体事项：
   - 必填: token,device_name,device_id,uuid，抓包获得，不建议更改。token决定了你可以访问你的账户，device_name和id是检测多机的，uuid和一个固定的随机数一样，应该也是检测多机的。
   - `utc`, `sign`，`utc`是时间生成的随机数，`sign`是`utc`和`uuid`2者的md5值，具体怎么算的看代码就行了，服务器只会验证`sign`是不是前二者的md5，所以可以一套用到死，3.3.1以后脚本会自动生成这些参数，这2个不用填了。
   - 可选：填写map_key，现在，打表模式再也不需要map_key了。
   - 备注：只需要填写user部分就行，其他地方我已经设置默认值，如果你不知道那是什么，请不要更改。
3. 关于`config.ini` 与 `tasklist.json`，可以使用`proxy.py` 快速配置。详细教程请参考[说明](./proxy.md)

**打表模式：**

- **简介：**

1. 使用`task`文件夹的json文件控制轨迹，json文件来源是历史记录的抓包。
2. 合工大翡翠湖和屯溪路校区有默认提供的表格，无需配置表格即可直接使用。


~~更新--java解密小工具，专门用于解包：**(Dead，别看了，现在没有人可以解密)~~

~~- 简介：如果你有java，双击打开`./tools/decrypt_java.jar`就行了*(jdk-17.0.9)*。(后续更新提供了命令行版本)~~

**其他校区或者学校要额外配置：**

1. 确保你config里面的school_host改对了
2. 使用`history.py`获取跑步数据
3. 打表

6. **效果展示: **

  - 肉眼无法分辨真假的轨迹：

    <img src="./image/goodMap.jpg" alt="image" style="zoom:50%;" />

  - 进度条显示(只支持打表模式)

    <img src="./image/processBar.png" alt="image" style="zoom:50%;" />


**补充抓包教学：**

**新版本可以考虑直接使用ADNormalDD提供的`proxy.py`，教程见`./proxy.md`**

发现很多老哥卡在抓包上了，其实这个云运动是学校架设服务端，还用的http，所以基本上随便抓包，不用什么群里说的fiddler远程、CA证书、ss代理等，甚至还有群友kali都整上了...

其实没这么复杂，我这里介绍一个最简单的方法，**不用root，有一部手机就可以**：

1. Google Play上随便搜一个抓包软件(搞不定Google？你都能上github还搞不定Google？【笑)

   <img src="./image/googleplay.jpg" alt="image" style="zoom:50%;" />

2. 安装它，配置VPN给它过(演示用的群友给的`PCAPdroid`，你用哪个都差不多)

   <img src="./image/VPN.jpg" alt="image" style="zoom:50%;" />

3. 进云运动，随便翻一翻

4. 如果是对于合工大的，找到`ip`是`210.xxx.xxx.xxx:8080`的包就行

   <img src="./image/package.png" alt="image" style="zoom:50%;" />

5. copy里面headers的一切，照着填上去就行了

   <img src="./image/header.jpg" alt="image" style="zoom:50%;" />

6. 还有老哥问sys_edit这个参数，这个是安卓大版本，随便填一个就行，我一般填12，当然我手机是安卓13，服务器不会检查这个

**3.0.0导航模式的残留代码(新版本不推荐使用这种方式，很久没维护了)：**

1. `map.json`的点，你自己post一下getHomeInfo那个，对着地图选几个好看的点填上去就行。我把原作者的随机选点方法弃用改成了手动选点的方法，因为学校很贴心的把位置限定在了一个操场，选的点太乱会导致轨迹魔怔(虽然现在轨迹也很魔怔，不过起码不会抽搐了)

   **补充：**issue里面有老哥提到了轨迹问题，我详细介绍一下`map.json`的作用：

    	1. 这个`map.json`记录的是跑步的控制点，控制着给高德导航目的地的顺序，导航会从里面的上一个点走向下一个点。
    	2. config.ini里面有一个参数是初始点，这是导航最开始的点，别只改map忘记改这个了。
    	3. getHomeInfo的点是关键点，就是你跑步要踩点的几个点。
    	4. 把getHomeInfo的点copy过来相当于作者原本的导航直冲关键点方法，好处是方便，缺点是可能路径直来直去会魔怔。
    	5. 你可以自己对着地图选优质的点，按顺序填入，从而准确的控制脚本走的路径。
    	6. 当点距离足够近的时候还是推荐用导航，因为导航会返回距离，当然如果你有用经纬度精确计算里程的把握，你可以设计算法手动跑，这样就不需要高德的map_key了。
    	7. 经过测试，服务器的关键点也是以你给的点为准，你说什么点是关键点，有没有踩点，服务器就信什么。

   **代码实现细节：**

   普通模式，脚本默认会把`map.json`里面的点当成控制点上传给服务器(回跑的时候不会重复上传关键点)。这是一个偷懒的方式，如果你直接用getHomeInfo的点就不会有问题，当然如果你微操每一个点，打上100个，可能出现一次跑步100个关键点的逆天情况，这时候你可以改代码，比如每20个点add_task后才给manageList.append()一次关键点。*(你可以自己实现，我反正现在都是打表了)*

3. 如果是其他学校要改主机，这个很简单，替换一下就行，当然接口如果用的不一样那没办法，自己抓包研究吧(无慈悲)。

### 相关REPO：

之前的工作：感谢yun大佬的初代脚本[kontori/yun: 云运动一键跑步脚本，理论上适用于一切使用云运动的学校的健跑任务，包括但不限于合肥工业大学 (github.com)](https://github.com/kontori/yun)，为整个脚本提供逻辑框架，可惜作者停更了。

远古的最新消息：仓库公开前已经有人完成了相关工作，[StarYuhen/Yun: 云运动，协议一键刷路程脚本 (github.com)](https://github.com/StarYuhen/Yun)，不过用的接口和合工大的不同，已经测试了合工大用的是`/splitPointCheating`接口，`headers`也大改加了检测，所以合工大学生不能直接使用那个版本。那个项目issue里面提到的更新版本也是这个原因。(随口一提：其实我猜项目作者学校使用的才是老接口，合工大其实是新接口，那位打的其实是简单局，虽然难度也没差多少就是了)（错了当我没说...）

### 加密相关细节：

#### 云运动新版本的加密模式：

1. 随机生成sm4密钥，通过sm2加密sm4密钥。对应"cipherKey"参数
2. 用sm4密钥加密数据，对应"content"参数
3. 3.4.7换了公钥，私钥是乱给的，也就是现在我们不能解密，只能加密，详见开头。

#### 云运动防止修改的小细节：

1. sm2密钥存放于`crs-sdk.so`中，包括公钥和私钥。
2. 这个c++ 库会检查dex文件，如果文件被篡改，会返回错误的密钥(服务器可能因此判定软件作弊)。
3. apk安装包文件被360壳保护，需要脱壳才能反编译。
4. 服务器使用`/run/splitPointsCheating`域名，加入了检测，路径不能再魔幻了。

#### 本次实现的细节(偷懒部分)：

~~1. utc是随时间自动改变的，但服务器不会验证，所以可以不管，保证一套sign和utc、uuid对应上就行，具体表现是一次抓包获取一切。~~（已经修了）
2. cipherKey你给服务器什么服务器就用什么，所以我是直接默认给了一个cipherKey，用到死(偷懒，逃)，当然如果你愿意随机密钥，我提供了sm2加密解密函数和公钥私钥，你可以自己改代码实现。(其实原本不打算偷懒的，但java实现用的hutool和python的gmssl验签过不了，不知道什么原因，看上面那个实现也是一套cipherKey用到死，就不管了，逃~)
3. finish你说什么服务器信什么，你就是刚刚start原地没动下一秒finish说跑了2公里，服务器都信。路径点都不用上传的，我已经用这个方法干好几天了，系统算的是通过，所以就做了一个快速模式，还是不要用为好。

#### 加密破解方法(面向开发者)：

0. 这个加密的破解搞的头大，大一下课排满了，晚自习搞破解，要不然上周末应该就出来了(周六工程课进厂打工一天我"爱你"合工大)。
1. 反编译是通过Frida把真正的dex文件hook出来的，使用安卓虚拟机+adb。这里抓到的大多数是系统和依赖的dex，5秒延迟开深度大概率可以得到云运动的dex文件。
2. 使用dex2jar项目把dump出来的dex文件变成jar文件，然后使用jd-gui反编译找的加密代码。jadx的反编译不太行，用dex2jar的。
3. so库使用IDA分析的，IDA不是Pro居然还不给我分析ARM文件，逆天。

### 最后：

**这玩意随缘更新，有能力的推荐自己修改使用，把这个当成一个demo就好...**

*免责声明：一切内容只能用于交流学习，24h内自觉卸载，否则后果自负。*
