8月20日,阿里校园招聘前端岗位的在线笔试将统一开始。在这之前,我们先玩一下热身赛吧! http://ued.taobao.com/quiz3/ 截至8月18日11:00之前成功通关并且表现优异的同学,将有机会收到我们的惊喜邮件!
以上是阿里巴巴集团校园招聘的某一条微博的内容。
虽然我早已不是学生,本着好奇心也要玩一玩此游戏!经过几个小时的奋斗,我看到了美女,但不知道那是不是 True Ending。也许很多人把游戏通关之后就不玩不去探索了,可我不一样!我玩游戏向来都是要尽量把所有隐藏要素都挖掘出来才算结束。
正是因为知道结果,才有可能去优化过程,一个工程师的职责难道不正是这个么?“如何自动化、智能地去过每一关”的想法让我的血液稍微沸腾了起来。又经过几个小时的编码及测试,自我感觉已经把“隐藏要素”挖得差不多了。现将各个关卡的过关要点及自动获取过关条件的 JavaScript 脚本放出来。
进入每个关卡后,按 F12 打开开发者工具,在控制台中粘贴脚本代码并执行就可以。
打开控制台,在 DOM 树中就已经给出提示了——
调用
powder.blow()
显示指纹痕迹!
从代码的命名不难理解:撒粉。现实中提取指纹也是通过一种化学药剂。
这个方法需要执行多次才能够看清数字上的指纹,这时就需要把那几个数字排列组合一下挨个试了。不过这是一般人的做法,其实想进屋不止输入密码这一条路:
location.href = atob( document.getElementById("page").getAttribute("data-t") );
通关的方法就是翻转镜子,让折射光线照到黑点。当光线照射到第一个黑点后,第二个黑点就显示出来了。
(function() {
var pharaoh = getNode("pharaoh");
var sacrifice = getNode("sacrifice");
var sacrificeCoord = getDotCoord( sacrifice );
ejaculate();
// 射出
function ejaculate() {
var mirrors = document.getElementsByClassName( "mirror" );
[].forEach.call( mirrors, magicMirror );
}
// 镜子魔法
function magicMirror( mirror ) {
setCssStyle( mirror, mirrorStyles( mirror ) );
}
// 镜子样式
function mirrorStyles( mirror ) {
var id = mirror.id;
var position = mirrorPosition( id );
return {
"webkitTransformOrigin": "50% 0 0",
"webkitTransform": "rotate(" + (id === "ma" ? -67.5 : 180) + "deg)",
"left": position.left,
"top": position.top
}
}
// 镜子位置
function mirrorPosition( id ) {
var position;
if ( id === "ma" ) {
position = getMaCoord();
}
else {
position = getMbCoord();
}
return position;
}
// 通过 id 获取节点
function getNode( id ) {
return document.getElementById( id );
}
// 获取样式
function getCssStyle( node, ruleKey ) {
return getComputedStyle(node, null)[ruleKey];
}
// 设置样式
function setCssStyle( node, rules ) {
for ( var key in rules ) {
node.style[ key ] = rules[key];
}
}
// 获取黑点坐标
function getDotCoord( node ) {
return {
x: parseFloat( getCssStyle(node, "left") ) + parseFloat( getCssStyle(node, "width") )/2,
y: parseFloat( getCssStyle(node, "top") ) + parseFloat( getCssStyle(node, "height") )/2
};
}
// 计算 ma 镜子的图形中心坐标
function getMaCoord() {
var mirror = getNode("ma");
var light = getNode("source");
var coord_y = parseFloat( getCssStyle(light, "top") ) + parseFloat( getCssStyle(light, "height") )/2;
var dot2ray = coord_y - sacrificeCoord.y;
return {
left: sacrificeCoord.x + dot2ray - parseFloat( getCssStyle(mirror, "width") )/2 + "px",
top: coord_y + "px"
};
}
// 计算 mb 镜子的图形中心坐标
function getMbCoord() {
var pharaohCoord = getDotCoord( pharaoh );
var mirror = getNode( "mb" );
var dot2dot = (sacrificeCoord.x - pharaohCoord.x)/2;
var coor_x = pharaohCoord.x + dot2dot - parseFloat(getCssStyle(mirror, "width"))/2;
return {
left: coor_x + "px",
top: pharaohCoord.y - dot2dot + "px"
};
}
})();
本关要点就是运用 HTML 源码注释中的那一大段数字字符串通过 canvas
完成二维码。
(function() {
var qrdata = getQrData().split(" ");
var ctx = document.getElementById("qr-canvas").getContext("2d");
qrdata.forEach(function( code ) {
ctx.fillRect.apply( ctx, code.split( "," ) );
});
function getQrData() {
var data;
[].forEach.call(document.body.childNodes, function( node ) {
if ( node.nodeType === document.COMMENT_NODE ) {
data = node.data.replace(/\r|\n/g, "");
}
});
return data;
}
})();
将随机的几个图片是什么全部猜对即过关。
(function() {
var map = {
"T1eaRYFftbXXcuU8sK-225-225.jpg": "ubuntu",
"T1ifFNFklcXXbMbfEI-194-279.png": "sprites",
"T1hspWFgxbXXbufJvw-466-303.jpg": "wordpress",
"T15vVUFgNcXXX.oZHL-401-270.png": "grunt",
"T1FPXRFn8fXXcHpdDI-474-246.png": "less",
"T1e9FHFkhgXXbwWSnH-578-406.jpg": "php",
"T1J0JVFi4aXXXoqkr9-518-202.png": "npm",
"T1UB4UFg8dXXb1KC.o-586-89.jpg": "stackoverflow",
"T1JGxUFkJeXXbxRAc_-557-264.jpg": "w3",
"T16whWFdBXXXcpN87C-71-212.png": "v",
"T11_JTFa8gXXX5c4Pp-356-192.png": "github",
"T13ghQFdtgXXaaz0ft-569-116.png": "underscore",
"T1VcpUFaFeXXb0Z3E6-448-391.png": "sublime",
"T1ZRhTFfdeXXcRZNZO-441-244.png": "jade"
};
var img = node("J_pic");
var btn = node("J_btn");
img.onload = function() {
findAnswer();
};
btn.addEventListener( "mouseover", handler, false );
function handler( e ) {
var answer = map[ img.src.split("\/").pop() ];
if ( answer === undefined ) {
console.log( "data map 中没有该图片对应的答案,请自行查找答案。" );
}
else {
node("J_text").value = answer;
}
}
function node( id ) {
return document.getElementById( id );
}
function findAnswer() {
handler.call(img);
btn.click();
}
findAnswer();
})();
把 URI 中的房间号 room
替换成页面上“NEXT ROOM”中显示的。每页都会给出一点点文字提示信息,总共四十多页,如果完全靠人工获取的话,估计你要成鼠标手啦!为了预防疾病,请用下面的代码:
(function( $ ) {
var stack = [ $("#message").text() ];
var pathname = location.pathname;
(function trace( room ) {
if ( !!room ) {
var search = location.search;
var count = stack.length;
if ( count === 1 ) {
enterlLog( search.match(/room\=(\d+)/)[1], count, room );
}
$.ajax({
url: pathname + search.replace(/room\=\d+/, function() {
return "room=" + room;
}),
dataType: "html",
success: function( res ) {
var nextRoom = $("#next-room", $(res)).text();
stack.push( $("#message", $(res)).text() );
enterlLog( room, stack.length, nextRoom );
delay(function() {
trace( nextRoom );
}, 500);
}
});
}
else {
console.log( "经过重重困难险阻终于把所有线索收集齐了,将它们放到一起之后,原本上面空无一物的白纸突然发光,好像有什么要显现出来一样..." );
delay(function() {
var q = quiz( stack.join("") );
console.log( "“" + q.msg + "”——如来" );
delay(function() {
console.log( "“......”" );
delay(function() {
console.log( "“尼玛,你耍我?!”取经人赞美道。" );
delay(function() {
console.log( "“5 秒后会将你传送到 " + q.url + " 接受最后一次试炼,通过之后便得真经...”在白纸上方的空中显示道。" )
delay(function() {
location = q.url;
}, 5000);
}, 3000);
}, 3000);
}, 5000);
}, 5000);
}
})( $("#next-room").text() );
function quiz( str ) {
return {
msg: str.substring( 0, str.indexOf("好吧") ),
url: str.substring( str.indexOf( pathname ) )
};
}
function delay() {
setTimeout.apply( window, [].slice.call( arguments, 0 ) );
}
function enterlLog( room, count, nextRoom ) {
var msg;
if ( count === 1 ) {
msg = "你在房间 " + room + " 中找到了第 1 条获得真经的线索,上面写着“" + stack[0] + "”。";
}
else {
msg = "你从房间 " + room + " 破门而入,找到了第 " + count + " 条获得真经的线索,居然是块白纸!!!";
}
if ( !!nextRoom ) {
msg += "并且发现旁边有个标记提示到房间 " + nextRoom + " 去...";
}
else {
msg += "并且这回连房间提示都没有了?!?!?!";
}
console.log( msg );
}
})(jQuery);
控制台中的提示——
注意 cover
看到这个之后,一般都会立刻到 DOM 树中查找 id
或者 class
为 cover
的节点,并且理解到也许是利用 cover 让指纹的图片无法被看到,正常人都是这么想的。
在页面上除了指纹图片,还有更为明显的控件——文本框和提交按钮!这时大家都会明白是需要通过提交什么东西来达到目的。这时就要用到“伪·跨站攻击(XSS)”的技术手段了。
<style>
.cover {
position: absolute;
left: 588px !important;
top: 340px !important;
z-index: 9999999999999999;
background: wheat;
opacity: 1 !important;
}
</style>
其实还有个不按正常套路过关的方法,这个方法跟最开始开密码锁时的非主流方法是一样的:
location.href = atob( document.getElementById("page").getAttribute("data-p") );
经过长期奋战,千辛万苦之后只换得一个美女的背影,是不是很想上去拍她屁股一下啊?没关系,尽情地去实践你的想法吧!
用base64的界面,都可以用Base64.decode进行解码