0%

html5赛尔号启航脚本制作

网页游戏的核心

网页网游的游戏界面绝大多数是通过canvas实现的

网页网游的通信绝大多数是通过websocket实现的

如何找到赛尔号的通信函数

首先打开一个空白页,再打开浏览器的调试工具,快捷键f12

这时输入网址s.61.com,因为我们提前打开了调试工具,就能截获到从页面html开始之后的所有的HTTP请求

image-20210802013616839

如图,281次请求,这些请求主要是加载页面素材的,真正的游戏通信在画红线的websocket里

点开ws,再点开左侧的某一个protocol,这时就能看到和服务器的通信了

image-20210802013833049

这时的消息主要是登录时的请求,并没有什么重要性,所以我们进游戏后再看protocol里的变化

image-20210802014201812

登录进去后发现另一个protocal里出现了很多消息,那么这个protocal就是我们和服务器建立的ws连接

image-20210802014345700

我们随意在游戏里进行一些操作,然后选中最近的一个收到的消息(红色),点击上方发起程序,

然后我们在调用堆栈里选择这个e.connect,点击右侧进入源代码位置

image-20210802014810999

image-20210802015122325然后点击左下角的美化,这时自动定位到了发起程序的源码位置

image-20210802015242539

点击左侧空栏,下断点,如图,我下在第1045行image-20210802015338965

这时回到游戏进行操作,发现仍能操作,这说明这一行代码现在并没有在运行

往下发现一个sendMessage函数,在这里下断点后,游戏瞬间暂停

image-20210802020418753

在右方监视输入t._cmdt._body,就可以实时分别地看到通信的协议号和包体

image-20210802020718632

此时的协议279代表从服务器获取当前时间,包体为空

此时的协议4353代表角色移动,包体x,y代表移动的坐标

image-20210802020959588

找到通信函数后如何制作脚本呢?

归根到底有几种办法:

  1. 每次打开进入游戏后,在控制台写入脚本
  2. 直接写入html源代码中,这样每次打开不用手动输入脚本
  3. 制作浏览器扩展插件

1.控制台脚本

hook 负责发包的js对象

既然我们已经找到了发包的函数,直接将尝试将其打包

首先注意prototype关键词,prototype是原型的意思,也就是说我们现在是在复杂的函数e内的一个叫sendMessage的原型函数中,要想能够完整还原函数e的全部功能,我们需要整个e,而不仅仅是它的sendMessage函数,这时使用this关键字就能在一个原型函数内获得其外部的整体

image-20210803021230357

封装的发包函数=this就是一行代码这么简单!!我们新建了一个全局变量封装的发包函数并将其指向了this实例

然后再封装我们想要模拟发送的包,也就是函数的参数上图括号里的t

image-20210803014801726

这么简单,三个字符的代码包=t

然后只需要每次发包时对包进行我们需要的更改(下图的4353是玩家移动的指令,包._body.x是移动的横坐标),然后使用封装的发包函数.sendMessage(包)就可以模拟真人操作了

image-20210803015159642

视频演示

small

虽然本地没看到用户移动,但是服务器确实收到了包,因为其他账号可以看到

接下来的时间我会制作一些其他发包的脚本,欢迎加入赛尔号启航战队混元~太极门,学习交流

2.本地替代

chrome浏览器有一个强大功能——本地替代。本地替代可以使你随心所欲的修改任意一个网页,其原理是在请求远程网站时会先查看是否存在本地替代的改写文件。

本地替代只有打开F12时才会生效。所以在打开目标网页之前需要先打开任意网页并打开F12然后再跳转到目标网页。查看s.61.com的网页源代码后,会发现整个游戏的代码都在BootStrapV2.min.js?(后跟时间戳)里,而经过我的测试,发现不论什么时间,返回的包都是一样的,虽然文件名带有不断变化的时间戳,但完全给它一个固定的文件名并进行本地改写。以下代码,先定义了一个网络请求的函数sendasgetRequest,然后使用这个函数来加载名为bootStart.js的文件,这个文件其实就是BootStrapV2.min.js的替代。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

async function sendasgetRequest(url) {
const Http = new XMLHttpRequest();

Http.open("GET", url);
Http.send();

if (Http.readyState === XMLHttpRequest.DONE) {
return Http;
}

let res;
const p = new Promise((r) => res = r);
Http.onreadystatechange = () => {
if (Http.readyState === XMLHttpRequest.DONE) {
res(Http);
}
}
return p;
}


