用实际的变量名称/字符串替换数组映射变量?

9

我正在尝试编辑一个Greasemonkey/jQuery脚本。这里不能发布链接。
代码经过混淆并使用minify进行压缩。
它的开头是这样的:

var _0x21e9 = ["\x67\x65\x74\x4D\x6F\x6E\x74\x68", "\x67\x65\x74\x55\x54\x43\x44\x61\x74\x65", ...

“解码”后,我得到了这个:
var _0x21e9=["getMonth","getUTCDate","getFullYear", ...   

这是一个巨大的列表(500+)。然后,它还有一些变量,比如:

 month = date[_0x21e9[0]](), day = date[_0x21e9[1]](), ...

_0x21e9[0]代表获取月份,_0x21e9[1]代表获取UTC日期等。

是否可以用实际的变量名替换方括号?如何操作?
我对javascript/jQuery了解不多,无法像现在这样“读”代码。
我只想使用一些函数来执行这个庞大的脚本,并删除我不需要的内容。

更新:我尝试使用jsbeautifier.org,如此重复问题中所建议的,但除了“缩进”之外,没有任何变化。

它没有用解码后的名称替换数组变量。
例如:

  1. jsbeautifier仍然显示:month = date[_0x21e9[0]]()
  2. 但我需要:month = date["getMonth"]()

似乎没有在线反混淆程序可以做到这点,我该怎么办?


有没有办法让我与某人分享代码,至少其中的一部分?我读到我不能在这里发布pastebin或类似的东西。我不能在这里发布完整的代码。

这是代码的另一部分:

$(_0x21e9[8] + vid)[_0x21e9[18]]();    

[8]表示“.”,[18]表示“remove”。手动替换会导致奇怪的结果。

为什么要用实际变量名称替换方括号?访问名为_0x21e9getMonth的变量以检索字符串"getMonth"有什么意义? - hofan41
这是一个包含500多个字符串的长列表。要知道[0]代表的是getMonth,我必须手动检查整个列表并计算。如果它是[500],我将需要计算逗号分隔的字符串数量。我该如何做呢?虽然这不是我的脚本,但我只想移除我不需要的部分。 - nex
这段代码相当“混淆”了……你是在试图解码别人的JavaScript并使用它吗?也就是说,这段代码很可能被混淆出于某种原因,如果你知道是谁做的,他们同样可以轻松地恢复它。 - BuddhistBeast
这不是我的脚本。它为我使用的论坛添加了一些功能,比如屏蔽用户、添加一些菜单等等。我想把它全部删除,只保留刷新页面的功能。有些用户甚至说它是“键盘记录器”。我只是想删除一些功能以供个人使用,我甚至没有在这里发布脚本。 - nex
显示剩余3条评论
3个回答

14

我还没有看到任何在线的反混淆工具可以做到这一点,但原则很简单。
构建一个文本过滤器,解析"key"数组,然后用适当的数组值替换每个引用该数组的实例。

例如,假设你有一个文件evil.js,它看起来像这样(在你通过jsbeautifier.org 运行了 Detect packers and obfuscators?Unescape printable chars... 选项之后):

var _0xf17f = ["(", ")", 'div', "createElement", "id", "log", "console"];
var _0x41dcx3 = eval(_0xf17f[0] + '{id: 3}' + _0xf17f[1]);
var _0x41dcx4 = document[_0xf17f[3]](_0xf17f[2]);
var _0x41dcx5 = _0x41dcx3[_0xf17f[4]];
window[_0xf17f[6]][_0xf17f[5]](_0x41dcx5);
在这种情况下,“key”变量将是_0xf17f,“key”数组将是["(", ")", ...]
过滤过程如下:
1. 使用JavaScript文件中的文本处理提取关键字名称。结果为:_0xf17f
2. 提取关键字数组的字符串src。结果为:
keyArrayStr = '["(", ")", \'div\', "createElement", "id", "log", "console"]';
  • 在JavaScript中,我们可以使用.replace()方法来解析其余的JS源代码。像这样:

  • var keyArrayStr = '["(", ")", \'div\', "createElement", "id", "log", "console"]';
    var restOfSrc   = "var _0x41dcx3 = eval(_0xf17f[0] + '{id: 3}' + _0xf17f[1]);\n"
                    + "var _0x41dcx4 = document[_0xf17f[3]](_0xf17f[2]);\n"
                    + "var _0x41dcx5 = _0x41dcx3[_0xf17f[4]];\n"
                    + "window[_0xf17f[6]][_0xf17f[5]](_0x41dcx5);\n"
                    ;
    var keyArray    = eval (keyArrayStr);
    //-- Note that `_0xf17f` is the key name we already determined.
    var keyRegExp   = /_0xf17f\s*\[\s*(\d+)\s*\]/g;
    
    var deObsTxt    = restOfSrc.replace (keyRegExp, function (matchStr, p1Str) {
        return '"' + keyArray[ parseInt(p1Str, 10) ] + '"';
    } );
    console.log (deObsTxt);
    

    如果你运行这段代码,你将得到:

    var _0x41dcx3 = eval("(" + '{id: 3}' + ")");
    var _0x41dcx4 = document["createElement"]("div");
    var _0x41dcx5 = _0x41dcx3["id"];
    window["console"]["log"](_0x41dcx5);
    

    --这使得阅读/理解起来更加容易一些。


    我还创建了一个在线页面,可以以稍微更自动化和健壮的方式执行所有3个重新映射步骤。 您可以在以下网址查看:

    jsbin.com/hazevo

    (请注意,该工具期望源以"key"变量声明开头,就像您的代码示例一样)


    4
    @Brock Adams的解决方案很棒,但是有一个小错误:它没有考虑到简单引号变量。

    例子:

    var _0xbd34 = ["hello ", '"my" world'];
    (function($) {
      alert(_0xbd34[0] + _0xbd34[1])
    });
    

    如果您试图解读这个示例,结果将如下所示:
    alert("hello " + ""my" world")
    

    为了解决这个问题,只需要将replacedSrc.replace替换成@Brock的代码即可:
    replacedSrc     = replacedSrc.replace (nameRegex, function (matchStr, p1Str) {
        var quote = keyArry[parseInt (p1Str, 10)].indexOf('"')==-1? '"' : "'";
        return quote + keyArry[ parseInt (p1Str, 10) ] + quote;
    } );
    

    这里有一个修补过的版本


    0
    for (var i = 0; i < _0x21e9.length; i++) {
      var funcName = _0x21e9[i];
      _0x21e9[funcName] = funcName;
    }
    

    这将把所有函数名称作为键添加到数组中,使您能够进行操作。
    date[_0x21e9["getMonth"]]()
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接