方案 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 分析发现 :
- 花指令函数由 BlockStatement -> ReturnStatement -> LogicalExpression 或 BinaryExpression 组成
- 数组混淆都是 MemberExpression 且都是同一个函数名称
2. 还原花指令
还原思路:
- 通过遍历
FunctionDeclaration
节点获取 花指令函数 - **过滤
ReturnStatement
、LogicalExpression
、BinaryExpression
确定花指令函数 ** - 获取 运算符 用于后面替换节点
- 获取函数的作用域 并遍历 作用域之内调用(
CallExpression
)当前函数的 代码 - 重写 作用域中复合条件的
CallExpression
为binaryExpression
- 删除当前节点(无效代码)
还原代码如下:
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. 还原数组混淆
还原思路:
- **获取 大数组和对应的名称 通过
eval
执行 到本地 ** - 遍历
MemberExpression
获取 代码 通过 eval 得到 对应内容 并替换 - 删除多余代码 (这个可有可无 就没写 思路:获取 第二个
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
发布评论