document.body.ontouchstart = function (e) { e.preventDefault && e.preventDefault(); };
setTimeout(async function () {
var oHead = document.getElementsByTagName('HEAD').item(0);
// var script = document.createElement("script");
// script.type = "text/javascript";
// script.src = 'BootStrapV2.min.js?' + ~~(Date.now() / 1000);
// oHead.appendChild(script);
// var response=await sendasgetRequest( 'BootStrapV2.min.js?' + ~~(Date.now() / 1000) );
var response=await sendasgetRequest( 'bootStart.js' );

var script =

// ' debugger; ' +
response.response+'\n'
// + '//# sourceURL=s.61.com/bootStart.js'
// ;


var el = document.createElement('script');
el.type = 'text/javascript';
el.text = script
;
oHead.appendChild(el);



接下来分析网页的主要代码bootStart.js,可以发现游戏加载了如图所示的几个重要的js文件,在原本的index.html中你会发现一个奇怪的单词egret,经过研究,赛尔号启航使用的就是这个叫egret的游戏引擎制作的。在控制台输入egret,你会发现的确它是一个已经存在的全局变量。而图上的几个js文件就是赛尔号个性化修改后的egret的引擎文件。

接下来再通过修改这几个重要的引擎文件,就能实现游戏脚本的制作。那么接下来首先要找到这些引擎文件的请求是在哪里发起的。在网络选项=》发起程序中找到其请求是由bootStart.js中如下代码发起的

1
2
3
4
5
o.$value=e(n.$value)}catch(e){t=!0,o.$error=e}n.$error=null,n.$value=null,n.$next=null,o.$next?o.$next():t&&setTimeout(function(t){console.error(t)},0,o.$error)},o},t}();t.SimplePromise=e,egret.registerClass(e,"bootStrap.SimplePromise");var r=e,n=function(){function t(){}return __define,t.prototype,t.get=function(t,e,n,o){return void 0===e&&(e="text"),void 0===n&&(n="GET"),void 0===o&&(o=6e4),new r(function(r,i){var a,u,c=/^([\w-]+:)\/\//.test(t)?RegExp.$1:w.location.protocol;if(w.XMLHttpRequest)a=new w.XMLHttpRequest;else try{a=new ActiveXObject("MSXML2.XMLHTTP")}catch(t){a=new ActiveXObject("Microsoft.XMLHTTP")}a.onreadystatechange=function(){if(4==a.readyState)if(u&&clearTimeout(u),a.onreadystatechange=null,a.status>=200&&a.status<300||304==a.status||0==a.status&&"file:"==c)r(a);else{var e=new Error(t+" 加载失败! xhr.status:"+a.status);e.url=t,e.status=a.status,i(e)}},u=setTimeout(function(){clearTimeout(u),a.abort(),i(new Error('"'+t+'"加载超时,用时'+o/1e3+"s"))},o);try{a.responseType=e}catch(t){console.error(t)}

a.open(n,t,!0),
a.send()}).then(function(t){if(void 0!=t.response)return t.response;if(/msie

如果你在最后一行打上断点,你会发现这里的a其实是一个XMLHttpRequest,既然发送的请求在这里,那么处理请求的函数应该也在附近。往下找就发现了一句代码document.createElement("script"),这就是关键了,通过修改这里的script,就能实现修改引擎文件。我筛选了4个重要的引擎文件,以下图是通过访问本机的3009端口获取本地的4个引擎文件从而实现对引擎文件进行本地修改。当然,这样就需要本机在3009端口开启cors的服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
let List=[
'bootStrap/libs.{-1300278934}.BootStrapV2.min.js?-1300278934'
// , 'bootStrap/base.{-116702590}.BootStrapV2.min.js?-116702590'
,'bootStrap/base.%7B-116702590%7D.BootStrapV2.min.js?-116702590'.replace('%7B','{').replace('%7D','}')
// ,'bootStrap/env.%7B-1033305282%7D.BootStrapV2.min.js?-1033305282'.replace('%7B','{').replace('%7D','}')
,'bootStrap/env.%7B-2093208555%7D.BootStrapV2.min.js?-2093208555'.replace('%7B','{').replace('%7D','}')
// ,'bootStrap/libs.%7B-1300278934%7D.BootStrapV2.min.js?-1300278934'.replace('%7B','{').replace('%7D','}')
// ,'bootStrap/libs.%7B1442564649%7D.BootStrapV2.min.js?1442564649'.replace('%7B','{').replace('%7D','}')
,'bootStrap/start.%7B-792005426%7D.BootStrapV2.min.js?-792005426'.replace('%7B','{').replace('%7D','}')
]
// .replace('%7B','{').replace('%7D','}')

let judgr= ()=>{return List.some((ur)=>{if (ur==e){
return true
}})}
if(judgr()){
await fetch("http://localhost:3009/"+encodeURI(e).replaceAll('%','%25').replaceAll('?','%253f'), {

mode: "cors",
method: "GET",
headers: {
"Accept": "application/javascript; charset=UTF-8"
}
})
.then(response => response.text())
.then((response) => {
// alert(response)
f.text=response
document.head.appendChild(f).parentNode.removeChild(f) })

这里我为什么不继续使用chrome的本地替代功能,而要大费周章从自建服务器获取文件呢?

因为有BUG,chrome的本地替代有bug,修改index.html和bootStart还好,因为它们都在s.61.com的域名下,而这里的/bootStrap/不知为何变成了未知域名网址,网页就不会自动加载这些本地文件,仍然从远端获取。

egret引擎的介绍

egret是一个2D的游戏引擎,也就是说游戏里所有的2D图像本质上都是egret里的“显示物体”和“显示容器”,而所有这些物体和容器都存在于“舞台”之内,在控制台输入MFC.stage你就能得到这个”舞台“指向的 Object。

有了这个舞台 Object,你会发现它有一个children属性,这个属性就是它所有的子对象,有些子对象还会有自己的子对象,如此递进,就能得到”舞台“中任意的对象,也就是egret里的“显示物体”和“显示容器”。

1