1

这是这个问题的延续,更困难的情况。假设我想用 2 个参数调用字符串函数,例如

console.log(
  "truefalse".replace("true",1)
)

在第一步中,我将字符集减少为jsfuck约定,其中我们有 6 个可用字符:[]()!+并且 az 字母和数字被"字符包围 - JS 字符串(很容易转换为这 6 个字符):

console.log(
  "truefalse"["replace"]("true","1")
)

这里的问题是逗号(禁止字符),但我们可以通过使用trincot发现的以下巧妙技术来克服这个问题:

console.log(
  ["true"]["concat"]("1")["reduce"](""["replace"]["bind"]("truefalse"))
)

但新的问题出现了:

可以调用具有 2 个(或更多)参数的函数序列而不嵌套它们(这是由上述技术强加的),但是以“流动”方式,我们在右侧调用下一个函数,例如"truefalse".replace("true",1).replace("false",0).. :(不使用 'eval' 之类的将字符串解释为代码的解决方案)?(对于具有一个参数的函数,例如"truefalse"["replace"]("true")["replace"]("false"):)

4

1 回答 1

2

是的,有可能。

所以我们从省略逗号的表达式开始,它只包含字符串文字和 JSF 字符:

["true"]["concat"]("1")["reduce"](""["replace"]["bind"]("truefalse"))

一会儿,我将使用更易读的点符号来表达这个表达式,然后回到数组​​文字的逗号分隔符:

["true", "1"].reduce("".replace.bind("truefalse"))

这具有替换的输入,即“真假”,位于最后。另一方面,参数位于左侧,即“真”和“1”。我们可以尝试使“真假”也成为一个论点,这样我们就可以将它移到左边。

为此,我们可以使用"".replace.apply而不是"".replace作为回调来reduce. 的第一个参数apply是调用的this-binding replace。第二个参数应该是要传递给的参数数组replace,这就是我们当前在左边的数组。

然后apply方法本身也应该得到一个this-binding。我们得到这个表达式:

console.log(
    ["truefalse", ["true", "1"]].reduce("".replace.apply.bind("".replace))
);

注意:"".replace.apply可以引用任何其他函数而不是replace,只要它是一个函数。我们只需要一种引用Function.prototype.apply函数的方法。

因此,我们成功地将“truefalse”表达式移到了前面。但如果我们想实现非嵌套链接,它真的不应该放在数组文字中。

这里我们可以使用该方法的一个“特性” split:如果不传递任何参数,它会返回一个带有原始字符串的数组。正是我们需要的。

所以:

console.log(
    "truefalse".split().concat([["true", "1"]]).reduce("".replace.apply.bind("".replace))
);

现在我们可以连锁了!

因此,最后,这是删除点和逗号的相同表达式:

console.log(
  "truefalse"["split"]()["concat"]([["true"]["concat"]("1")])
    ["reduce"](""["replace"]["apply"]["bind"](""["replace"]))
);

...并链接,您只需使用["split"]()...etc 继续表达式。

于 2020-08-26T19:33:10.167 回答