¶网页游戏的核心
网页网游的游戏界面绝大多数是通过canvas实现的
网页网游的通信绝大多数是通过websocket实现的
¶如何找到赛尔号的通信函数
首先打开一个空白页,再打开浏览器的调试工具,快捷键f12
这时输入网址s.61.com
,因为我们提前打开了调试工具,就能截获到从页面html开始之后的所有的HTTP请求
如图,281次请求,这些请求主要是加载页面素材的,真正的游戏通信在画红线的websocket里
点开ws,再点开左侧的某一个protocol,这时就能看到和服务器的通信了
这时的消息主要是登录时的请求,并没有什么重要性,所以我们进游戏后再看protocol里的变化
登录进去后发现另一个protocal里出现了很多消息,那么这个protocal就是我们和服务器建立的ws连接
我们随意在游戏里进行一些操作,然后选中最近的一个收到的消息(红色),点击上方发起程序,
然后我们在调用堆栈里选择这个e.connect
,点击右侧进入源代码位置
然后点击左下角的美化,这时自动定位到了发起程序的源码位置
点击左侧空栏,下断点,如图,我下在第1045行
这时回到游戏进行操作,发现仍能操作,这说明这一行代码现在并没有在运行
往下发现一个sendMessage
函数,在这里下断点后,游戏瞬间暂停
在右方监视输入t._cmd
和t._body
,就可以实时分别地看到通信的协议号和包体
此时的协议279
代表从服务器获取当前时间,包体为空
此时的协议4353
代表角色移动,包体x,y代表移动的坐标
¶找到通信函数后如何制作脚本呢?
归根到底有几种办法:
- 每次打开进入游戏后,在控制台写入脚本
- 直接写入html源代码中,这样每次打开不用手动输入脚本
- 制作浏览器扩展插件
¶1.控制台脚本
¶hook 负责发包的js对象
既然我们已经找到了发包的函数,直接将尝试将其打包
首先注意prototype
关键词,prototype
是原型的意思,也就是说我们现在是在复杂的函数e内的一个叫sendMessage
的原型函数中,要想能够完整还原函数e的全部功能,我们需要整个e,而不仅仅是它的sendMessage
函数,这时使用this
关键字就能在一个原型函数内获得其外部的整体
封装的发包函数=this
就是一行代码这么简单!!我们新建了一个全局变量封装的发包函数
并将其指向了this
实例
然后再封装我们想要模拟发送的包,也就是函数的参数上图括号里的t
这么简单,三个字符的代码包=t
然后只需要每次发包时对包进行我们需要的更改(下图的4353是玩家移动的指令,包._body.x
是移动的横坐标),然后使用封装的发包函数.sendMessage(包)
就可以模拟真人操作了
视频演示
虽然本地没看到用户移动,但是服务器确实收到了包,因为其他账号可以看到
接下来的时间我会制作一些其他发包的脚本,欢迎加入赛尔号启航战队混元~太极门
,学习交流
¶2.本地替代
chrome浏览器有一个强大功能——本地替代。本地替代可以使你随心所欲的修改任意一个网页,其原理是在请求远程网站时会先查看是否存在本地替代的改写文件。
本地替代只有打开F12
时才会生效。所以在打开目标网页之前需要先打开任意网页并打开F12
然后再跳转到目标网页。查看s.61.com的网页源代码后,会发现整个游戏的代码都在BootStrapV2.min.js?(后跟时间戳)
里,而经过我的测试,发现不论什么时间,返回的包都是一样的,虽然文件名带有不断变化的时间戳,但完全给它一个固定的文件名并进行本地改写。以下代码,先定义了一个网络请求的函数sendasgetRequest
,然后使用这个函数来加载名为bootStart.js
的文件,这个文件其实就是BootStrapV2.min.js
的替代。
1 |
|
接下来分析网页的主要代码bootStart.js
,可以发现游戏加载了如图所示的几个重要的js文件,在原本的index.html中你会发现一个奇怪的单词egret
,经过研究,赛尔号启航使用的就是这个叫egret
的游戏引擎制作的。在控制台输入egret,你会发现的确它是一个已经存在的全局变量。而图上的几个js文件就是赛尔号个性化修改后的egret的引擎文件。
接下来再通过修改这几个重要的引擎文件,就能实现游戏脚本的制作。那么接下来首先要找到这些引擎文件的请求是在哪里发起的。在网络选项=》发起程序中找到其请求是由bootStart.js
中如下代码发起的
1 | 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其实是一个XMLHttpRequest
,既然发送的请求在这里,那么处理请求的函数应该也在附近。往下找就发现了一句代码document.createElement("script")
,这就是关键了,通过修改这里的script,就能实现修改引擎文件。我筛选了4个重要的引擎文件,以下图是通过访问本机的3009端口获取本地的4个引擎文件从而实现对引擎文件进行本地修改。当然,这样就需要本机在3009端口开启cors的服务器
1 | let List=[ |
这里我为什么不继续使用chrome的本地替代功能,而要大费周章从自建服务器获取文件呢?
因为有BUG,chrome的本地替代有bug,修改index.html和bootStart还好,因为它们都在s.61.com的域名下,而这里的/bootStrap/不知为何变成了未知域名网址,网页就不会自动加载这些本地文件,仍然从远端获取。
¶egret引擎的介绍
egret是一个2D的游戏引擎,也就是说游戏里所有的2D图像本质上都是egret里的“显示物体”和“显示容器”,而所有这些物体和容器都存在于“舞台”之内,在控制台输入MFC.stage
你就能得到这个”舞台“指向的 Object。
有了这个舞台 Object,你会发现它有一个children
属性,这个属性就是它所有的子对象,有些子对象还会有自己的子对象,如此递进,就能得到”舞台“中任意的对象,也就是egret里的“显示物体”和“显示容器”。
1 |