特别说明:本文 生成节点时,函数的使用对于 Js 来说是错误的(不能指定参数给值),这样写是方便 看节点属性
二项式 转 函数花指令
花指令用来更好的隐藏 源代码的真实意图,还能增加代码量,增加分析难度
类型一
// 源代码 var num = a + b; // 变成 function xxx(c, d){ return c + d; } var num = xxx(a, b)
类型二
// 源代码 var num = add(a); // 变成 function xxx(c, v){ return c(v); } var num = xxx(add, v)
类型一 思路
获取
二项式
的符号
和左右部分
,然后 生成函数节点
,把函数节点
添加到当前代码块
的最前面
,然后把原始
的二项式
替换为调用表达式
// 二项式转花指令 traverse(ast, { BinaryExpression(path) { let operator = path.node.operator; let left_ = path.node.left; // 加个下滑线 防止 冲突 let right_ = path.node.right; // 构造函数节点 let funName = path.scope.generateUidIdentifier('xxx'); let a = type.identifier(name = 'a'); let b = type.identifier(name = 'b'); let func = type.functionDeclaration( id = funName, params = [a, b], body = type.blockStatement( body = [type.returnStatement( argument = type.binaryExpression( operator = operator, left=a, right = b ) )] ) ) // 把生成的函数节点添加到当前代码的最前面 let blockStatement = path.findParent(function (p) { return p.isBlockStatement() }) blockStatement.node.body.unshift(func); // 替换原节点 为 调用表达式 path.replaceWith(type.callExpression( callee = funName, _arguments = [left_, oright_] )) } })
类型二 思路
获取
调用表达式
的函数
和参数
,然后 生成函数节点
,把函数节点
添加到当前代码块
的最前面
,然后把原始
的调用表达式
替换为新的调用表达式
,只处理 一层的fun('aa')
不处理fun.fun('aa')
例子
function add(a, b) { return a + b; } console.log(add(2, 3))
代码
// 调用表达式 转 花指令 traverse(ast, { CallExpression(path) { let callee_ = path.node.callee; let arguments_ = path.node.arguments; if(!type.isIdentifier(callee_)){ // 只处理 一层的 `fun('aa')` 不处理 `fun.fun('aa')` return } // 构造函数节点 let funName = path.scope.generateUidIdentifier('fff'); let f = type.identifier(name = 'f') // 第一个参数,是 函数 let params_ = []; // 参数列表 for (let arg in arguments_) { params_.push(name = path.scope.generateUidIdentifier('arg')) } let func = type.functionDeclaration( id = funName, params = [f].concat(params_), body = type.blockStatement( body = [type.returnStatement( type.callExpression( callee = f, _arguments = params_ ) )] ) ) // 把生成的函数节点添加到当前代码的最前面 let blockStatement = path.findParent(function (p) { return p.isBlockStatement() || p.isProgram() // 兼容处理 如何函数需要添加到 最外面层 }) blockStatement.node.body.unshift(func); // 替换原节点 为 调用表达式 arguments_.unshift(callee_) path.replaceWith(type.callExpression( callee = funName, _arguments = arguments_ )) path.skip() } })
版权声明:《 【AST 混淆】四、代码块的混淆 》为明妃原创文章,转载请注明出处!
最后编辑:2022-4-14 09:04:32