对 属性 名称使用字符串连接的 javascript 反混淆方法

Methods for de-obfuscating javascript that uses string concatenation for property names

我正在想办法去混淆 javascript,看起来像这样:

https://jsfiddle.net/douglasg14b/4951br9f/2/

var testString = 'Test | String'

var wf6 = {
 fq4: 'su',
 k8d: 'bs',
 l8z: 'tri',
 cy1: 'ng',
 t5j: 'te',
 ol: 'stS',
 x3q: 'tri',
 l9x: 'ng',
 gh: 'xO'
};


//Obfuscated
let test1 = testString[wf6.fq4 + wf6.k8d + wf6.l8z + wf6.cy1](4,11);

//Normal
let test2 = testString.substring(4,11);
let test3;

//More complex obfuscation
(function moreComplex(){
 let h = "i",
        w = "nde",
        T0 = "f",
        hj = '|',
        a = eval(wf6.t5j + wf6.ol + wf6.x3q + wf6.l9x).length;
    //Obfuscated
    test3 = testString[wf6.fq4 + wf6.k8d + wf6.l8z + wf6.cy1](testString[h + w + wf6.gh + T0](hj), a);
    
    //Normal
    let test4 = testString.substring(testString.indexOf('|'), testString.length);
        
})();

$('.span1').text(test1);
$('.span2').text(test3);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="span1"></span><br>
<span class="span2"></span>

这是一个小例子,我正在处理的文件大约有 60k 行长,并且充满了这种混淆。到处都可以用一个字符串作为属性名字,就用到了这种混淆方式

我能想到的方法是评估所有字符串连接,以便将它们变成可读的等价物。不过,我不确定如何解决这个问题并忽略所有连接之间存在的所有其他工作代码。

想法?

奖金问题:是否有这种混淆的常用名称可以使搜索更容易一些?

编辑:添加了一个更复杂的示例。

您的基本想法是正确的:您必须 partially-evaluate 程序并预先计算所有常量计算。在您的情况下,主要关注的恒定计算是对不变值的串联步骤。

为此,您需要 program transformation system (PTS)。这是一个工具,它将 read/parse 指定语言的源代码并构建抽象语法树,允许您指定对 AST 和 运行 的转换和分析,然后将修改后的 AST 吐出为再次源代码。

在你的情况下,你显然想要一个有线的 PTS 知道 JavaScript 开箱即用(罕见)或者愿意接受 JavaScript 的描述然后阅读 JavaScript (更典型),希望您可以轻松构建或获得 JavaScript 描述。 [我构建了一个具有 JavaScript 可用描述的 PTS,请参阅我的简介]。

有了它,您需要:

  • 编写一个分析器,检查在表达式中找到的每个变量以查看该表达式是否为常量(例如,"wf6")。要证明它是常量,您必须找到变量定义,并检查变量定义中使用的所有值本身都是常量。如果有多个变量定义,您可能必须检查所有定义是否产生相同的值。您需要检查变量的副作用(例如,没有允许修改变量值的函数调用 "foo(...,wf6,...)")。您需要担心是否存在实现此类副作用的 eval 命令[这实际上是不可能的,因此您通常不得不忽略 evals 并假设它们不会执行此类操作]。许多 PTS 都有办法让你构建这样的分析器;有些比其他的更容易。
  • 对于每个常量值变量,在代码中替换该变量的值
  • 对于此类替换后的每个常量值子表达式,"fold"(计算)该表达式的结果并将该值替换为该子表达式并重复直到不可能再折叠。显然,您至少希望对所有“+”运算符执行此操作。 [OP 刚刚修改了他的例子;当所有操作数都是常量时,他也想为 "eval" 运算符这样做。
  • 您可能必须重复此过程,因为折叠表达式可能会明显表明变量现在具有常量值

上述过程在编译器文献中称为"constant propagation",是很多编译器的特性。

在您的情况下,您可以将常量折叠限制为仅字符串连接。然而,一旦您有足够的机制来执行常量值传播,那么对常量执行所有或大多数运算符并不难。您可能需要它来撤消涉及常量的其他混淆,因为那 似乎是您正在处理的代码中使用的混淆方式。

你需要一个特殊的规则来转换

var['string'](args)

进入

 var.string(args)

作为最后一步。

您还有另一个难题:那就是知道您拥有与生成常值变量相关的所有 JavaScript。一个网页可能包含许多 JavaScript 的块;您将需要所有这些来证明对变量没有副作用。我假设在你的情况下你确定你拥有一切。

关于生成已知常量值,您可能担心一个棘手的情况:从非常量操作数生成常量值的表达式。假设混淆后的表达式是:

   x=random(); // produce a value between 0 and 1
   one=x+(1-x); // not constant by constant propagation, but constant by algebraic relations
   teststring['st'[one]+'vu'[one+1]+'bz'[one]+...](4,11)

您可以看到它总是将 'substring' 计算为 属性。您可以添加一个转换规则来理解用于计算 "one" 的技巧,例如,用于计算已知常量的每个代数技巧的规则。不幸的是,有无数的代数定理可以用来制造常数;您的示例代码中真正使用了多少? [欢迎来到智能对手的逆向工程问题]。

不,这个 "easy" 的 none。大概这就是混淆方法的原因 选择使用。