同盾fm.js AST处理方案 2022

编程入门 行业动态 更新时间:2024-10-18 22:31:34

同盾fm.js AST处理<a href=https://www.elefans.com/category/jswz/34/1770692.html style=方案 2022"/>

同盾fm.js AST处理方案 2022

同盾fm.js AST处理方案 2022-12-03

1. 准备

需要处理的文件地址

.js

astexplorer

/

在对 同盾 fm.js 分析时发现存在大量花指令代码 和大量数组混淆

代码如下:

function o0O0QQ(Qo0oO, OQQoO) {return Qo0oO >> OQQoO;
}function o0oOO0(Qo0oO, OQQoO) {return Qo0oO <= OQQoO;
}function Qo0Q00(Qo0oO, OQQoO) {return Qo0oO / OQQoO;
}
// ....
function O00000(Qo0oO, OQQoO) {return Qo0oO === OQQoO;
}function Oo00Q(Qo0oO, OQQoO) {return Qo0oO && OQQoO;
}
var oQ0ooQ = O00000(typeof Symbol, QQQo0O[1054]) && O00000(typeof Symbol[QQQo0O[522]], QQQo0O[612])
// ....

同时通过 astexplorer 分析发现 :

  1. 花指令函数由 BlockStatement -> ReturnStatement -> LogicalExpression 或 BinaryExpression 组成
  2. 数组混淆都是 MemberExpression 且都是同一个函数名称

2. 还原花指令

还原思路:

  1. 通过遍历 FunctionDeclaration 节点获取 花指令函数
  2. **过滤 ReturnStatementLogicalExpressionBinaryExpression 确定花指令函数 **
  3. 获取 运算符 用于后面替换节点
  4. 获取函数的作用域 并遍历 作用域之内调用( CallExpression )当前函数的 代码
  5. 重写 作用域中复合条件的 CallExpressionbinaryExpression
  6. 删除当前节点(无效代码)

还原代码如下:

FunctionDeclaration(path) {if (path.node.body.body === null|| !types.isReturnStatement(path.node.body.body[0])|| !(types.isBinaryExpression(path.node.body.body[0].argument) || types.isLogicalExpression(path.node.body.body[0].argument))) return;let operator = path.node.body.body[0].argument.operatorlet Bind = path.scope.getBinding(path.node.id.name)Bind.scope.traverse(Bind.scope.block,{CallExpression(p) {if (p.node.callee.name !== path.node.id.name|| p.node.arguments.length !== 2) return;p.replaceInline(types.binaryExpression(operator, p.node.arguments[0], p.node.arguments[1]))}})path.remove()
}

3. 还原数组混淆

还原思路:

  1. **获取 大数组和对应的名称 通过 eval 执行 到本地 **
  2. 遍历MemberExpression 获取 代码 通过 eval 得到 对应内容 并替换
  3. 删除多余代码 (这个可有可无 就没写 思路:获取 第二个 FunctionExpression节点中的 BlockStatement 替换即可)

还原代码如下:

let bigArr = generator(ast.program.body[0].expression.callee.body.body[0].expression.arguments[0]).code
let bigArrName = ast.program.body[0].expression.callee.body.body[0].expression.callee.params[0].nameeval(bigArrName + "=" + bigArr)MemberExpression(path) {
if (!types.isNumericLiteral(path.node.property)
|| path.node.object.name !== bigArrName
) return;let v = eval(generator(path.node).code);
path.replaceInline(types.valueToNode(v))
}

4. 效果

整体代码如下:

const fs = require("fs");   // 文件操作
const parser = require("@babel/parser"); // JS->AST
const traverse = require("@babel/traverse").default;  // 遍历AST
const types = require("@babel/types"); // 判断AST 节点类型
const generator = require("@babel/generator").default;  // AST -> JS源码let input_File = "./fm.js",output_File = "./fm_de.js";let JsCode = fs.readFileSync(input_File, {encoding: "utf-8"});  // 读取文件
let ast = parser.parse(JsCode);   // JS 转换成 ASTlet bigArr = generator(ast.program.body[0].expression.callee.body.body[0].expression.arguments[0]).code
let bigArrName = ast.program.body[0].expression.callee.body.body[0].expression.callee.params[0].nameeval(bigArrName + "=" + bigArr)let visitors = {MemberExpression(path) {if (!types.isNumericLiteral(path.node.property)|| path.node.object.name !== bigArrName) return;let v = eval(generator(path.node).code);path.replaceInline(types.valueToNode(v))},FunctionDeclaration(path) {if (path.node.body.body === null|| !types.isReturnStatement(path.node.body.body[0])|| !(types.isBinaryExpression(path.node.body.body[0].argument) || types.isLogicalExpression(path.node.body.body[0].argument))) return;let operator = path.node.body.body[0].argument.operatorlet Bind = path.scope.getBinding(path.node.id.name)Bind.scope.traverse(Bind.scope.block,{CallExpression(p) {if (p.node.callee.name !== path.node.id.name|| p.node.arguments.length !== 2) return;p.replaceInline(types.binaryExpression(operator, p.node.arguments[0], p.node.arguments[1]))}})path.remove()}
}traverse(ast, visitors)traverse(ast, {BinaryExpression(path) {if (!types.isNumericLiteral(path.node.right)|| !types.isNumericLiteral(path.node.left)) returnpath.replaceInline(types.valueToNode(eval(generator(path.node).code)))}
})let Code = generator(ast, opts = {jsescOption: {"minimal": true}}).code;  //将AST转换成JS
fs.writeFile(output_File, Code, (err) => {
}); // 写出处理完成的JS

还原效果如下 (代码太长 放小部分):

var oQ0ooQ = typeof Symbol === "function" && typeof Symbol["iterator"] === "symbol"

更多推荐

同盾fm.js AST处理方案 2022

本文发布于:2024-03-23 22:56:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1743823.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:方案   js   fm   AST

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!