这是一小段警告“Hello world”的JavaScript代码:
゚ω゚ノ=/`m´)ノ~┻━┻//*´∇`*/['_'];o=(゚ー゚)=_=3;c=(゚Θ゚)=(゚ー゚)-(゚ー゚);(゚Д゚)=(゚Θ゚)=(o^_^o)/(o^_^o);(゚Д゚)={゚Θ゚:'_',゚ω゚ノ:((゚ω゚ノ==3)+'_')[゚Θ゚],゚ー゚ノ:(゚ω゚ノ+'_')[o^_^o-(゚Θ゚)],゚Д゚ノ:((゚ー゚==3)+'_')[゚ー゚]};(゚Д゚)[゚Θ゚]=((゚ω゚ノ==3)+'_')[c^_^o];(゚Д゚)['c']=((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)-(゚Θ゚)];(゚Д゚)['o']=((゚Д゚)+'_')[゚Θ゚];(゚o゚)=(゚Д゚)['c']+(゚Д゚)['o']+(゚ω゚ノ+'_')[゚Θ゚]+((゚ω゚ノ==3)+'_')[゚ー゚]+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+((゚ー゚==3)+'_')[゚Θ゚]+((゚ー゚==3)+'_')[(゚ー゚)-(゚Θ゚)]+(゚Д゚)['c']+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+(゚Д゚)['o']+((゚ー゚==3)+'_')[゚Θ゚];(゚Д゚)['_']=(o^_^o)[゚o゚][゚o゚];(゚ε゚)=((゚ー゚==3)+'_')[゚Θ゚]+(゚Д゚).゚Д゚ノ+((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)]+((゚ー゚==3)+'_')[o^_^o-゚Θ゚]+((゚ー゚==3)+'_')[゚Θ゚]+(゚ω゚ノ+'_')[゚Θ゚];(゚ー゚)+=(゚Θ゚);(゚Д゚)[゚ε゚]='\\';(゚Д゚).゚Θ゚ノ=(゚Д゚+゚ー゚)[o^_^o-(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ+'_')[c^_^o];(゚Д゚)[゚o゚]='\"';(゚Д゚)['_']((゚Д゚)['_'](゚ε゚+(゚Д゚)[゚o゚]+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚Θ゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚ー゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)-(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚])(゚Θ゚))('_');
好看的版本:
゚ω゚ノ = /`m´)ノ~┻━┻//*´∇`*/['_'];
o = (゚ー゚) = _ = 3;
c = (゚Θ゚) = (゚ー゚) - (゚ー゚);
(゚Д゚) = (゚Θ゚) = (o^_^o)/(o^_^o);
(゚Д゚) = {
゚Θ゚: '_',
゚ω゚ノ: ((゚ω゚ノ==3)+'_')[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ+'_')[o^_^o-(゚Θ゚)],
゚Д゚ノ: ((゚ー゚==3)+'_')[゚ー゚]
};
(゚Д゚)[゚Θ゚] = ((゚ω゚ノ==3)+'_')[c^_^o];
(゚Д゚)['c'] = ((゚Д゚)+'_')[(゚ー゚)+(゚ー゚)-(゚Θ゚)];
(゚Д゚)['o'] = ((゚Д゚)+'_')[゚Θ゚];
(゚o゚)=(゚Д゚)['c'] + (゚Д゚)['o'] + (゚ω゚ノ + '_')[゚Θ゚] + ((゚ω゚ノ==3) + '_')[゚ー゚] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚==3) + '_')[゚Θ゚] + ((゚ー゚==3) + '_')[(゚ー゚) - (゚Θ゚)] + (゚Д゚)['c'] + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + (゚Д゚)['o'] + ((゚ー゚==3) + '_')[゚Θ゚];
(゚Д゚)['_'] = (o^_^o)[゚o゚][゚o゚];
(゚ε゚) = ((゚ー゚==3) + '_')[゚Θ゚] + (゚Д゚).゚Д゚ノ + ((゚Д゚) + '_')[(゚ー゚) + (゚ー゚)] + ((゚ー゚==3) + '_')[o^_^o-゚Θ゚] + ((゚ー゚==3) + '_')[゚Θ゚] + (゚ω゚ノ+'_')[゚Θ゚];
(゚ー゚) += (゚Θ゚);
(゚Д゚)[゚ε゚] = '\\';
(゚Д゚).゚Θ゚ノ = (゚Д゚+゚ー゚)[o^_^o-(゚Θ゚)];
(o゚ー゚o) = (゚ω゚ノ+'_')[c^_^o];
(゚Д゚)[゚o゚] = '\"';
(゚Д゚)['_']((゚Д゚)['_'](゚ε゚+(゚Д゚)[゚o゚]+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚Θ゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+(゚ー゚)+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(c^_^o)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚Θ゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+((゚ー゚)+(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚ー゚)+(c^_^o)+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)-(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+((゚ー゚)+(o^_^o))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((o^_^o)+(o^_^o))+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+(゚Θ゚)+((゚ー゚)+(゚Θ゚))+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚Θ゚)+(゚ー゚)+(゚ー゚)+(゚Д゚)[゚ε゚]+(゚ー゚)+((o^_^o)-(゚Θ゚))+(゚Д゚)[゚ε゚]+((゚ー゚)+(゚Θ゚))+(゚Θ゚)+(゚Д゚)[゚o゚])(゚Θ゚))('_');
摘自此处: https://codegolf.stackexchange.com/questions/23975/obfuscation-challenge/24041#24041
它是如何工作的?我甚至没有在该代码中看到alert
。
答案 0 :(得分:110)
在仔细查看代码之前,您必须知道,因为JavaScript 1.5 identifiers不仅包含ASCII字符,还包含Unicode字符。
在这种情况下,许多这些有趣的序列只是标识符。在通过更简单的标识符交换这些标识符并删除不必要的注释和括号之后,代码如下所示:
a = /`m´)ノ~┻━┻/['_'];
o = b = _ = 3;
c = d = b-b;
e = d = o^_^o/o^_^o;
e = {
d: '_',
a: ((a==3)+'_')[d],
h: (a+'_')[o^_^o-d],
i: ((b==3)+'_')[b]
};
e[d] = ((a==3)+'_')[c^_^o];
e['c'] = (e+'_')[b+b-d];
e['o'] = (e+'_')[d];
f = e['c']+e['o']+(a+'_')[d]+((a==3)+'_')[b]+(e+'_')[b+b]+((b==3)+'_')[d]+((b==3)+'_')[b-d]+e['c']+(e+'_')[b+b]+e['o']+((b==3)+'_')[d];
e['_'] = (o^_^o)[f][f];
g = ((b==3)+'_')[d]+e.i+(e+'_')[b+b]+((b==3)+'_')[o^_^o-d]+((b==3)+'_')[d]+(a+'_')[d];
b += d;
e[g] = '\\';
e.j = (e+b)[o^_^o-d];
obo = (a+'_')[c^_^o];
e[f] = '\"';
e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_');
现在我们可以一次评估每个语句:
a = /`m´)ノ~┻━┻/['_']
评估为a = undefined
o = b = _ = 3
分配o
,b
和_
整数3
c = d = b-b
分配c
和d
整数0
e = d = o^_^o/o^_^o
分配e
和d
整数1
(o^_^o
评估为3 XOR 3 XOR 3,产生3)e = { d: '_', a: ((a==3)+'_')[d], h: (a+'_')[o^_^o-d], i: ((b==3)+'_')[b] }
指定e
对象{ d: '_', a: 'a', h: 'd', i: 'e' }
e[d] = ((a==3)+'_')[c^_^o]
指定e[1]
字符串'f'
e['c'] = (e+'_')[b+b-d]
指定e['c']
字符串'c'
e['o'] = (e+'_')[d]
指定e['o']
字符串'o'
这只是设置,并设置了以下变量:
a = undefined
b = 3
c = 0
d = 1
e = {
1: "f",
a: "a",
c: "c",
d: "_",
h: "d",
i: "e",
o: "o"
}
下一个陈述是第一个构造东西的陈述:
f = e['c'] + // => "c"
e['o'] + // => "o"
(a+'_')[d] + // => "undefined_"[1] = "n"
((a==3)+'_')[b] + // => "false_"[3] = "s"
(e+'_')[b+b] + // => "object_"[6] = "t"
((b==3)+'_')[d] + // => "true_"[1] = "r"
((b==3)+'_')[b-d] + // => "true_"[2] = "s"
e['c'] + // => "c"
(e+'_')[b+b] + // => "object_"[6] = "t"
e['o'] + // => "o"
((b==3)+'_')[d]; // => "true"[1] = "r"
所以f = "constructor"
。在下一个语句中,"constructor"
用于检索函数:
e['_'] = (o^_^o)[f][f]
这相当于(3).constructor.constructor
,产生function Function
,因此:
e['_'] = Function
这个Function
函数是特殊的,因为可以通过参数传递函数体代码来动态构造函数:
f = Function("alert(1)")
// equivalent to
f = function() { alert(1) }
我将跳过接下来的几个语句,然后编写结果变量和值:
a = undefined
b = 4
c = 0
d = 1
e = {
1: "f",
_: Function,
a: "a",
c: "c",
constructor: "\"",
d: "_",
h: "d",
i: "e",
j: "b",
o: "o",
return: "\\"
}
f = "constructor"
obo = "u"
最后一个陈述完成了最后的工作:
e['_'](e['_'](g+e[f]+e[g]+d+b+d+e[g]+d+(b+d)+b+e[g]+d+b+(b+d)+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+((o^_^o)+(o^_^o))+b+e[g]+(b+d)+(c^_^o)+e[g]+b+((o^_^o)-d)+e[g]+d+d+(c^_^o)+e[g]+d+b+(b+d)+e[g]+d+(b+d)+b+e[g]+d+(b+d)+b+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+b+(c^_^o)+e[g]+d+((o^_^o)-d)+(b+(o^_^o))+e[g]+d+(b+d)+(b+(o^_^o))+e[g]+d+((o^_^o)+(o^_^o))+((o^_^o)-d)+e[g]+d+(b+d)+b+e[g]+d+b+b+e[g]+b+((o^_^o)-d)+e[g]+(b+d)+d+e[f])(d))('_');
这相当于:
Function(Function( … )(1))('_')
long表达式构建以下字符串:
return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"
转义字符串的评估结果为:
alert("Hello World")
此return
代码传递给Function
,它会创建一个匿名函数,如:
function anonymous() {
return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51";
}
我们知道,这相当于:
function anonymous() {
return"alert(\"Hello World\")";
}
然后以1
为参数执行此函数,返回结果字符串:
alert("Hello World")
然后再将其传递给Function
,这将创建一个新的匿名函数:
function anonymous() {
alert("Hello World");
}
最后,还使用'_'
作为参数调用此函数。
答案 1 :(得分:15)
这里有很多东西。变量附近的括号不起作用。
基本上他构造了这个字符串:
return"\141\154\145\162\164\50\42\110\145\154\154\157\40\127\157\162\154\144\42\51"
这是
的转义版本return "alert(\"Hello World\")"
最后这样做:
Function(Function('return "alert(\\"Hello World\\")"')())()
双Function
似乎是一件随意的事,但事实并非如此。 Function()
将字符串中的反斜杠解释为转义字符。所以第一个调用解码,第二个调用执行。
Function("return '\\110\\145\\154\\154\\157'")()
// => "Hello"
这是相同的代码,更好的格式化,以及“普通”变量名称;
var1=/`m´)ノ~┻━┻//*´∇`*/['_'];
three=(threeThenFour)=_=3;
c=(one)=(threeThenFour)-(threeThenFour);
(anObject)=(one)=(three)/(three);
(anObject)={
one:'_',
var1:((var1==3)+'_')[one],
var2ノ:(var1+'_')[three-(one)],
var4ノ:((threeThenFour==3)+'_')[threeThenFour]
};
(anObject)[one]=((var1==3)+'_')[c ^ _ ^ three];
(anObject)['c']=((anObject)+'_')[(threeThenFour)+(threeThenFour)-(one)];
(anObject)['three']=((anObject)+'_')[one];
(theConstructor)=(anObject)['c']+
(anObject)['three']+
(var1+'_')[one]+
((var1==3)+'_')[threeThenFour]+
((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
((threeThenFour==3)+'_')[one]+
((threeThenFour==3)+'_')[(threeThenFour)-(one)]+
(anObject)['c']+
((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
(anObject)['three']+
((threeThenFour==3)+'_')[one];
// theConstructor => "constructor"
(anObject)['_']=(three)[theConstructor][theConstructor];
(theReturn)=((threeThenFour==3)+'_')[one]+
(anObject).var4ノ+
((anObject)+'_')[(threeThenFour)+(threeThenFour)]+
((threeThenFour==3)+'_')[three-one]+
((threeThenFour==3)+'_')[one]+
(var1+'_')[one];
// theReturn => "return"
(threeThenFour)+=(one);
(anObject)[theReturn]='\\';
(anObject).var3ノ=(anObject+threeThenFour)[three-(one)];
(ovar2o)=(var1+'_')[c ^ _ ^ three];
(anObject)[theConstructor]='\"';
// (anObject)['_'] => Function
(anObject)['_'](
(anObject)['_'](theReturn+
(anObject)[theConstructor]+
(anObject)[theReturn]+
(one)+
(threeThenFour)+
(one)+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+(
threeThenFour)+
((threeThenFour)+(one))+
(anObject)[theReturn]+
(one)+
((three)+(three))+
((three)-(one))+
(anObject)[theReturn]+
(one)+
((three)+(three))+
(threeThenFour)+
(anObject)[theReturn]+
((threeThenFour)+(one))+
(c ^ _ ^ three)+
(anObject)[theReturn]+
(threeThenFour)+((three)-(one))+
(anObject)[theReturn]+
(one)+(one)+
(c ^ _ ^ three)+
(anObject)[theReturn]+
(one)+
(threeThenFour)+
((threeThenFour)+(one))+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
((threeThenFour)+(three))+
(anObject)[theReturn]+
(threeThenFour)+
(c ^ _ ^ three)+
(anObject)[theReturn]+
(one)+
((three)-(one))+
((threeThenFour)+(three))+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
((threeThenFour)+(three))+
(anObject)[theReturn]+
(one)+
((three)+(three))+
((three)-(one))+
(anObject)[theReturn]+
(one)+
((threeThenFour)+(one))+
(threeThenFour)+
(anObject)[theReturn]+
(one)+
(threeThenFour)+
(threeThenFour)+
(anObject)[theReturn]+
(threeThenFour)+
((three)-(one))+
(anObject)[theReturn]+
((threeThenFour)+(one))+
(one)+
(anObject)[theConstructor]
)
(one)
)('_');
答案 2 :(得分:9)
让我解释一下关键步骤:
代码创建一个名为Д的对象,然后添加一个属性'_'
,其值为magic JavaScript Function constructor。在JavaScript中,您可以将任何字符串作为代码执行,方法是将其传递给Function构造函数。
(゚Д゚)['_']
如何包含Function构造函数?这是通过以下方式完成的聪明技术:
(゚Д゚)['_'] = (o^_^o)[゚o゚][゚o゚];
这里o和_设置为3.所以o^_^o
返回3.显然作者可能刚刚使用了o因为o^_^o
返回相同的值,但我猜他对混淆有很好的品味:) 。所以上面的表达式现在变为(3)[゚o゚][゚o゚]
。
方括号中゚o゚
的值设置为由前一语句中的连接构建的字符串“constructor”。它使用一种非常聪明的方法来构建字符串“constructor”,方法是从内置的JavaScript字符串中删除单个字符,例如“object”,“true”,“false”和“undefined”,它们是从转换为字符串的JavaScript表达式生成的。显然作者找不到字符“c”来从这些内置字符串中剔除,所以他必须明确地写出那个字符串。请注意,方括号中的字符是゚o゚,它是Unicode字符,而不是圆括号中使用的简单o,尽管两者看起来非常相似。执行(3)("constructor")
后,它会返回Number constructor function。 Number构造函数的构造函数是Function构造函数。因此,通过执行(3)("constructor")("constructor")
,您将获得Function构造函数,现在您最终可以传递任意字符串来执行它。
最后一行构建字符串"alert(\"Hello World\")"
并将其传递给Function构造函数以执行。
问题是如何在不键入实际字母的情况下获取字符串"alert(\"Hello World\")"
?聪明的技巧是使用\xxx
,其中xxx是八进制数并转换为一个字符。要获得此字符串,您需要的数字是0,1,2,3,4,5,6,7和8.但实际上并不需要所有这些,而是可以通过三个数字0的简单算法生成它们例如,要在“alert”中生成字符'a'
,您需要ASCII十进制97或八进制141,即\141
。如果只有0,1和4存储在上面对象的某个属性中,则可以将它们连接起来以生成'a'
。这样你就可以生成任何字符串,即使你拥有的所有字符串都是0,1和4存储在Д对象的某些属性中。聪明?你敢打赌!