8月20日,阿里校园招聘前端岗位的在线笔试将统一开始。在这之前,我们先玩一下热身赛吧! http://t.cn/zQRFjtd 截至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 = {
"http://img03.taobaocdn.com/tps/i3/T1eaRYFftbXXcuU8sK-225-225.jpg": "ubuntu",
"http://img01.taobaocdn.com/tps/i1/T1ifFNFklcXXbMbfEI-194-279.png": "sprites",
"http://img01.taobaocdn.com/tps/i1/T1hspWFgxbXXbufJvw-466-303.jpg": "wordpress",
"http://img03.taobaocdn.com/tps/i3/T15vVUFgNcXXX.oZHL-401-270.png": "grunt",
"http://img04.taobaocdn.com/tps/i4/T1FPXRFn8fXXcHpdDI-474-246.png": "less",
"http://img03.taobaocdn.com/tps/i3/T1e9FHFkhgXXbwWSnH-578-406.jpg": "php",
"http://img02.taobaocdn.com/tps/i2/T1J0JVFi4aXXXoqkr9-518-202.png": "npm",
"http://img02.taobaocdn.com/tps/i2/T1UB4UFg8dXXb1KC.o-586-89.jpg": "stackoverflow",
"http://img03.taobaocdn.com/tps/i3/T1JGxUFkJeXXbxRAc_-557-264.jpg": "w3",
"http://img02.taobaocdn.com/tps/i2/T16whWFdBXXXcpN87C-71-212.png": "v",
"http://img03.taobaocdn.com/tps/i3/T11_JTFa8gXXX5c4Pp-356-192.png": "github",
"http://img03.taobaocdn.com/tps/i3/T13ghQFdtgXXaaz0ft-569-116.png": "underscore",
"http://img03.taobaocdn.com/tps/i3/T1VcpUFaFeXXb0Z3E6-448-391.png": "sublime"
};
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 ];
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();
})();
(function( $ ) {
var currentRoom = $("#next-room").text();
var stack = [currentRoom];
trace( currentRoom );
function trace( room ) {
$.ajax({
url: location.pathname + location.search.replace(/room\=\d+/, function() {
return "room=" + room;
}),
dataType: "html",
success: function( res ) {
var nextRoom = $("#next-room", $(res)).text();
if ( nextRoom !== "" ) {
var msg = $("#message", $(res)).text();
stack.push( msg );
console.log( "恭喜你,在第 " + room + " 号房间中找到了<" + msg + ">!正在前往第 " + nextRoom + " 号房间..." );
setTimeout(function() {
trace( nextRoom );
}, 1500);
}
else {
var url = quizUrl();
console.log( "经过层层劫难,已取得真经 " + url + "!" );
setTimeout(function() {
location.href = url;
}, 5000);
}
}
});
}
function quizUrl() {
var str = stack.join("");
return str.substring( str.indexOf("/quiz") );
}
})(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") );
经过长期奋战,千辛万苦之后只换得一个美女的背影,是不是很想上去拍她屁股一下啊?没关系,尽情地去实践你的想法吧!