什么是JavaScript的内置字符串?

时间:2013-04-12 18:16:47

标签: javascript obfuscation

这个问题很难在问题标题中总结

更新 我创建了一个JSFiddle,它根据从这个问题中提取的字母从输入中构建一个混淆的字符串:你可以访问它here,还是gist会更容易?

我最近在this profile中遇到了一些有趣的混淆JavaScript,看起来像这样:

javascript:[[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+([]+!!-
[])[1<<1]+[/~/+{}][+!1][-~1<<1]+([]+/-/[(!!1+[])[1>>1]+(!!1
+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]+([,][
~1]+[])[1-~1]+[[]+{}][!1.1%1][11111.1%11.1*111e11|!1]+(/1/+
1/[1<1][1%1])[1^11]+[[],[]+{}][1][+1]+(/<</[1]+[])[1/1.1&1]

很抱歉破坏了这个惊喜,但是当评估它时会返回:

"I love you" in Chrome
"I lone you" In Firefox
"I lo[e you" in IE10

分解时的工作方式是生成一系列消息并从中拉出字母(使用“I”作为示例):

[]+1/!1
returns
"Infinity"
then
[[]+1/!1]
creates this array:
["Infinity"]
then
[[]+1/!1][1^1]
Takes the first (1^1 == 0) element of that array
"Infinity"
finally
[[]+1/!1][1^1][1>>1]
Takes the first (1>>1 == 0) char of that string
"I"

生成的其他字符串包括:

({}+[])       -> "[object Object]" (where the space comes from)
([]+!!-[])    -> "false" (used for it's "l")
[/~/+{}][+!1] -> "/~/[object Object]" (this is used for an "o")
(/<</[1]+[])  -> "undefined"

我有兴趣找到“n”和“[”的替代品,并想出了这个:

String.fromCharCode(('1'.charCodeAt(0)<<1)+(10<<1))

我觉得使用1和0的精神,但违反了原始代码的一个更优雅的方面,即完全与字符串无关。是否有其他人知道如何生成与原始混淆代码保持一致的“v”?

以下是一些额外的信息,这些信息是在许多才华横溢的JavaScript程序员深入研究之后发现的

Firefox返回“I lone you”因为这一行:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]+

[1^11<<1]修剪一个特定字符:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])

对此进行评估:

"function test() {
    [native code]
}"

看起来我们可能有“V”!!!

Chrome会返回“我爱你”,因为相同的代码会返回:

"function test() { [native code] }"

在问题因“真正的编程问题”而被关闭之前,我认为我会添加一个基于@Supr's@Cory's@alpha123's构建的摘要解决方案:

alert([[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+(
[]+!!-[])[1<<1]+[/~/+{}][+!1][-~1<<1]+[([]+/-/[(
!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(
!!1+[])[1^1]])[1+(1^(11+1+1)<<1)],([]+/-/[(!!1+[
])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[
])[1^1]])[1^11<<1],([]+/-/[(!!1+[])[1>>1]+(!!1+[
])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11
+1+1)<<1]][((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<
1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1<<1<<1<<1
)+1<<1]==({}+[])[1^1])*1)+((([]+/-/[(!!1+[])[1>>
1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1
]])[(1^11<<1)-1]==({}+[])[1^1])<<1)]+([,][~1]+[]
)[1-~1]+[[]+{}][!1.1%1][11111.1%11.1*111e11|!1]+
(/1/+1/[1<1][1%1])[1^11]+[[],[]+{}][1][+1]+(/<</
[1]+[])[1/1.1&1])

鉴于代码的复杂性及其产生的消息,它几乎就像JavaScript引擎告诉你有多特别感觉:)

7 个答案:

答案 0 :(得分:83)

首先,我要感谢杰森和所有贡献者玩这个有趣的片段。我已经写了那段代码只是为了好玩以便在2月14日将它发送给我的妻子:)在笔记本电脑上只安装了Chrome我无法检查它在Firefox和IE中是如何工作的。此外,我并没有真正期望内置方法的toString()表示在其他浏览器中看起来可能有所不同。

现在,转向真正的问题,让我们来看看代码。是的,"v"是真正的“问题”。除了解析[native code]字符串之外,我找不到其他方法来获取此字母,这可以从任何内置方法中获取。由于除了使用1之外没有字符串和数字限制自己,我需要利用一些在名称中只有可用字符的方法。

