嗨小伙伴们,今天给大家带来一篇超赞的翻译文章!本文是我翻译的,原文链接在这里哦:Javascript obfuscation techniques by example
我的目的是帮助大家更好地理解原文的内容。如果我们翻译的不够准确或者有疑问的地方,欢迎随时提出哦~
废话不多说,让我们一起来看看这篇翻译文章吧!
有时,当你在抓取一些网站时,你会看到 JavaScript 代码,它看起来一团糟,无法阅读——无论你怎么眯着眼睛,你都无法理解它,那是因为它被混淆了。代码混淆是一种转换,旨在使代码难以阅读和防止逆向工程。许多网站利用 JavaScript 混淆来让抓取工具或自动化开发人员感到为难。
给出以下非常简单的 Javascript 语句,它作为后面演示的示例代码:
console.log("Hello, world! " + 123);
我们将讨论混淆它的各种方法。为了清楚起见,我们将一次介绍一种混淆技术,并提供一个示例,说明每种技术如何以一种不可读的形式更改此代码。然而,应该注意的是,通常在反抓取网站中使用多种混淆方法。
演示过程中将尝试一些混淆 JS 代码的在线工具。
字符串编码
十六进制字符串编码
打开 Javascript Obfuscator 网站关闭除 「Encode Strings」之外的所有复选框,混淆示例代码:
输出结果如下:
console["\x6C\x6F\x67"]("\x48\x65\x6C\x6C\x6F\x2C\x20\x77\x6F\x72\x6C\x64\x21\x20"+ 123)
硬编码字符串的每个 ASCII 字符都被转换为十六进制形式,可以在计算机程序上进行验证。这很简单因为混淆隐藏东西的方式很弱,在 JavaScript REPL 可以简单地还原:
$ node
Welcome to Node.js v18.5.0.
Type ".help" for more information.
> "\x48\x65\x6C\x6C\x6F\x2C\x20\x77\x6F\x72\x6C\x64\x21\x20"
'Hello, world! '
> "\x6C\x6F\x67"
'log'
另外,我们注意到,在代码的混淆形式中使用了方括号符号 ——console.log
变成了 console["log"]
。因为后一种相对前一种能使用变量,这也是 JS 混淆常用的伎俩。
八进制字符串编码
除了十六进制,还可以用八进制进行编码,比如:
console["\154\157\147"]("\150\145\154\154\157\54\40\167\157\162\154\144\41\40" + "\40\61\62\63")
运算结果:
请注意,八进制转义符在 ES5 中已被弃用,此外,它们在严格模式下会产生语法错误。
Unicode 字符串编码
除了上面两种,我们还可以进行 Unicode 编码,比如:
console["\u006c\u006f\u0067"]("\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0057\u006f\u0072\u006c\u0064\u0021" + "\u0031\u0032\u0033")
关于 JS 编码详情可以学习文章:JavaScript character escape sequences
字符串数组映射
现在让我们取消选中「Encode Strings」并选中「Move Strings」。单击混淆按钮会为我们提供以下代码:
var _0xcd26=["Hello, world! ","log"];console[_0xcd26[1]](_0xcd26[0]+ 123)
我们可以看到代码现在有一个字符串数组,通过在各种索引处引用数组来间接使用这些字符串。
死代码注入
在不改变功能的情况下,可以注入死代码或无法访问的代码,使 Javascript 源代码更大,更难阅读。让我们用 defendjs 试试:
$ defendjs --input hello.js --features dead_code --output .
这将使我们的 JS 代码变成了一团糟:
(function () {
function a(a, d) {
var b = new Array(0);;
var c = arguments;
while (true)
try {
switch (a) {
case 15229:
return;
case 21176:
function e(a, b) {
return Array.prototype.slice.call(a).concat(Array.prototype.slice.call(b));
}
function f() {
var a = arguments[0], c = Array.prototype.slice.call(arguments, 1);
var b = function () {
return a.apply(this, c.concat(Array.prototype.slice.call(arguments)));
};
b.prototype = a.prototype;
return b;
}
function g(a, b) {
return Array.prototype.slice.call(a, b);
}
function h(b) {
var c = {};
for (var a = 0; a < b.length; a += 2) {
c[b[a]] = b[a + 1];
}
return c;
}
function i(a) {
return a.map(function (a) {
return String.fromCharCode(a & ~0 >>> 16) + String.fromCharCode(a >> 16);
}).join('');
}
function j() {
return String.fromCharCode.apply(null, arguments);
}
console.log('Hello, world! ' + 123);
a = 15229;
break;
}
} catch (b) {
$$defendjs$tobethrown = null;
switch (a) {
default:
throw b;
}
}
}
a(21176, {});
}())
我们可以看到我们的原始语句,但它现在嵌套得很深了。在顶层,有一个叫做 IIFE 的东西——立即调用函数表达式——一个在单个语句中定义和调用的 JS 函数。这个函数有两个语句:
a()
带有两个参数的函数声明。- 调用
a()
第一个参数值为 21176 的函数。
如果我们阅读函数的代码,a()
我们可以看到第二个参数被忽略,并且只有一条代码路径指向我们要执行的代码console.log()
,并且它周围有相当多的代码永远无法执行 - 一些函数嵌套在 switch
语句深处并且 try/catch
没有任何出错的可能。此外,它在开始时声明了几个永远不会被使用的变量。
控制流混淆
我们的死代码示例,还演示了另外一种可以使控制流变得混乱的方式 - 控制流混淆。
在无限循环代码 while 语句中,包含 try-catch 结构。下面 try
是一个包含两种情况的 switch 语句:一种用于从函数中返回,另一种用于调用 log 函数,并为变量设置一个值,然后退出循环代码。这引入了一个令人困惑的、迂回的代码路径,它在功能上与我们原来的单行代码相同。
范围混淆
让我们重新运行代码并使用 DefendJS 的 scope
功能:
$ cp hello.js scope.js
$ defendjs --input scope.js --features scope --output .
这为我们提供了以下代码:
(function () {
{
{
function b(a, b) {
return Array.prototype.slice.call(a).concat(Array.prototype.slice.call(b));
}
function c() {
var a = arguments[0], c = Array.prototype.slice.call(arguments, 1);
var b = function () {
return a.apply(this, c.concat(Array.prototype.slice.call(arguments)));
};
b.prototype = a.prototype;
return b;
}
function d(a, b) {
return Array.prototype.slice.call(a, b);
}
function e(b) {
var c = {};
for (var a = 0; a < b.length; a += 2) {
c[b[a]] = b[a + 1];
}
return c;
}
function f(a) {
return a.map(function (a) {
return String.fromCharCode(a & ~0 >>> 16) + String.fromCharCode(a >> 16);
}).join('');
}
function g() {
return String.fromCharCode.apply(null, arguments);
}
}
var a = [];
console.log('Hello, world! ' + 123);
}
}())
这种技术可能看起来像前一种技术的简单版本,但有一个关键的区别:它引入了多个相同的词法作用域范围。例如,a
可能是最内层作用域中第一个函数的参数,或者它可以是第二个函数中的变量,甚至是与我们的日志语句相同作用域中的变量。在我们的简单示例中,很容易看出这一点,因为最内层作用域中的任何函数都没有在任何地方被调用,但在现实世界的情况下不会那么简单。
字面量的重新计算
让我们试试 DefendsJS 的另一个特性:
$ cp hello.js literals.js
$ defendjs --input literals.js --features literals --output .
结果代码是:
(function () {
function c() {
var c = arguments;
var b = [];
b[1] = '';
b[1] += a(72);
b[1] += a(101, 108, 108, 111);
b[1] += a(44, 32, 119, 111);
b[1] += a(114, 108, 100, 33);
b[1] += a(32);
return b[1];
}
{
{
function e(a, b) {
return Array.prototype.slice.call(a).concat(Array.prototype.slice.call(b));
}
function d() {
var a = arguments[0], c = Array.prototype.slice.call(arguments, 1);
var b = function () {
return a.apply(this, c.concat(Array.prototype.slice.call(arguments)));
};
b.prototype = a.prototype;
return b;
}
function f(a, b) {
return Array.prototype.slice.call(a, b);
}
function g(b) {
var c = {};
for (var a = 0; a < b.length; a += 2) {
c[b[a]] = b[a + 1];
}
return c;
}
function h(a) {
return a.map(function (a) {
return String.fromCharCode(a & ~0 >>> 16) + String.fromCharCode(a >> 16);
}).join('');
}
function a() {
return String.fromCharCode.apply(null, arguments);
}
}
var b = [];
console.log(d(c, b)() + 123);
}
}())
在这种情况下,硬编码字符串正在以一种令人困惑的方式重新计算,因此从阅读代码来看它是什么远非显而易见。
因为示例代码简单仔细看还是能看懂的,上面代码只是把 Hello, World!
翻译成 UTF-16 代码单元序列,然后通过 String.fromCharCode()
方法还原,比如 String.fromCharCode("72")
就是大写的 H
,因为序列是数字就可以加入复杂的计算逻辑。
命名重整(Name Mangling)
Mangling 是一种为了优化和混淆目的而缩短变量和属性名称的转换。
考虑以下 JS 代码:
let oneTwoThree = 123;
let hello = "Hello, world! ";
console.log(hello + oneTwoThree);
让我们使用 DefendJS 的修饰功能:
$ cp hello2.js mangling.js
$ defendjs --input mangling.js --features mangle --output .
结果代码是:
(function () {
var a = 123;
var b = 'Hello, world! ';
console.log(b + a);
}())
oneTwoThree
成为a
并重hello
命名为b
. 这并没有使一个微不足道的例子变得更难阅读,而是可以做的另一件事是使大块的 JS 难以理解,同时使包含内联 JS 的 HTML 页面更轻量。开发人员倾向于以表示其含义的方式命名他们的变量,当代码被破坏时,这些含义就会丢失。
代码压缩
这本身并不是混淆技术,但压缩可以从代码中删除缩进、换行符和空格通常作为混淆过程的一部分,与其他技术结合使用。
JSFuck
JSFuck是一种将 JS 代码转换为类似于臭名昭著的 Brainfuck 编程语言的深奥风格的方法。false
成为 ![]
,true
成为 !![]
等等。
将我们的原始 JS 代码转换为 JSFuck 版本后,我们得到如下结果:
![图片转存失败,建议将图片保存下来直接上传 [][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]][([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]((! +[])[+!+[]]+(! +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+([][[]]+[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+!+[]]+(+[ ]+[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+!+[]]]+(! +[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+!+[]+[+!+[]]))[(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]][([][[]]+[])[+!+[]]+( +[])[+!+[]]+((+[])[([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(! +[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[!+[]+!+[]])+( +[])[+!+[]]+( +[])[!+[]+!+[]])()([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]][([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]((! +[])[+!+[]]+(! +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+([][[]]+[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+!+[]]+([]+[])[( +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(! +[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+( +[])[!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+((! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+( +[])[!+[]+!+[]]+(! +[])[!+[]+!+[]+!+[]]+(+(+!+[]+[+!+[]]+(! +[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]+( +[])[!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[+!+[]]+[+[]]+(! +[])[!+[]+!+[]+!+[]]+( +[])[!+[]+!+[]]+( +[])[!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(! +[])[+[]]+[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(! +[])[+!+[]]+( +[])[!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]]+[+[]]+[+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+[+!+[]]+(! +[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]])[( +[])[!+[]+!+[]+!+[]]+(+(!+[]+!+[]+[+!+[]]+[+!+[]]))[(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([]+[])[([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]][([][[]]+[])[+!+[]]+( +[])[+!+[]]+((+[])[([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]+[])[+!+[]+[+!+[]]]+(! +[])[!+[]+!+[]+!+[]]]](!+[]+!+[]+!+[]+[+!+[]])[+!+[]]+( +[])[!+[]+!+[]]+([ ]+[][[]])[+!+[]+[+[]]]+(! +[])[+[]]]((! +[])[+[]])[([][(! +[])[!+[]+!+[]+!+[]]+([][[]]+[])[+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([ ]+[][[]])[+!+[]+[+[]]]+(! +[])[!+[]+!+[]+!+[]]+( +[])[!+[]+!+[]+!+[]]]()+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([ ]+[][[]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]](([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]][([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]((! +[])[+!+[]]+(! +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+([][[]]+[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+!+[]]+( +[+[]])[([ ]+[][[]])[+!+[]+[+[]]]+(! +[])[+[]]+( +[])[+!+[]]+( +[])[!+[]+!+[]]+([ ]+[][[]])[+!+[]+[+[]]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+( +[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]]+ +( +[+[]])[([ ]+[][[]])[+!+[]+[+[]]]+(! +[])[+[]]+( +[])[+!+[]]+( +[])[!+[]+!+[]]+([ ]+[][[]])[+!+[]+[+[]]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+( +[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]])()[([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+( +[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[])[+!+[]]+([][[]]+[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]](( +[+[]])[([ ]+[][[]])[+!+[]+[+[]]]+(! +[])[+[]]+( +[])[+!+[]]+( +[])[!+[]+!+[]]+([ ]+[][[]])[+!+[]+[+[]]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+( +[])[!+[]+!+[]+!+[]]]()[+!+[]+[+[]]])+[])[+!+[]])+([]+[])[( +[])[+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(! +[])[+[]]+([][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]]+[])[!+[]+!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+( +[])[!+[]+!+[]]+(! +[][( +[])[+[]]+( +[])[!+[]+!+[]]+( +[])[+!+[]]+(! +[])[+[]]])[+!+[]+[+[]]]+(! +[])[+!+[]]]()[+!+[]+[!+[]+!+[]]])())
]()```

现在,这实际上是不可读的,但是有一种方法可以,通过执行 AST 操作来消除这种混乱。