特别说明:本文 生成节点时,函数的使用对于 Js 来说是错误的(不能指定参数给值),这样写是方便 看节点属性
思路
流程平坦化有好几种形式,结果都是 打乱代码执行 流程,原理都一样,while-switch、 for-switch
当然 阿里 极验 的平坦流混淆,更复杂,这里只是最简单的,分发器还能看见
while (!![]){ // 一个死循环 switch (...){ // 每次循环 改变 switch 的判断,而走不同的分支 case "0": ... case "1": ... } }
实现
获取代码块,映射
代码块的 执行循序{index:i, value: 代码块节点}
,然后 打乱 执行顺序
,构造 分发器
,构建 死循环
,再构建 switch
分支,替换
原来的代码块
// 流程平坦流 混淆 traverse(ast, { FunctionExpression(path) { let blockStatement = path.node.body; // 映射 语句执行顺序 let statement = blockStatement.body.map((v, i) => { return {index: i, value: v} }) // 流程打乱语句 for (let i = 1; i < statement.length; i++) { const j = Math.floor(Math.random() * (i + 1)); [statement[i], statement[j]] = [statement[j], statement[i]]; } // 构建分发器,创建 swichCase 数组 let dispenserArr = []; // 流程分发数组 let cases = []; // 构建 cases 节点 statement.map((v, i) => { dispenserArr[v.index] = i; let switchCase = type.switchCase( test = type.numericLiteral(value = i), consequent = [v.value, type.continueStatement()] ) cases.push(switchCase); }) // 生成 _array 和 _index 标识符,利用 BableAPI 保证不重名 let array = path.scope.generateUidIdentifier('array') let index = path.scope.generateUidIdentifier('index') // 生成 var _array = '0|2|2'.spiit('|'), index=0; 节点 let dispenserStr = dispenserArr.join('|'); let dispenser = type.variableDeclaration( kind = 'var', declarations = [type.variableDeclarator( id = array, init = type.callExpression( callee = type.memberExpression( object = type.stringLiteral(value = dispenserStr), property = type.identifier(name = 'split') ), _arguments = [type.stringLiteral(value = '|')] ), ), type.variableDeclarator( id = index, init = type.numericLiteral(value = 0)) ] ) // 生成 while-swiich 节点 let whileSta = type.whileStatement( test = type.unaryExpression( // while 循环条件节点 operator = '!', argument = type.unaryExpression( operator = '!', argument = type.arrayExpression( elements = [] ))), body = type.blockStatement( // swiich 节点 body = [type.switchStatement( discriminant = type.unaryExpression( // 构建 switch 判断部分 switch(+array[index++]) operator = '+', argument = type.memberExpression( object = array, property = type.updateExpression( operator = '++', argument = index), computed = true), ), cases = cases) // case 节点 ] ) ) // 用分发器 和 while 循环 来替换原有的节点 path.get('body').replaceWith(type.blockStatement( body = [dispenser, whileSta])) } })
版权声明:《 【AST 混淆】七、实现流程平坦化 》为明妃原创文章,转载请注明出处!
最后编辑:2022-4-19 08:04:25