mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6
489 字
1 分钟
Unity3dWeb金课堂的逆向
2026-02-04
统计加载中...

开端#

学校在校内部署了一个非常神秘的学习小游戏,发现他是unity引擎所制作。

利用之前在远古版本解包过原神的经验,于是就有了这篇文章

这次实现了能够直接一键完成的操作。

本文只提供学习,不要用于盈利

第一步 抓引擎加载文件#

通过抓包得到 xxxx.js.unityweb , 一共三个文件,这里的 xxx 有:

  • framework 资源文件
  • wasm 二进制代码
  • 忘记了

第二步 解包分析#

通过7-zip右键打开压缩包,发现内部还藏了一个东西。

通过 unitywebuwdtool 进行解包,得到 Assembly-Csharp.dll 文件,使用dnSpy打开后发现了 wocao

咳咳咳,打岔了,我们发现用户的信息是通过另一个接口获得的

还有玩家在完成一定的任务下,会向后端上传当前玩家数据

第三步 抓包#

通过抓包分析,我们可以知道会存档信息就是一个Base64后的encode Json,所以我们需要一个即将通过的存档,

才能伪造全100分的存档。

于是经过九九八十一难,我终于到达最后一关,并把数据抓了下来。

第三步 编写脚本#

通过分析游戏数据包,我们可以发现,每次打开游戏会向服务器请求得到自己的存档

于是我们可以通过拦截这个请求的响应数据,让他返回一个几乎完成的存档

完成以上这些我们可以直接做到在 30秒 内完成这一建模差劲的游戏

脚本内容:#

脚本具体就是重写window.fetch,通过更改他的响应数据

期间尝试了重写多个请求,最后发现 unity web 调用的请求是走的window.fetch

// ==UserScript==
// @name 一键完成
// @namespace http://tampermonkey.net/
// @version 202x-1x-0x
// @description try to take over the world!
// @author You
// @match *://172.xx.0.xx:xxxx/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=0.10
// @grant none
// ==/UserScript==
// 具体原理:
// 每次启动拟真都会读档,读档则会想服务器请求存档数据
// 我们只需要修改响应数据更改存档数据,即可一键完成,
// 只需要加载脚本,随后完成最后一步即可。。。
(function() {
'use strict';
const originalFetch = window.fetch;
const gradeData = {
"loginTime": "17x1xxxxxx",
"startTime": "17x1xxxxxx",
"dataList": [
// 这里有敏感数据 不方便展示
],
"finishNum": 13,
"cameraPosX": 25.4873600006104,
"cameraPosY": 1.35499978065491,
"cameraPosZ": -30.6442451477051,
"cameraRotX": 0.0,
"cameraRotY": 251.015045166016,
"cameraRotZ": 0.0,
"studyList": [
true,
true,
true,
true,
false,
false,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false
],
"doorState": [
false,
false,
false,
false,
false,
false
],
"hdFinish": [
false,
true,
true,
true,
true
],
"doorIndex": 5,
"hdState": [
false,
false,
true,
false
],
"videoCount": 1,
"countHD1": 4,
"guideIndex": 32
};
const hoursAgo = 6 + Math.random(); // 2-3小时
const referenceTime = Math.floor(Date.now() / 1000) - Math.floor(hoursAgo * 3600);
gradeData.loginTime = referenceTime.toString();
gradeData.startTime = referenceTime.toString();
const totalCourses = gradeData.dataList.length;
const firstCourseStart = referenceTime;
gradeData.dataList.forEach((course, index) => {
const minDuration = 600; // 5分钟
const maxDuration = 600 * 4; // 10分钟
const duration = Math.floor(Math.random() * (maxDuration - minDuration) + minDuration);
if (index === 0) {
course.startTime = firstCourseStart;
course.endTime = firstCourseStart + duration;
} else {
// 后续课程在前一个课程结束后开始
const prevCourse = gradeData.dataList[index - 1];
// 课程之间的间隔为15-25分钟
const minInterval = 900;
const maxInterval = 1500;
const interval = Math.floor(Math.random() * (maxInterval - minInterval) + minInterval);
course.startTime = prevCourse.endTime + interval;
course.endTime = course.startTime + duration;
}
});
function toBinaryStr(str) {
const encoder = new TextEncoder();
const charCodes = encoder.encode(str);
return String.fromCharCode(...charCodes);
}
window.fetch = async function(...args) {
const [input, init = {}] = args;
const url = typeof input === 'string' ? input : input.url;
const targetApis = [
'http://172.xx.0.xx:xxxx/',
];
const shouldIntercept = targetApis.some(api => url.includes(api));
if (!shouldIntercept) {
return originalFetch.apply(this, args);
}
const response = await originalFetch.apply(this, args);
const clonedResponse = response.clone();
try {
const data = await clonedResponse.json();
if (url.includes('/zydx-web/trans/vr/temp/get')) {
const courseData = data.data; // 当前保存的课程信息
data.endflag = "1"
try {
const encrypt = btoa(toBinaryStr(JSON.stringify(gradeData)));
console.log(gradeData);
data.data = encrypt;
}catch(e1) {
console.error(e1);
return response;
}
}
return new Response(JSON.stringify(data), {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
} catch (error) {
return response;
}
};
console.log('已启用');
})();
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Unity3dWeb金课堂的逆向
https://blog.cutebaka.cloud/posts/jkt/
作者
0x0AB8
发布于
2026-02-04
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时