Javascript介绍
¶编译型语言的特点
c , c++ , 打包成操作系统机器码,然后再执行
¶解释型语言的特点
Javascript,一边编译成机器码一边执行
¶V8引擎
V8引擎是谷歌浏览器和NodeJS内置的 Javascript引擎
比如你在一个网页中加载一个calc.js文件,如图:
这个文件里的每个字节都会被转化成符号,比如ASCII或者UTF-8字节谷歌浏览器会识别这些关键词符号,直至将文件读取完毕
然后检查语法并生成抽象树
之后交给V8引擎的ignition解释器,生成字节码
ignition解释器然后会运行这些字节码,转化成cpu运行的机器码
对于一些被调用多次的函数,turbofan优化器会存留之前生成的机器码,跳过解释直接运行机器码,啊v要注意函数的参数个数,类型一定要是一样的
¶致谢
https://www.youtube.com/watch?v=p-iiEDtpy6I&t=634s
https://dev.to/lydiahallie/javascript-visualized-the-javascript-engine-4cdf
未命名
未命名
费马小定理和欧拉定理
¶取模的定义
模除(又稱模数、取模操作、取模運算等,英語:modulo 有时也称作 modulus)得到的是一个数除以另一个数的余数。
给定两个正整数:被除数 a 和除数 n,a modulo n (缩写为 a mod n)得到的是使用欧几里德除法时 a/n 的余数。
¶取模的性质
对于正整数a,k,m,n,如果有 a = m (mod n),那么 m* k (mod n) = [ a* k (mod n) ]mod n
¶费马小定理的证明
¶举例证明
如果p是一个素数(质数),a是一个正整数且与p的最大公因数为1,那么对于数列:
a, 2a, 3a, 4a, 5a, (p-1)a
将每个项都除去p得出余数, 得出的结果是一个包含正整数1到p-1的数列,且每个整数都只出现一次
举例,a=8,p=11,可得:
8, 0*11+ 8
16,1*11+ 5
24,2*11+ 2
32,2*11+ 10
40,3*11+ 7
48,4*11+ 4
56,5*11+ 1
64,5*11+ 9
72,6*11+ 6
80, 7*11+ 3
可以看到,余数是打乱后的数列 1,2,3,4,5,6,7,8,9,10
将数列逐项相称,a *2a *3a *4a *5a … *(p-1)a,
根据乘法的交换律,其结果就等于 1 * 2 * 3 … * (p-1) (mod p)
也就是说
$$
a^{p-1}(p-1)! \equiv (p-1)!(\mod p)
$$
接着根据取模的性质,两边消去(p-1),可得:
$$
a^{p-1} \equiv 1(\mod p)
$$
¶串珠证明
取一个整数a,一个素数p
一个珠子串共有p个珠子,每个珠子有a种颜色可能,那么这个珠子串共有ap种可能,
从所有可能的珠子串中减去都为同样的颜色珠子串(共有a个),得到的珠子串为ap-a 个
因为每个珠子串共p个珠子,所以ap-a 能够整除p
也就是
$$
a^{p}-a (\mod p)\equiv 0
$$
转化得
$$
a^{p}\equiv a (\mod p)
$$
$$
a^{p-1}\equiv 1 (\mod p)
$$
¶费马小定理解决扑克牌问题
给你一副按大小顺序排好的扑克牌(52张不包括大小王),将牌平分为上下两组,取第二组的一张牌,再取第一组的一张牌,循环直至所有牌都拿完
再次循环上面的操作,将牌组再平分为上下两组,取第二组一张,再取第一组一张,直至取完
如此循环,需要多少次循环才能使牌组重新回到顺序排好的状态呢?
这里就可以用模算术,我们假设一张牌最初的位置是x
很容易发现规律:经过一次洗牌后,牌的位置变成了2x(mod 53) ,比如 27*2 mod53可得1,52*2 mod53可得51
那么进行n次洗牌,原本x位置的牌会变成 x* 2^n (mod 53),注意 x *2(mod53)*2(mod53)…*2(mod53)=x*2*2…*2(mod53)
要想n次洗牌后位置不变,则 x*2^n(mod53)=x
等式两边消去x,得2n(mod53)=1,变换写法就是2n=1 (mod53)
也就是说找到次幂n能够使2^n-1整除53
根据费马小定理,因为53是素数且和2之间没有公因数(公约数),则n=52
¶费马小定理到欧拉定理
未完待续…
¶视频参考
有兴趣的小伙伴可以进入文章页面,在底部评论 >_<
未命名
¶如何在关闭中查找变量
如下函数,
1 | let obj = function() { |
代码会打印出一个对象,里边有两个函数
赛尔号启航脚本如何随着版本更新
¶1.不启用本地替代,打开开发者工具,正常启动赛尔号
在网络里搜索关键词zzz_conf
会找到env.%7B
开头的一个js文件,可以清楚的看到,这里有一行,写着游戏版本控制文件
¶2.打开服务器项目,(从gitee下载)
找到env%7B-103
这个文件,搜索关键词zzz_conf
找到注释的版本文件位置,并修改成上一步中获取的url地址,(不要忘了保存修改)如下图:
¶3.启动服务器项目
如下图,启动服务器
启动后如下图:
¶4.打开本地替代,重新进入赛尔号
打开本地替代
刷新浏览器
发现这次版本更新,mapManager
这个文件也更新了,这也好办
关掉本地替代,重新打开一个网页,网址栏输入s.61.com
,回车
在网络里搜索mapmanager
找到如下文件
在这里右键,选在新标签打开
进入新标签,按键盘,ctrl+s,将这个保存到服务器项目static/resouce/app/mapManager
里,在这里新建文本文档
在vscode里,右键文件夹,可以快速打开文件所在目录
将新文档重命名为网址最后的名字
保存修改,重启服务器
启动本地替代,重进赛尔号
成功进入,但是😭,这次更新把js文件都改了,服务器里的js一个也没加载
¶5. 本地替代修改游戏js文件
先找发包的js文件,网络里搜索控制对战速度的js文件battle
,得到如下,记住这个文件名
在源代码–>页面–>无域名里,找到这个文件
右键,选择保存为本地替代,效果如图,有一个紫色的圆点
点击代码美化
在美化后代码里,ctrl+f,搜索关键词animation.play
,找到如下:
修改为:
安卓逆向一款变声器,frida首战告捷
¶得来全不费工夫
在了解firda之前,我曾经接触过xposed,当时也是对这样的东西存在感到十分吃惊,Reverse Engineer的学习道路上,必不可少各种各样的工具。这些前辈们给我们留下的工具是我们工作的基础。如果说安卓应用和windows应用原本就像一个黑盒子,我们无法窥探它内部的工作,而frida和Ollydbug这些工具,就是我们打开黑盒面纱的钥匙。
¶我们要实现的功能:
破解vip才能使用的变声功能
付费语音包的使用
¶Jadx反编译,窥探APP源码,定位关键类
通过jadx反编译,找到应用包名,在Mainactivity里搜索关键词VIP,就找到了关键函数gotoBuyVIPUI
¶IntelliJ smalidea 插件,动态调试APP
用Android killer 拆apk后,用IntelliJ打开项目。找到我们之前找到关键函数,在这下断点
在APP上点击一个付费VIP才能使用的语音包,果然,在断点处停了下来。说明我们找对地方了,这个就是检测是否VIP的函数
¶改写APKsamli代码或者frida动态hook,实现vip功能的使用
由于对samli语法不熟悉,经过一番尝试无果
我选择简单粗暴的frida
以下为python注入代码
1 | import frida, sys |
以下为weiyin.js 的脚本代码
1 |
|
¶注入脚本后,即可愉快使用vip功能,不过缺点是每次重启app后,都要重新注入,可惜不会samli语法啊
html5赛尔号启航脚本制作
¶网页游戏的核心
网页网游的游戏界面绝大多数是通过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 |