什么是 JavaScript 的内置字符串?

IT技术 javascript obfuscation
2021-03-05 22:14:16

这个问题很难用问题标题来概括

更新 我创建了一个 JSFiddle,它根据从这个问题中提取的字母从你的输入中构建一个混淆的字符串:你可以在这里访问它,或者一个要点会更容易吗?

我最近在这个配置文件中发现了一个有趣的混淆 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 返回“我孤独你”:

([]+/-/[(!!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的@科里@ alpha123的,看哪:

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 引擎在告诉你让它感觉有多特别:)

6个回答

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

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

可用的字符可以从现有的关键字和字符串表示中获得,即从我们有NaN, null, undefined, Infinity, true, false, 和 开始"[object Object]"其中一些可以轻松转换为字符串,例如1/!1+[]给出"Infinity"

我分析了数组[]、对象{}、正则表达式/(?:)/、数字1.1、字符串的不同内置方法"1",并发现了一种漂亮的RegExp对象方法,称为test(). 它的名称可以由所有可用字符组合而成,例如"t"and "e"fromtrue"s"from false我创建了一个字符串"test"并使用方括号表示法处理了这个方法/-/,在这一行中正确标识了正则表达式文字

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

正如已经讨论过的,这段代码在 Chrome 中被评估为:

function test() { [native code] }

在 Firefox 中为:

function test() {
    [native code]
}

在 IE 中为:

 function test() {     [native code] }  

(在后者中要特别注意function关键字前的空格

因此,正如您清楚地看到的那样,我的代码正在从显示的字符串中获取第 24 个字符,这在 Chrome 中是"v"(按计划),但不幸的是在 Firefox 和 IE 中——"n"以及"["分别。

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

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]

但是,为了引起读者的兴趣,我不会为此提供解决方案。老实说,我相信你会很容易理解它是如何工作的......有些甚至可以跨浏览器的方式让他们心爱的人大吃一惊;)

PS又一个混淆器

受到 Jason 创建通用混淆工具的想法的启发,我又写了一个。您可以在JSBin 上找到它http : //jsbin.com/amecoq/2它可以混淆任何包含数字[0-9]、小拉丁字母[a-z]和空格的文本字符串长度主要受您的 RAM 限制(至少我的答案正文已成功混淆)。Chrome、Firefox 和 IE 支持输出。

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

@JasonSperske 这是一个不错的技巧!做得好!我会努力为它做出贡献。
2021-04-26 22:14:16
“构造函数”... 哇,太神奇了,您保留了带有有效换行符的完美矩形。你很好
2021-04-30 22:14:16
我创建了一个混淆器,它创建了一个符合您的样式规则的字符串:jsfiddle.net/w9rFF/8
2021-05-02 22:14:16

为什么不native code使用问题中位?这个'v'在 Chrome 和 Firefox 中都给出了

([]+/-/[(!!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)
]
小吹毛求疵:三级算子是第三重要的算子,仅次于一级和二级。采用三个操作数的运算符是三元的。
2021-04-18 22:14:16
这个想法是只选择两个nandv并且只选择最大的那个str[23]>str[27]?str[23]:str[27]换句话说,三级运算符就是诀窍。也可以扩展以支持 IE:([]+/-/[(!!1+[])[1>>1]+(!!1+[])[1<<1^1]+(!1+[])[1|1<<1]+(!!1+[])[1^1]])[1+(1^(11+1+1)<<1)]
2021-04-19 22:14:16
这太有趣了。最初,Firefox 和 Chrome 之间无法预测“本机代码”一词的位置已被驳回。这解决了这个问题,但在 IE10 中不起作用(它返回“i”)。我仍然想知道这个选项是否可以提供一些新的想法
2021-05-02 22:14:16
@EricLippert,呃,我什至用谷歌搜索以确保我使用了正确的术语,但我最终还是用错了一个!谢谢,更正。
2021-05-04 22:14:16
您的答案是第一个(在原始代码的创建者之前),但我觉得他的答案最合乎逻辑地被认为是正确的。仍然很棒(而且当之无愧的 13 票)
2021-05-11 22:14:16

这几乎是我所能得到的,不幸的是,它通过调用以下方法违反了原始混淆的约定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. 从其中包含“无效”一词的异常中获取文本

更新:

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

我也喜欢这个。我在选择一个“正确”的答案时有点纠结,因为你和@alpha123 的答案看起来都非常模糊,并且巧妙地隐藏了最初的意图。
2021-04-16 22:14:16
和 IE10 支持达成协议(真诚地道歉@alpha123 的优秀答案)
2021-04-21 22:14:16
您可以'%'通过(/%/+[[]+1/!1])[1]删除任何引号来替换它我还添加了l=unescape;使用小写字母L来隐藏对unescape. 这很有趣:)
2021-04-29 22:14:16
@JasonSperske:更短: (/%/+[])[1]
2021-05-02 22:14:16
或者你可以命名你的变量$1
2021-05-07 22:14:16

这是生成 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 的额外空格,这还不足以到达“v”,而是“n”。

这就是为什么您不应该依赖 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,从而在两种情况下从 'native' 获得 'v'(我找不到另一个 'v ':P)。
parseInt 看起来有点不合适,但这是我现在能做的最好的。

问题是 Does anyone else have an idea of how to generate a "v" that is in keeping with the original obfuscated code?
2021-04-16 22:14:16
@Ian - 那么大概, [(1^11<<1)+1+1+1+1] 会做吗?
2021-05-01 22:14:16
@JanDvorak - 我目前没有 FF。它评估什么?如果我可以如此冒昧地问,那就是。
2021-05-03 22:14:16
谢谢。现在我正试图找出一种跨浏览器的方式来做到这一点......“V”是一个令人惊讶的罕见字母......
2021-05-13 22:14:16
@enhzflep 抱歉,我的意思是“另一方面,这在 Chrome 中不起作用”
2021-05-14 22:14:16

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

创建函数“c”,它将数字 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"