AST 解ob混淆初体验

Sherry 发布于 2025-06-22 82 次阅读 文章 最后更新于 2025-06-22 1112 字


🍔混淆代码

 var _0x9892 = ['trace', 'toString', 'Hello\x20World!', 'return\x20(function()\x20', 'log', '__proto__', 'table', 'console', '{}.constructor(\x22return\x20this\x22)(\x20)', 'length', 'apply', 'exception', 'bind', 'error', 'constructor'];
(function (_0x4b56d1, _0x4564e9) {
 var _0x9892e2 = function (_0x17c1cb) {
     while (--_0x17c1cb) {
         _0x4b56d1['push'](_0x4b56d1['shift']());
     }
 };
 _0x9892e2(++_0x4564e9);
}(_0x9892, 0x1dc));
var _0x17c1 = function (_0x4b56d1, _0x4564e9) {
    _0x4b56d1 = _0x4b56d1 - 0xbf;
    var _0x9892e2 = _0x9892[_0x4b56d1];

    return _0x9892e2;
};
var _0x1eb17c = _0x17c1
function hi() {
     var _0x2e11d2 = _0x17c1
         , _0x1b400d = function () {
         var _0x56b97f = !![];
         return function (_0x2f02e6, _0x3da0d9) {
             var _0x5610cd = _0x56b97f ? function () {
                         var _0x18fd4c = _0x17c1;
                         if (_0x3da0d9) {
                             var _0x154edd = _0x3da0d9[_0x18fd4c(0xcd)](_0x2f02e6, arguments);
                             return _0x3da0d9 = null,
                                 _0x154edd;
                         }
                     }
                     : function () {
                     }
             ;
             return _0x56b97f = ![],
                 _0x5610cd;
         }
             ;
     }()
         , _0x3bc942 = _0x1b400d(this, function () {
         var _0x1eb17c = _0x17c1, _0x118c6f;
         try {
             var _0x2521bf = Function(_0x1eb17c(0xc6) + _0x1eb17c(0xcb) + ');');
             _0x118c6f = _0x2521bf();
         } catch (_0x2241e2) {
             _0x118c6f = window;
         }
         var _0x59b918 = _0x118c6f[_0x1eb17c(0xca)] = _0x118c6f[_0x1eb17c(0xca)] || {}
             ,
             _0x3a8d6f = [_0x1eb17c(0xc7), 'warn', 'info', _0x1eb17c(0xc1), _0x1eb17c(0xbf), _0x1eb17c(0xc9), _0x1eb17c(0xc3)];
         for (var _0x42b442 = 0x0; _0x42b442 < _0x3a8d6f[_0x1eb17c(0xcc)]; _0x42b442++) {
             var _0x1b8b7a = _0x1b400d[_0x1eb17c(0xc2)]['prototype'][_0x1eb17c(0xc0)](_0x1b400d)
                 , _0x1d1203 = _0x3a8d6f[_0x42b442]
                 , _0x5a65c9 = _0x59b918[_0x1d1203] || _0x1b8b7a;
             _0x1b8b7a[_0x1eb17c(0xc8)] = _0x1b400d['bind'](_0x1b400d),
                 _0x1b8b7a[_0x1eb17c(0xc4)] = _0x5a65c9['toString']['bind'](_0x5a65c9),
                 _0x59b918[_0x1d1203] = _0x1b8b7a;
         }
 });
 _0x3bc942(),
     console[_0x2e11d2(0xc7)](_0x2e11d2(0xc5));
}

hi();

🍟AST代码

const fs = require('fs');
const { parse } = require('@babel/parser');
const types = require('@babel/types');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;

// 获取AST代码
var AST_code = fs.readFileSync('ob混淆.js', 'utf8');
let AST_parse = parse(AST_code);

// 获取解密函数,并写入内存
let member_decode_js = '';

// 循环获取前三块代码
for(var i=0;i<=3;i++){
    member_decode_js += generate(AST_parse.program.body[i],{compact:true}).code
    delete AST_parse.program.body[i]
}

// 执行代码,存放在内存中
eval(member_decode_js)

// 第一步:解密函数还原
traverse(AST_parse,{
    CallExpression(path){
        if(path.node.callee.name === '_0x1eb17c' && path.node.arguments[0].type === 'NumericLiteral'){
            path.replaceInline(types.valueToNode(eval(path.toString())))
        }
    }
})

// 第二步:简化布尔值表达式
traverse(AST_parse, {
    UnaryExpression(path) {
        // 将 !![] 替换为 true
        if (path.node.operator === '!' &&
            path.node.argument.type === 'UnaryExpression' &&
            path.node.argument.operator === '!' &&
            path.node.argument.argument.type === 'ArrayExpression' &&
            path.node.argument.argument.elements.length === 0) {
            path.replaceWith(types.booleanLiteral(true));
        }
        // 将 ![] 替换为 false
        if (path.node.operator === '!' &&
            path.node.argument.type === 'ArrayExpression' &&
            path.node.argument.elements.length === 0) {
            path.replaceWith(types.booleanLiteral(false));
        }
    }
});

