【AST 混淆】七、实现流程平坦化

特别说明:本文 生成节点时,函数的使用对于 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]))
    }
})

mark

发表评论 / Comment

用心评论~