Skip to content

Instantly share code, notes, and snippets.

@huixisheng
Forked from ourai/alibaba_campus_quiz3.md
Created August 16, 2013 02:50
Show Gist options
  • Save huixisheng/6246854 to your computer and use it in GitHub Desktop.
Save huixisheng/6246854 to your computer and use it in GitHub Desktop.

智勇大闯关第三季

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 或者 classcover 的节点,并且理解到也许是利用 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") );

X,新的任务...

"任务完成"

经过长期奋战,千辛万苦之后只换得一个美女的背影,是不是很想上去拍她屁股一下啊?没关系,尽情地去实践你的想法吧!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment