喵喵喵喵
前言
当我做到第一题我就觉得头痛,要玩2048玩到有一个2048的格子才算胜利,奈何本人实在苦手。
习惯性地按出Inspector,发现所有代码都在本地运行,于是决定今年走邪道解法,手动误入歧途。
简单说一下思路,就是使用抓包工具(以fiddler为例)拦截javascript的http请求,并替换为修改后的代码,以达到不用做题就通关的目的。
打开Fiddler之后,将浏览器的Proxy指向Fiddler的监听端口(默认为8866),使用AutoResponder即可将指定的请求替换为本地修改过的js文件。
Level1
2048,出现2048的方块才能通关。
将game_manager保存在本地,修改70行处的 GameManager.prototype.addRandomTile
函数。
// Adds a tile in a random position
GameManager.prototype.addRandomTile = function () {
if (this.grid.cellsAvailable()) {
// var value = Math.random() < 0.9 ? 2 : 4;
//var tile = new Tile(this.grid.randomAvailableCell(), value);
var tile = new Tile(this.grid.randomAvailableCell(), 1024);
this.grid.insertTile(tile);
}
};
注释掉产生随机数的一行, 并将下一行的value
修改为1024
。 修改完成之后在Fiddler中添加Auto Responder规则
刷新页面(如果reload之后不是修改之后的js文件,清除缓存即可),所有新出现的方块都是1024,合并一次即可过关。
Level2
俄罗斯方块,要获得1024分才能过关。
首先将level22.js
保存在本地。
从第二题开始js代码就开始有混淆了。但是数值是没法隐藏的。
通关条件是1024, 十六进制为0x400,在js中搜索0x400,只有两个结果,而且都与分数有关。
case '10':
if (!_0x5d1071['TNKOn'](validateBlock, nextBlock)) {
status = 0x2;
// if (_0x5d1071['qVkxf'](score, 0x400)) {
if (_0x5d1071['qVkxf'](score, 0x1)) {
document['getElementById'](_0x5d1071['smtEb'])['innerText'] = _0x5d1071['NqDyV'];
} else {
document['getElementById'](_0x5d1071['smtEb'])['innerText'] = _0x5d1071['cpSmM'];
}
document['getElementById'](_0x5d1071['xWOsg'])['disabled'] = ![];
return;
}
continue;
// if (_0x43e5f0['wLwev'](score, 0x400)) {
if (_0x43e5f0['wLwev'](score, 0x1)) {
var _0x597490 = _0x43e5f0['QIEww']['split']('|')
, _0x1f49d0 = 0x0;
将0x400修改为0x1,添加Auto Responder规则
只要获得1分以上即可过关
Level3
这他妈smdx
果断打开Inspector,发现有一个Textarea,并且会随时时检查输入,应该是输flag的地方
在level33.js
里找到一个看起来像是flag的东西
if (_0x473dc8['lGuXU'](ined['value'], 'I\x20Luv\x20South\x20China\x20Normal\x20University')) {
在前面找到的Textarea输入I Luv South China Normal University
即可过关
Level4
四个按钮,每按一次就将button显示的值加到指示器上,并且当前button会产生新的数字。
打开Inspector,找到被隐藏显示的区域。
删掉style
属性,即可看见隐藏内容。
将任意btn修改为1024,点击一次即可过关。
Level5
粗略地看下代码,发现是一个按键发声的钢琴程序。
在level55.js
中发现看起来像是答案的内容。
let arr_ans = [0x1, 0x1, 0x5, 0x5, 0x6, 0x6, 0x5, 0x4, 0x4, 0x3, 0x3, 0x2, 0x2, 0x1];
依次按下对应的数字键,即可过关。
顺便一提,敲出来的旋律是小星星,也和网页里的图片吻合。
Level6_0
先来说正常解法。
在网页偏右下的地方有一个Textarea,左边显示的内容原封不动地敲进去即可过关。
第二部分也是类似,不赘述了。
Level6_1
现在来说邪道解法。
第一次玩的时候没注意到那个Textarea,加上被邪道蛊惑心灵,于是直接走了邪道玩法。
首先在level66.js
中找到过关时会执行的函数。
text22InChange = function() {
var structture = {
'kKSsu': function(_0x147d4c, _0x2fd784) {
return _0x147d4c === _0x2fd784;
},
'qokWA': '7|5|8|6|2|1|3|0|4',
'UcTHH': '61f76181c5d100b3',
'eKSyF': 'post_form',
'sRhcg': '04ad5938eaf0efb6',
'cPaAT': 'textarea'
};
splatStack['push'](0x1);
if (structture['kKSsu'](my_text22['value'], my_text['value'])) {
var _0x31ae2e = structture['qokWA']['split']('|')
, _0x84efb3 = 0x0;
while (!![]) {
switch (_0x31ae2e[_0x84efb3++]) {
case '0':
_0x41a986['submit']();
continue;
case '1':
_0x41a986['appendChild'](_0x2e9287);
continue;
case '2':
_0x2e9287['value'] = structture['UcTHH'];
continue;
case '3':
document['body']['appendChild'](_0x41a986);
continue;
case '4':
return;
case '5':
var _0x41a986 = document['getElementById'](structture['eKSyF']);
continue;
case '6':
_0x2e9287['name'] = structture['sRhcg'];
continue;
case '7':
splatStack['push'](0x32);
continue;
case '8':
var _0x2e9287 = document['createElement'](structture['cPaAT']);
continue;
}
break;
}
}
}
;
很显然代码被混淆过。先来推断一下逻辑,输入时检查输入内容是否符合答案,如果符合就提交。
上面函数里的if
很明显就对应着判断输入的逻辑。
再看接下来的4行。(下面的structure是被我重命名之后的变量名,忘记原来的变量名了orz)
var _0x31ae2e = structture['qokWA']['split']('|')
, _0x84efb3 = 0x0;
while (!![]) {
switch (_0x31ae2e[_0x84efb3++]) {
_0x31ae2e
是一个数组({7,5,8,6,2,1,3,0,4}
),_0x84efb3
是索引。
_0x31ae2e[_0x84efb3++]
就是对数组进行遍历。
再结合case
中的内容来看,就是以{7,5,8,6,2,1,3,0,4}
的顺序来执行各个case来完成提交的过程。
要直接过关,只需要删去判断条件,再按顺序执行各个case
中的代码即可。
以下为修改后的函数
text22InChange = function() {
var structture = {
'kKSsu': function(_0x147d4c, _0x2fd784) {
return _0x147d4c === _0x2fd784;
},
'qokWA': '7|5|8|6|2|1|3|0|4',
'UcTHH': '61f76181c5d100b3',
'eKSyF': 'post_form',
'sRhcg': '04ad5938eaf0efb6',
'cPaAT': 'textarea'
};
splatStack['push'](0x1);
var _0x31ae2e = structture['qokWA']['split']('|')
, _0x84efb3 = 0x0;
splatStack['push'](0x32);
var _0x41a986 = document['getElementById'](structture['eKSyF']);
var _0x2e9287 = document['createElement'](structture['cPaAT']);
_0x2e9287['name'] = structture['sRhcg'];
_0x2e9287['value'] = structture['UcTHH'];
_0x41a986['appendChild'](_0x2e9287);
document['body']['appendChild'](_0x41a986);
_0x41a986['submit']();
}
;
拦截并修改请求后,在Console中直接执行text22InChange()
即可过关。
Level7_0
输入表达式,会生成蓝色的函数图,与目标拟合程度足够高时即可进入下一关。
像这样:
题目数量不少,想靠我的数学知识全部写出正确答案基本是在做梦,因为后面有一些不做人的题目:
所幸所有答案的表达式都以明文的形式写在level77.js
里面。
levels = ['x', 'x^2', 'x<0', '0.1/x', 'abs(x)', 'abs(x^3)', 'sin(10x)<10y', 'sin(PI*x)', 'exp(E*x)', 'x%0.2>y', 'sqrt(0.5-x^2)', 'x^2+x', 'x^2+y^2<0.5', 'ceil(x*10)/10', 'x^3+0.3*x^2-0.5*x-0.3', 'x^10+y^10<0.1', 'tan(x^2*3.8)', 'ceil(x*10)/10+floor(x*10)/10', 'min(x^2-x,x)', 'sin(x)^2+sin(y)^2<0.5', 'tan(x)^2+tan(y)^2<0.5', 'sin(10x+0.3sin(1000x))', 'log(E*x)', 'gamma(10x)/10', 'x\x20mod\x200.4', 'x^x', 'pow(x^3,x)', 'abs(sin(x))', '((2x)^2+(2y)^2-1)^3<(2x)^2(2y)^3', 'x*y<0', 'x*y<0.1', 'x<-0.2\x20or\x20x>0.2', '-0.8<x<0.2', '-0.2<x<y<0.2', '(abs(x)-0.5)^2+y^2<0.1', 'abs(sin(x^2*5))', 'max(x%0.2,sin(10*PI*x))', 'gamma(abs(x)*10)/10', 'max(sin(x*10)/10,cos(x*10)/10)', 'log(abs(x*5)-0.1)/5', 'x%(0.2)+sin(x*10)/10', 'max(0,x)', 'max(0.1x,x)', 'sign(sin(x*10))/10', 'atan(x*1.5)', 'tanh(x*1.5)', '1/(1+e^(-x*10))', 'sign(sin(x*1000))/2', '0.1sin(10x)+0.2sin(20x)+0.3sin(30x)+0.4sin(40x)', 'abs(x)+abs(y)<0.5', 'sin(10x)%1-0.5', '0.2*isPrime(ceil(x*20))', 'norm(cos(i*10x))/10', 'gcd(6,ceil(10*x))/10', 'sin(PI*(x+sin(x*1000)))'];
一一输入即可过关,最后提交flag即可。(这就没意思了)
Level7_1
正常解法2
直接在level77.js
中找到flag
'tNthG': '分(满分20000)。flag:\x201db8d352466b5e5b',
Level7_2
邪道解法
当时又是被邪道蛊惑心灵,想都没想直奔js代码orz
function judge() {
var _0x1e2712 = {
'xOjFj': function(_0x41ee66) {
return _0x41ee66();
},
'BaqMh': function(_0x3eee3a, _0xe0eaef) {
return _0x3eee3a < _0xe0eaef;
},
'heHun': '1px\x20solid\x20green',
'EiJaU': '1px\x20solid\x20red'
};
_0x1e2712['xOjFj'](reMes);
// if (_0x1e2712['BaqMh'](R, dd)) {
bu['disabled'] = ![];
bu['style']['border'] = _0x1e2712['heHun'];
// } else {
// bu['disabled'] = !![];
// bu['style']['border'] = _0x1e2712['EiJaU'];
// }
}
找到judge()
函数,直接将判断对错的部分注释掉,只留下结果正确的代码。
添加相应的Auto Responder规则,之后无论输入什么内容都可以进入下一关,像这样: