python如何解决js逆向混淆?

  • A+
所属分类:Python

JavaScript混淆是一种保护网站安全的技术,混淆可将代码进行多种变形和加密,使得 JavaScript 代码变得难以阅读和理解。逆向混淆是混淆中的一种方式。通过逆向混淆,混淆的代码更难被攻击者分析和了解混淆的含义。Python 是一种强大的编程语言,可以用于处理 JavaScript 混淆代码。下面我们就通过一个例子,详细介绍 Python 如何解决 JavaScript 逆向混淆问题。

首先,让我们来了解一下需要解淆的JavaScript代码。它是一个包含各种混淆技巧的javascript文件。混淆后的代码可见以下代码(示例代码来自于 https://obfuscator.io/):

var _0x413c=['foo','bar','baz','hello\x20world!','log'];(function(_0x30fc94,_0x17c46f){var _0x2ff54f=function(_0x50c0f){while(--_0x50c0f){_0x30fc94['push'](_0x30fc94['shift']());}};_0x2ff54f(++_0x17c46f);}(_0x413c,0x1e7));var _0x4073=function(_0x4124e5,_0x45130a){_0x4124e5=_0x4124e5-0x0;var _0xa28e27=_0x413c[_0x4124e5];return _0xa28e27;};function[_0x4073('0x2')][_0x4073('0x4')](){console[_0x4073('0x3')](_0x413c[0x2]);}console[_0x4073('0x3')](_0x413c[0x3]);

看到上面的代码,可能让我们不得不重新思考:

变量使用短、无意义的名称
压缩过的代码难以阅读,代码几乎没有缩进
混淆代码中没有注释
字符串有编码
函数定义被压缩成一行
我们可以使用 Python 编写脚本进行解密。这里我们采用字符串查找和分割、正则表达式、AST 分析等技术。尽管某些混淆技术会使解混淆变得复杂,但我们可以通过一些简单的技巧来解决大多数混淆问题。

下面是我们对这个JavaScript混淆文件的解淆步骤:

1. 如果需要,使混淆代码可读
首先,我们需要把代码中的编码还原为它们对应的字符。这可以通过正则表达式和 Python 的 Unicode 编/解码来实现。以下是一个 Python 工具函数,可以将字符串中的字符编码转换为可读的字符:

  1. def decode_string(encoded_str):

  2.     return re.sub(r'\\x([a-fA-F0-9]{2})', lambda m: chr(int(m.group(1), 16)), encoded_str)

  3. 现在,在代码中使用 decode_string 函数,将所有 \x 编码的字符解密并重写代码:

  4. with open('MixedCodeObfuscated.js', 'r', encoding='utf-8') as f:

  5. pattern = re.compile(r'(\\x[A-Za-z0-9]{2})')

  6. matches = pattern.findall(content)

  7.     content = content.replace(match, decode_string(match))

在上面的 Python 代码中,我们将 MixedCodeObfuscated.js 中的混淆代码加载到 content 变量中。然后,定义了一个正则表达式类型的pattern,用于匹配全部的"\x"编码格式。再通过for循环结构把字符码转换为对应的可读的字符。最终,输出解密后的内容。现在,我们已经删除了所有编码字符,使混淆的JavaScript 代码更易于阅读和理解。

  1. var _0x413c = ['foo', 'bar', 'baz', 'hello world!', 'log'];

  2. (function (_0x30fc94, _0x17c46f) {

  3.     var _0x2ff54f = function (_0x50c0f) {

  4.         while (--_0x50c0f) {

  5.             _0x30fc94['push'](_0x30fc94['shift']());

  6.     _0x2ff54f(++_0x17c46f);

  7. var _0x4073 = function (_0x4124e5, _0x45130a) {

  8.     _0x4124e5 = _0x4124e5 - 0x0;

  9.     var _0xa28e27 = _0x413c[_0x4124e5];

  10.     console[_0x4073('0x3')](_0x413c[0x2]);

  11. console[_0x4073('0x3')](_0x413c[0x3]);

2. 重命名函数和变量
变量名和函数名通常是混淆代码中的另一个问题。混淆器通常使用短、无意义的名称来给变量和函数命名,例如 _0x413c 和 _0x4073。这使得代码的阅读和理解变得更加困难。为了重命名函数和变量,我们需要对代码进行解析,并对变量赋予更有意义的名称。

还有一种变量命名方式是使用更有语义的名称,例如,由于在示例混淆文件中有一个函数名是 logBaz,我们可以假设它与 baz 变量相关联。因此,我们可以将其重命名为 logImportantWord。

对于变量和参数名称,我们还可以使用后缀来表示变量和参数的类型。例如,strFoo 表示它是一个字符串类型。

以下是一个 Python 脚本,用于重新命名混淆代码中变量和函数:

  1. def get_random_name(length):

  2.     chars = string.ascii_lowercase

  3.     return ''.join(random.choice(chars) for i in range(length))

  4.     tree = ast.parse(code)

  5.     used_names = [node.id for node in ast.walk(tree) if isinstance(node, ast.Name) and not isinstance(node.ctx, ast.Store)]

  6. used_names = set(used_names)

  7. for node in ast.walk(tree):

  8.     if isinstance(node, ast.FunctionDef):

  9.         if node.name.startswith('_'):

  10.         new_name = get_random_name(8)

  11.         while new_name in used_names:

  12.             new_name = get_random_name(8)

  13.         node.name = new_name

  14.         used_names.add(new_name)

  15.     elif isinstance(node, ast.Name) and not isinstance(node.ctx, ast.Store):

  16.         if len(node.id) < 3 or node.id.startswith('_'):

  17.         new_name = get_random_name(8)

  18.         while new_name in used_names:

  19.             new_name = get_random_name(8)

  20.         node.id = new_name

  21.         used_names.add(new_name)

  22. with open(‘MixedCodeObfuscated.js’, ‘r’, encoding=‘utf-8’) as f:

  23. content = rename_vars(content)

在上面的 Python 脚本中,我们首先定义了一个名为 `get_random_name` 的函数,它返回指定长度的随机字符串。接下来,我们使用 Python 的抽象语法树(AST)模块分析了代码。在代码分析过程中,我们提取了每个变量的名称,以便我们可以选择一个新名称来重命名它们。我们使用 `get_random_name` 函数生成一个新的、唯一的名称,并将其分配给变量或函数。最后,我们返回一段新的代码,其中所有变量和函数都被重命名。

那么,重命名之后,我们来看一下解密后的 JavaScript 代码:

  1. var strFoo = ['foo', 'bar', 'baz', 'hello world!', 'log'];

  2. (function (strBaz, intEel) {

  3.     var funcFish = function (intHam) {

  4.         for (--intHam; intHam;) {

  5.             strBaz['push'](strBaz['shift']());

  6. var funcImportantWord = function (intCow, ocrJim) {

  7.     intCow = intCow - 0x0;

  8.     var strZoo = strFoo[intCow];

  9. function logImportantWord() {

  10.     console[funcImportantWord('0x3')](strFoo[0x2]);

  11. console[funcImportantWord('0x3')](strFoo[0x3]);

可以看到,所有变量和函数现在都被赋予更有意义的名称,这使得代码更易于阅读和理解。

3. 恢复代码结构
JavaScript 代码混淆通常会改变代码的结构。例如,混淆器可以交换条件语句的顺序、使用三元运算符或条件语句来替代简单赋值语句等。为了使代码更易于阅读和修改,我们可以使用 Python 和 JavaScript Beautifier 库来还原代码的结构。JavaScript Beautifier 可以格式化代码,添加适当的缩进和换行符,使代码更清晰易读。以下是一段示例代码,说明了如何使用 JavaScript Beautifier 还原代码的结构:

  1.     options = jsbeautifier.default_options()

  2.     options.indent_size = 4

  3.     options.indent_char = ' '

  4.     options.preserve_newlines = True

  5.     return jsbeautifier.beautify(code, options)

  6. with open('MixedCodeObfuscated.js', 'r', encoding='utf-8') as f:

  7. content = decode_code(content)

  8. content = rename_vars(content)

  9. content = format_code(content)

在上面的示例代码中,我们调用 jsbeautifier.beautify() 函数,并设置了适当的选项来格式化代码。最后,我们返回格式化后的代码。

4. 解密 JavaScript 没那么简单!
需要说明的是,在实践中,解密 JavaScript 代码并不总是如此简单直接。混淆器可以使用各种技巧,使代码更加混淆和难以理解。例如,混淆器可以使用以下技术:

控制流平坦化:这是一种技术,用于将分支结构展平为一系列条件语句,使得代码难以阅读。
字符串加密:混淆器可以将字符串编码,并将其解码为字符数组,以使代码更难以理解。例如,可以使用 Base64、RC4 等加密技术来加密字符串。
基于 AST 的混淆:混淆器可以分析代码抽象语法树,并使用各种技术来重构代码,使其难以理解和修改。
在这样的情况下,解密 JavaScript 代码需要更高级的技术和更深入的理解。可能需要使用自定义脚本、反混淆器和各种 JavaScript 分析和调试工具。

此外,在尝试解密混淆 JavaScript 代码时,需要注意一些安全问题。如果您不是代码的所有者或授权的维护者,请不要尝试破解代码。将黑客工具用于未经授权的代码解密可能会涉嫌违法行为,应该遵守法律和道德准则。

总结:

以上是 Python 解密 JavaScript 逆向混淆的初步介绍。在实践中,解密混淆的 JavaScript 代码需要更深入的理解和高级技术。但是,通过 Python 脚本、正则表达式、AST 分析和 JavaScript Beautifier,我们可以为大多数混淆技术找到解决方案,并使代码更易于阅读和理解。在尝试解密混淆 JavaScript 代码时,请注意安全问题,遵守法律和道德准则。

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin