利用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)=>{});

大家以后按照这个框架去写代码即可。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值