利用AST解混淆先导知识:调用babel库反混淆代码模板
读取JavaScript源文件
因为是对源代码进行处理,因此需要读取源文件。当然代码也可以直接放进处理文件中,但是有些代码非常多,不太适合,因此这里使用读取文件的方式来获取源代码。
代码如下
   
    - 
     
      
     
     
      
       let encode_file = "./encode.js",decode_file = "./decode_result.js";
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       if (process.argv.length > 2)
      
     
- 
     
      
     
     
      
       {
      
     
- 
     
      
     
     
        encode_file = process.argv[2];
      
     
- 
     
      
     
     
      
       }
      
     
- 
     
      
     
     
      
       if (process.argv.length > 3)
      
     
- 
     
      
     
     
      
       {
      
     
- 
     
      
     
     
        decode_file = process.argv[3];
      
     
- 
     
      
     
     
      
       }
      
     
  代码释义: 源文件名默认为 encode.js,生成处理后的目标文件名默认为 decode_result.js。后面的代码是从命令行参数来读取。
eg:
   
    - 
     
      
     
     
      
       node decode_obfuscator.js encode.js decode_result.js
      
     
- 
     
      
     
     
      
       encode.js 混淆前js源代码的路径
      
     
- 
     
      
     
     
      
       decode_result.js 生成新js代码的路径
      
     
  再保存到一个变量中,对这个变量进行处理即可:
let jscode = fs.readFileSync(encode_file, {encoding: "utf-8"});
  babel库也可以从文件获取js的源代码,不过为了方便起见,还是用 fs 库吧。
特别注意:一定要将从网上copy下面的代码保存为 utf-8 格式,我已经踩过很多坑了。
将JavaScript源代码 转换成一棵AST树:
const {parse} = require("@babel/parser");
  它的函数定义是这样的:
   
    - 
     
      
     
     
      
       function parse(input, options) {
      
     
- 
     
      
     
     
        if (options && options.sourceType === "unambiguous") {
      
     
- 
     
      
     
     
      
        options = Object.assign({}, options);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       try {
      
     
- 
     
      
     
     
      
        options.sourceType = "module";
      
     
- 
     
      
     
     
       const parser = getParser(options, input);
      
     
- 
     
      
     
     
       const ast = parser.parse();
      
     
- 
     
      
     
     
       if (!parser.sawUnambiguousESM) ast.program.sourceType = "script";
      
     
- 
     
      
     
     
       return ast;
      
     
- 
     
      
     
     
      
        } catch (moduleError) {
      
     
- 
     
      
     
     
       try {
      
     
- 
     
      
     
     
      
        options.sourceType = "script";
      
     
- 
     
      
     
     
       return getParser(options, input).parse();
      
     
- 
     
      
     
     
      
        } catch (scriptError) {}
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       throw moduleError;
      
     
- 
     
      
     
     
      
        }
      
     
- 
     
      
     
     
      
         } else {
      
     
- 
     
      
     
     
       return getParser(options, input).parse();
      
     
- 
     
      
     
     
      
         }
      
     
- 
     
      
     
     
      
       }
      
     
  一般以下面这种形式调用:
let ast = parse(jscode);
  它的返回结果(在这里赋值给ast)是一个JSON结构的数据。
日常调用时它的第二个参数 options 为空,所以最终还是调用的 getParser(options, input).parse()函数。
可以将整个ast规整的打印出来,代码如下:
JSON.stringify(ast,null,'\t');
  可以发现它和在线解析网站的结果相差无二。
遍历各个节点的函数:
const traverse = require("@babel/traverse").default;
  该函数的源代码:
   
    - 
     
      
     
     
      
       function traverse(parent, opts, scope, state, parentPath) {
      
     
- 
     
      
     
     
        if (!parent) return;
      
     
- 
     
      
     
     
        if (!opts) opts = {};
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
        if (!opts.noScope && !scope) {
      
     
- 
     
      
     
     
       if (parent.type !== "Program" && parent.type !== "File") {
      
     
- 
     
      
     
     
       throw new Error("You must pass a scope and parentPath unless traversing a Program/File. " + `Instead of that you tried to traverse a ${parent.type} node without ` + "passing scope and parentPath.");
      
     
- 
     
      
     
     
      
        }
      
     
- 
     
      
     
     
      
         }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
         visitors.explode(opts);
      
     
- 
     
      
     
     
      
         traverse.node(parent, opts, scope, state, parentPath);
      
     
- 
     
      
     
     
      
       }
      
     
  最终调用的是 traverse.node 函数,定义如下
   
    - 
     
      
     
     
      
       traverse.node = function (node, opts, scope, state, parentPath, skipKeys) {
      
     
- 
     
      
     
     
        const keys = t().VISITOR_KEYS[node.type];
      
     
- 
     
      
     
     
        if (!keys) return;
      
     
- 
     
      
     
     
        const context = new _context.default(scope, opts, state, parentPath);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
        for (const key of keys) {
      
     
- 
     
      
     
     
       if (skipKeys && skipKeys[key]) continue;
      
     
- 
     
      
     
     
       if (context.visit(node, key)) return;
      
     
- 
     
      
     
     
      
         }
      
     
- 
     
      
     
     
      
       };
      
     
  可以看到,第一个参数是node,也就是说,只要定义了traverse函数,可以随时随地对node进行遍历。
节点的类型判断及构造等操作:
const types = require("@babel/types");
  它的功能非常强大,操作AST,主要是对节点进行替换,删除,增加等操作,因此会经常用到它(后续文章会进行介绍)。
将处理完毕的AST转换成JavaScript源代码:
const generator = require("@babel/generator").default;
  它的函数定义如下:
   
    - 
     
      
     
     
      
       function _default(ast, opts, code) {
      
     
- 
     
      
     
     
        const gen = new Generator(ast, opts, code);
      
     
- 
     
      
     
     
        return gen.generate();
      
     
- 
     
      
     
     
      
       }
      
     
  最终调用的是 Generator(ast, opts, code).generate()。返回的是一个object类型:
   
    - 
     
      
     
     
      
       {
      
     
- 
     
      
     
     
        code:"",
      
     
- 
     
      
     
     
      
         map:null,
      
     
- 
     
      
     
     
      
         rawMappings:null,
      
     
- 
     
      
     
     
      
       }
      
     
  只需要提取出其中的code即可:
let {code} = generator(ast);
  将将最终的code结果保持为新的js文件:
fs.writeFile('decode.js', code, (err)=>{});
  所以,代码整合起来是这样的:
   
    - 
     
      
     
     
      
       //babel库及文件模块导入
      
     
- 
     
      
     
     
      
       const fs = require('fs');
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       //babel库相关,解析,转换,构建,生产
      
     
- 
     
      
     
     
      
       const parser = require("@babel/parser");
      
     
- 
     
      
     
     
      
       const traverse = require("@babel/traverse").default;
      
     
- 
     
      
     
     
      
       const types = require("@babel/types");
      
     
- 
     
      
     
     
      
       const generator = require("@babel/generator").default;
      
     
- 
     
      
     
     
      
       //读取文件
      
     
- 
     
      
     
     
      
       let encode_file = "./encode.js",decode_file = "./decode_result.js";
      
     
- 
     
      
     
     
      
       if (process.argv.length > 2)
      
     
- 
     
      
     
     
      
       {
      
     
- 
     
      
     
     
      
         encode_file = process.argv[2];
      
     
- 
     
      
     
     
      
       }
      
     
- 
     
      
     
     
      
       if (process.argv.length > 3)
      
     
- 
     
      
     
     
      
       {
      
     
- 
     
      
     
     
      
         decode_file = process.argv[3];
      
     
- 
     
      
     
     
      
       }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       let jscode = fs.readFileSync(encode_file, {encoding: "utf-8"});
      
     
- 
     
      
     
     
      
       //转换为ast树
      
     
- 
     
      
     
     
      
       let ast = parser.parse(jscode);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       const visitor = 
      
     
- 
     
      
     
     
      
       {
      
     
- 
     
      
     
     
        //TODO write your code here!
      
     
- 
     
      
     
     
      
       }
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       //some function code
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       //调用插件,处理源代码
      
     
- 
     
      
     
     
      
       traverse(ast,visitor);
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
       
      
     
- 
     
      
     
     
      
       //生成新的js code,并保存到文件中输出
      
     
- 
     
      
     
     
      
       let {code} = generator(ast);
      
     
- 
     
      
     
     
      
       fs.writeFile('decode.js', code, (err)=>{});
      
     
  大家以后按照这个框架去写代码即可。

文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq523176585/article/details/109507691
- 点赞
- 收藏
- 关注作者
 
             
           
评论(0)