Javascript自卫是如何工作的,又是如何在美化后进入死循环的?

How does Javascript Self-Defending work and how does it manage to enter an infinite loop upon beautifying?

有一个网站“obfuscator.io”,它混淆了 Javascript 代码。它的功能之一是“自卫”。它将一个简单的 console.log() 行变成这样:

var _0x2a3a06=function(){var _0x409993=!![];return function(_0xe0f537,_0x527a96){var _0x430fdb=_0x409993?function(){if(_0x527a96){var _0x154d06=_0x527a96['apply'](_0xe0f537,arguments);_0x527a96=null;return _0x154d06;}}:function(){};_0x409993=![];return _0x430fdb;};}();var _0x165132=_0x2a3a06(this,function(){var _0x46b23c=function(){var _0x4c0e23=_0x46b23c['constructor']('return\x20/\x22\x20+\x20this\x20+\x20\x22/')()['constructor']('^([^\x20]+(\x20+[^\x20]+)+)+[^\x20]}');return!_0x4c0e23['test'](_0x165132);};return _0x46b23c();});_0x165132();console['log']();

该代码在 Webkit 控制台中确实有效,但是当您再次在同一个控制台中使用“beautifier.io”或“de4js”和 运行 等应用程序对其进行美化时,代码会进入一个无限循环,本质上是破坏代码。这是如何运作的?它与美化器的工作方式有关,还是与 Javascript 解释代码的方式有关?

例如,它可以调用一些函数对象的.toString()方法,所以如果它以某种方式重构,输出就不一样了。

运行 像您一样通过美化器处理代码,然后应用一些基本的变量重命名,un-escaping 产生以下代码:

var makeRun = function() {
    var firstMakeRun = true;
    return function(global, callback) {
        var run = firstMakeRun ? function() {
            if (callback) {
                var result = callback['apply'](global, arguments);
                callback = null;
                return result;
            }
        } : function() {};
        firstMakeRun = false;
        return run;
    };
}();
var run = makeRun(this, function() {
    var fluff = function() {
        var regex = fluff['constructor']('return /" + this + "/')()['constructor']('^([^ ]+( +[^ ]+)+)+[^ ]}');
        return !regex['test'](run);
    };
    return fluff();
});
run();
console['log']()

重要的部分是它针对 run 函数本身测试正则表达式 /^([^ ]+( +[^ ]+)+)+[^ ]}/,执行隐式 run.toString().

现在无限循环在哪里?有 none,但应用于包含大量 space 的字符串的正则表达式确实显示 catastrophic backtracking。尝试 运行 使用制表符而不是 space 缩进的代码,它会工作得很好 - 只要您的 run 函数不包含多个 [=26=,正则表达式匹配]s 一个接一个,在结束 }.

之前没有 space