答案 0 :(得分:44)
这需要一些挖掘。 samy.pl在此代码之上有几个级别的间接和混淆。它使用的检测代码版本与JohanP发现的the GitHub repository不同。与GitHub存储库不同,samy.pl中的代码可以在未停靠时检测到devtools。
它通过使用一个短脚本执行此操作,该脚本根据devtools是打开还是关闭而执行不同。
这是一个独立的例子;在浏览器中打开它,注意输出在打开和关闭devtools时是如何变化的(无论它是否停靠):
<!doctype html>
<html lang="en">
<head>
<title>My App</title>
</head>
<body>
<h1>Hello World!</h1>
<div id="future"></div>
<form id="chat_form">
<input id="chat_input" type="text">
<input type="submit" value="Send">
</form>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:4200');
socket.on('connect', function(data) {
socket.emit('join', 'Hello World from client');
});
socket.on('messages', function(data) {
alert(data);
});
</script>
</body>
</html>
每秒执行setInterval。始终执行<!DOCTYPE html>
<html>
<body>
<pre id="output"></pre>
<script type="text/javascript">
var element = new Image;
var devtoolsOpen = false;
element.__defineGetter__("id", function() {
devtoolsOpen = true; // This only executes when devtools is open.
});
setInterval(function() {
devtoolsOpen = false;
console.log(element);
document.getElementById('output').innerHTML += (devtoolsOpen ? "dev tools is open\n" : "dev tools is closed\n");
}, 1000);
</script>
</body>
</html>
,无论devtools是打开还是关闭:始终定义console.log
对象。但是,console
方法仅在devtools打开时将输出写入控制台。如果关闭devtools,log
是无操作。这是让你检测devtools是否打开的关键:检测日志操作是否为无操作。
在将console.log
写入控制台的过程中,它获取元素的id。这会调用附加__defineGetter__
的函数。因此,element
仅在devtools打开且console.log(element)
不是no-op时才调用该函数。该函数中设置了该标志,每秒为我们提供一个devtools状态的更新视图。
samy.pl使用一些额外的技巧来隐藏它:控制台也每秒都被清除,并且这个代码用空格(!)编码进行模糊处理。