// 第三步:简化条件表达式
traverse(AST_parse, {
    ConditionalExpression(path) {
        // 如果条件是 true,直接返回 consequent
        if (path.node.test.type === 'BooleanLiteral' && path.node.test.value === true) {
            path.replaceWith(path.node.consequent);
        }
        // 如果条件是 false,直接返回 alternate
        if (path.node.test.type === 'BooleanLiteral' && path.node.test.value === false) {
            path.replaceWith(path.node.alternate);
        }
    }
});

// 第四步:移除死代码(空函数)
traverse(AST_parse, {
    FunctionExpression(path) {
        // 移除空的函数表达式
        if (path.node.body.body.length === 0) {
            path.replaceWith(types.nullLiteral());
        }
    }
});

// 第五步:清理无用变量
let toRemove = [];
traverse(AST_parse, {
    VariableDeclarator(path) {
        if (!path.node || !path.node.id) return;

        // 标记要删除的无用变量
        if ((path.node.id.name === '_0x2e11d2' || path.node.id.name === '_0x1eb17c') &&
            path.node.init &&
            path.node.init.name === '_0x17c1') {
            toRemove.push(path);
        }
    }
});

// 安全地删除标记的节点
toRemove.forEach(path => {
    if (path.node) {
        path.remove();
    }
});

// 第六步:进一步简化 - 内联常量
traverse(AST_parse, {
    VariableDeclarator(path) {
        if (!path.node || !path.node.id) return;

        // 内联 _0x56b97f = true
        if (path.node.id.name === '_0x56b97f' &&
            path.node.init &&
            path.node.init.type === 'BooleanLiteral' &&
            path.node.init.value === true) {

            let binding = path.scope.getBinding('_0x56b97f');
            if (binding) {
                binding.referencePaths.forEach(refPath => {
                    refPath.replaceWith(types.booleanLiteral(true));
                });
                path.remove();
            }
        }
    }
});

// 第七步:简化赋值表达式
traverse(AST_parse, {
    AssignmentExpression(path) {
        // 简化 _0x56b97f = false
        if (path.node.left.name === '_0x56b97f' &&
            path.node.right.type === 'BooleanLiteral' &&
            path.node.right.value === false) {
            path.replaceWith(types.booleanLiteral(false));
        }
    }
});

// 第八步:分析代码逻辑,进一步简化
console.log('=== 分析代码结构 ===');

// 分析这个混淆代码的实际功能
traverse(AST_parse, {
    CallExpression(path) {
        // 查找 console.log 调用
        if (path.node.callee.type === 'MemberExpression' &&
            path.node.callee.object.name === 'console' &&
            path.node.callee.property.name === 'log') {
            console.log('发现 console.log 调用,参数:', path.node.arguments);
        }
    }
});

console.log('\n=== 最终优化结果 ===');
let finalCode = generate(AST_parse, {
    compact: false,
    minified: false,
    comments: false
}).code;

console.log(finalCode);

🍕优化代码

function hi() {
  var _0x1b400d = function () {
      return function (_0x2f02e6, _0x3da0d9) {
        var _0x5610cd = true ? function () {
          var _0x18fd4c = _0x17c1;
          if (_0x3da0d9) {
            var _0x154edd = _0x3da0d9[_0x18fd4c(0xcd)](_0x2f02e6, arguments);
            return _0x3da0d9 = null, _0x154edd;
          }
        } : null;
        return false, _0x5610cd;
      };
    }(),
    _0x3bc942 = _0x1b400d(this, function () {
      var _0x118c6f;
      try {
        var _0x2521bf = Function("return (function() " + "{}.constructor(\"return this\")( )" + ');');
        _0x118c6f = _0x2521bf();
      } catch (_0x2241e2) {
        _0x118c6f = window;
      }
      var _0x59b918 = _0x118c6f["console"] = _0x118c6f["console"] || {},
        _0x3a8d6f = ["log", 'warn', 'info', "error", "exception", "table", "trace"];
      for (var _0x42b442 = 0x0; _0x42b442 < _0x3a8d6f["length"]; _0x42b442++) {
        var _0x1b8b7a = _0x1b400d["constructor"]['prototype']["bind"](_0x1b400d),
          _0x1d1203 = _0x3a8d6f[_0x42b442],
          _0x5a65c9 = _0x59b918[_0x1d1203] || _0x1b8b7a;
        _0x1b8b7a["__proto__"] = _0x1b400d['bind'](_0x1b400d), _0x1b8b7a["toString"] = _0x5a65c9['toString']['bind'](_0x
                                                                                                                       x5a65c9), _0x59b918[_0x1d1203] = _0x1b8b7a;
      }
    });
  _0x3bc942(), console[_0x2e11d2(0xc7)](_0x2e11d2(0xc5));
}
hi();