如何使用这个javascript正则表达式混淆算法?

时间:2014-04-23 19:23:57

标签: javascript regex algorithm compression obfuscation

我在js1k比赛中看到了一个演示,我对这种混淆算法感到惊讶。 有人可以解释它是如何工作的吗?我得到了混淆结果,但我无法理解其工作原理(混淆算法) 这是什么巫术? LOL

我已经提取了这个:

for(
    encoded_string = '... encoded string ...';
    g = /[^ -IM[-~]/.exec(encoded_string);
){
    encoded_string = encoded_string.split(g).join(encoded_string.split(g).shift());
}

// ... Use encoded_string to do what you want

我认为可能重点在于REGEXP。

原始代码(http://js1k.com/2014-dragons/details/1854

如果您愿意,可以在此处查看混淆的结果(http://jsbin.com/xeruqita/1/edit) 我添加了第一个var行。

1 个答案:

答案 0 :(得分:1)

基本上,这个逻辑似乎从一个字符串中去掉一组字符的每个实例,并返回" clean"字符串。

我无法确定要移除的字符组(^ -IM[-~)有什么特别之处,但我可以引导您完成他们正在做的事情。 。

  • 设置for循环

    for(
    
  • 初始化循环变量

        encoded_string = '... encoded string ...';
    
  • 设置循环条件。 。 。注意:exec()如果没有匹配则返回null,而null将评估为false,结束循环

        g = /[^ -IM[-~]/.exec(encoded_string);
    
  • 结束循环条件

    )
    
  • 下一步有多个部分。 。 。让我逐步完成它

    {
        encoded_string = encoded_string.split(g).join(encoded_string.split(g).shift());
    }
    
  • 在每个循环中,获取exec(g)的结果并将其用作分割原始encoded_string的输入(这在两个地方完成)。

    g是一个数组,但是通过使用它作为split()的输入,它被强制转换为字符串。这样做的结果是使用与字符串匹配的值(非常有趣,实际上,考虑到g的构成......请参阅此处的规范:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec)。

    将匹配用作"分离器"实际上,代码删除了该匹配的所有实例,并留下了所有" chunks"的数组。所有剩余字符的例子(例如:如果匹配为c且字符串为abcde,则拆分字符串将导致["ab", "de"]

  • 然后使用split string两次:

    1. 它用作连接的源,用于创建结果字符串

    2. 那个"分裂数组的第一个元素"用作"加入字符"

      所以,第二部分让我认为必须假设encoded_string值必须始终以exec()正则表达式模式中映射的一系列字符开头,因为如果是, "分裂数组的第一个字符"将永远是一个空白字符串,这意味着join()的结果将是原始encoded_string值,并删除所有匹配的字符。

      如果这个假设不正确,那么" split array"的第一个位置会有一个实际的字符,并且该字符将被插入到分割数组中的所有元素之间,从而创建来自联接的非常不同的结果字符串。

    3. 让我举一些例子,以便更好地说明。 。

      1)我的假设是正确的


      这使用一个小输入字符串,以及与该字符串的第一个字符匹配的模式:

      encoded_string = "abcdeabc";

      g = /[abc]/.exec(encoded_string);

      对于第一个循环,

      • g会发现"a"为第一场比赛,
      • "拆分字符串"将是["", "bcde", "bc"]
      • "加入角色"将是""
      • join()的结果为"bcdebc"

      对于第二个循环,

      • g会发现"b"为第一场比赛,
      • "拆分字符串"将是["", "cde", "c"]
      • "加入角色"将是""
      • join()的结果为"cdec"

      对于第三个循环,

      • g会发现"c"为第一场比赛,
      • "拆分字符串"将是["", "de", ""]
      • "加入角色"将是""
      • join()的结果为"de"

      没有更多匹配,因此循环将以此结束,最终encoded string值为"de"

      2)我的假设


      它使用与上面相同的输入字符串,但它使用匹配该字符串的第一个字符的模式:

      encoded_string = "abcdeabc";

      g = /[bcd]/.exec(encoded_string);

      对于第一个循环,

      • g会发现"b"为第一场比赛,
      • "拆分字符串"将是["a", "cdea", "c"]
      • "加入角色"将是"a"
      • join()的结果为"aacdeaac"

      对于第二个循环,

      • g会发现"c"为第一场比赛,
      • "拆分字符串"将是["aa", "deaa", ""]
      • "加入角色"将是"aa"
      • join()的结果为"aaaadeaaaa"

      对于第三个循环,

      • g会发现"d"为第一场比赛,
      • "拆分字符串"将是["aaaa", "eaaaa"]
      • "加入角色"将是"aaaa"
      • join()的结果为"aaaaaaaaeaaaa"

      没有更多匹配,因此循环将以此结束,最终encoded string值为"aaaaaaaaeaaaa"

      虽然第二种方法可能可能是作者试图做的事情,但我的第一种方法是更有可能的功能。 ;)


唷!那是很多。希望有助于澄清!