可以从现有关键字和字符串表示中获取可用字符,即从一开始我们NaNnullundefinedInfinitytruefalse"[object Object]"。其中一些可以很容易地转换为字符串,例如1/!1+[]提供"Infinity"

我分析了数组[],对象{},正则表达式/(?:)/,数字1.1,字符串"1"和已发现的不同内置方法一个名为test()RegExp对象的漂亮方法。它的名称可以从所有可用的字符组合,例如来自"t"的{​​{1}}和"e"以及来自true的{​​{1}}。我创建了一个字符串"s",并使用正方形文字false的方括号表示法来解决此方法,在此行中正确标识:

"test"

如前所述,这段代码在Chrome中评估为:

/-/
在Firefox中

/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]]

并在IE中:

function test() { [native code] }

(后者支付特殊注意function test() { [native code] } 关键字之前的空格

因此,正如您清楚地看到的那样,我的代码从呈现的字符串中获得了第24个字符,在Chrome中 function test() { [native code] } (按计划),但不幸的是在Firefox和IE中function"v"分别。

为了在所有浏览器中生成相同的输出,我使用了不同的方法,而不是其他答案中所示。现在修改后的版本看起来像这样:

"n"

然而,为了激发读者的兴趣,我不会为此提供解决方案。老实说,我相信你会很容易理解它是如何运作的......有些人甚至可以用跨浏览器的方式惊喜他们心爱的人;)

P.S。 Yet Another Obfuscator

受到Jason创建通用混淆工具的想法的启发,我又写了一篇。您可以在 JSBin:http://jsbin.com/amecoq/2 找到它。它可以混淆包含数字"[",小拉丁字母javascript:[[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+([]+!!- [])[1<<1]+[/~/+{}][+!1][-~1<<1]+/\[[^1]+\]/[([]+![])[1<<1<< 1]+(/|/[(1+{})[1+11>>>1]+[[]+{}][+!1][1]+([]+1/[])[1<<1>>1] +([1<1]+[])[1+11>>>1+1]+[[!!1]+1][+[]][1-1]+([]+!!/!/)[1|1] +(/1/[1]+[])[!1%1]+(-{}+{})[-1+1e1-1]+(1+[!!1])[1]+([]+1+{} )[1<<1]+[!!/!!/+[]][+[]][1&1]]+/=/)[1e1+(1<<1|1)+(([]+/-/[( !!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1 ]])[1^1]==+!1)]+(!![]+{})[1|1<<1]+[1+{}+1][!1+!1][(11>>1)+1 ]](([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+ (!!1+[])[1^1]]))[1&.1][11>>>1]+([,][~1]+[])[1-~1]+[[]+{}][! 1.1%1][11111.1%11.1*111e11|!1]+(/1/+1/[1<1][1%1])[1^11]+[[] ,[]+{}][1<<1>>>1][1||1]+(/[<+>]/[1&1|1]+[1.1])[1/11.1&1.11] 和空格的任何文本。字符串长度主要受限于你的RAM(至少我的答案的主体被成功地混淆了)。 Chrome,Firefox和IE支持输出。

提示:该工具使用与上述不同的混淆方法。

答案 1 :(得分:26)

为什么问题的native code位没有被使用?这个在Chrome和Firefox中都提供'v'

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]>([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]?([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]:([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]

编辑以支持IE并在没有三元运算符的情况下执行此操作: 这个适用于Chrome,IE和FF。构建一个数组并使用==来确定浏览器。

[([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1+(1^(11+1+1)<<1)],([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1],([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]][((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1<<1<<1<<1)+1<<1]==({}+[])[1^1])*1)+((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)-1]==({}+[])[1^1])<<1)]

可读:

[
    //ie
    ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1+(1^(11+1+1)<<1)],
    //ch
    ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1],
    //ff
    ([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^(11+1+1)<<1]
]
[
    //ch?
    ((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1<<1<<1<<1)+1<<1]==({}+[])[1^1])*1)+
    //ff?
    ((([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)-1]==({}+[])[1^1])<<1)
]

答案 2 :(得分:8)

这是我能得到的尽可能接近,不幸的是,它通过拨打unescape()违反了原始混淆的惯例:

unescape((/%/+[])[1]+(/1/[1]+[])[1%1]+(+!1)+(+!1)+(1e1+(11*(1-~1)<<1)))

拆解:

(/%/+[])[1]          => "%"
(/1/[1]+[])[1%1]     => "u"
(+!1)                => "0"
(+!1)                => "0"
(1e1+(11*(1-~1)<<1)) => "76"
===========================
unescape("%u0076")   => "v"

其他想法:

  1. 以某种方式进入unescape("\x76")
  2. 以某种方式转换118而不调用String.fromCharCode()
  3. 从异常中获取带有“无效”字样的文本
  4. <强>更新

    我开始玩代码高尔夫并且一直在缩短代码,用更多1等替换部件。

答案 3 :(得分:4)

这是生成n / v的部分:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1^11<<1]

在Firefox中,([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])评估为

"function test() {
    [native code]
}"

在Chrome中,它是

"function test() { [native code] }"

1^11<<1等于23.因此,由于Firefox的额外空白,这还不足以进入&#39; v&#39;而是&#39; N'#39;

这就是为什么你不应该依赖Function#toString行为。 ;)

编辑: 最后,我找到了一个合理混淆的跨浏览器版本:

[[]+1/!1][1^1][1>>1]+({}+[])[1<<1^11>>1]+([]+!!-[])[1<<1]+[/~/+{}][+!1][-~1<<1]+([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)+(parseInt("010")<10?(1+1+1+1):0)]+([,][~1]+[])[1-~1]+[[]+{}][!1.1%1][11111.1%11.1*111e11|!1]+(/1/+1/[1<1][1%1])[1^11]+[[],[]+{}][1][+1]+(/<</[1]+[])[1/1.1&1]

这会将n / v部分替换为:

([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[(1^11<<1)+(parseInt("010")<10?(1+1+1+1):0)]

利用parseInt中的差异(显然Firefox会解析以0开头的数字作为八进制,而Chrome不会在Firefox的情况下添加4),从而获得&#39; v&#39;来自&#39; native&#39;在这两种情况下(我都找不到另一个&#39; v&#39;:P) parseInt看起来有点不合适,但这是我现在能做的最好的事情。

答案 4 :(得分:4)

对于一般用例,如果字符大小不是一个大问题,我可能会倾向于作弊。

创建功能&#34; c&#34;它将数字0 .. 25变成一个字符。

c=function(v){for(var i in window){for(var ci in i){if(parseInt(i[ci],(10+11+11)+(1<<1)+(1<<1))==(v+10)){return i[ci]}}}};

出于性能原因,如果需要,请预先缓存字母。

l=[];for(var i=0; i<(11+11)+(1<<1)+(1<<1);i++){l[i]=c(i);}

在Chrome控制台中,生成的数组如下所示:

> l;
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "K", "l", "m", "n", "o", "p", "q", "r", "S", "t", "u", "v", "w", "x", "y", "Z"]

所以......你的 v 可能是l[10+10+1]

或者,像这样的一般解决方案:

p=(function(){10%11}+[])[1+11+(1<<1)]; // "%"
u=(function(){club=1}+[])[1+11+(1<<1)]; // "u"
vc=p+u+(0+[])+(0+[])+((111>>1)+11+10+[]); // "%u0076"
unescape(vc);

或者,对于此特定的问题,可能只是:

(function(){v=1}+[])[10+(1<<1)]; // "v"

答案 5 :(得分:3)

这在Chrome中提供了一个v:

Object.getOwnPropertyNames(Object)[17][3];

这是在Firefox中做到的:

Object.getOwnPropertyNames(Object)[9][3]

他们都将其从Object.prototype.preventExtensions()中删除,因此您可能会找到一种跨浏览器方式来引用该方法。 (对于初学者来说,它是Object.Prototype中唯一的17个字符的名称。)

随意建立一个更加混淆的版本并为自己拿走所有功劳,我没时间;)

答案 6 :(得分:2)

在chrome中,表达式([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])的计算结果为"function test() { [native code] }"[1^11<<1]的计算结果为23(按位运算符会导致变量被截断为32位)