吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5336|回复: 46
收起左侧

[Web逆向] 使用AST解混淆某数5代

  [复制链接]
alanhays 发表于 2023-3-22 19:02
本帖最后由 alanhays 于 2023-3-24 22:20 编辑

这是一个瑞数5代解混淆的案例,本案例未考虑通用性,只是专项学习性的插件。这里只是解混淆了外层代码,并不是解混淆内部生成的代码。

If节点转Switch节点

例子

这里将if节点转换成switch,当然只是针对这段代码而写的。
这里是为switch合并做预处理,只针对最内层case,外层case并不在处理范围。

if (_$nE < 4) {
    if (_$nE < 1) {
        _$hk = window,
            _$NB = String,
            _$OA = Array,
            _$Qd = document,
            _$uO = Date;
    } else if (_$nE < 2) {
        _$bx = _$hk['$_ts'] = {};
    } else if (_$nE < 3) {
        _$bx = _$hk['$_ts'];
    } else {
        _$_l = !_$bx;
    }
} else {
    if (_$nE < 5) {
        _$UX(0);
    } else if (_$nE < 6) {
        if (!_$_l)
            _$nI += 1;
    } else if (_$nE < 7) {
        _$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
    } else {
        return;
    }
}
----------------------------------------------
switch (_$nE) {
  case 3:
    switch (_$nE) {
      case 0:
        _$hk = window, _$NB = String, _$OA = Array, _$Qd = document, _$uO = Date;
      case 1:
        _$bx = _$hk['$_ts'] = {};
      case 2:
        _$bx = _$hk['$_ts'];
      case 3:
        _$_l = !_$bx;
    }
  case 4:
    switch (_$nE) {
      case 4:
        _$UX(0);
      case 5:
        if (!_$_l) _$nI += 1;
      case 6:
        _$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
      case 7:
        return;
    }
}

插件

function ifToSwitchNode(path, pathStr = "test.left") {
    function getNodes(path, list = []) {
        if (!path.isIfStatement()) {
            list.push({
                type: "SwitchCase",
                consequent: path.node.body,
                test: types.valueToNode(list[list.length - 2].right.value)
            })
            return list;
        }
        items.forEach(n => {
            let tmep = path.get(n);
            list.push(tmep.node);
        })
        return getNodes(path.get("alternate"), list);
    }

    function reductionTest(test) {
        switch (test.operator) {
            case "<":
                test = types.valueToNode(test.right.value - 1)
                break;
            case "===":
                test = types.valueToNode(test.right.value)
                break;
        }
        return test;
    }

    let items = ["test", "consequent"];
    let nodes = getNodes(path);
    let cases = [], count = Math.trunc(nodes.length / items.length);
    if (nodes.length % 2) cases.push(nodes.pop());
    for (let i = 0; i < count; i++) {
        cases.push({
            type: "SwitchCase",
            consequent: nodes.pop().body,
            test: reductionTest(nodes.pop())
        })
    }
    return {
        type: "SwitchStatement",
        discriminant: path.get(pathStr).node,
        cases: cases.reverse()
    }
}

const ifToSwitch = {
    IfStatement(path) {
        let {node} = path;
        let {alternate} = node;
        if (alternate === null) return;
        let newNode = ifToSwitchNode(path);
        path.replaceInline(newNode)
    }
}

switch合并

例子

这里将多维的switch合并为一维的。

switch (_$nE) {
  case 3:
    switch (_$nE) {
      case 0:
        _$hk = window, _$NB = String, _$OA = Array, _$Qd = document, _$uO = Date;
      case 1:
        _$bx = _$hk['$_ts'] = {};
      case 2:
        _$bx = _$hk['$_ts'];
      case 3:
        _$_l = !_$bx;
    }
  case 4:
    switch (_$nE) {
      case 4:
        _$UX(0);
      case 5:
        if (!_$_l) _$nI += 1;
      case 6:
        _$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
      case 7:
        return;
    }
}
----------------------------------------------
switch (_$nE) {
  case 0:
    _$hk = window, _$NB = String, _$OA = Array, _$Qd = document, _$uO = Date;
  case 1:
    _$bx = _$hk['$_ts'] = {};
  case 2:
    _$bx = _$hk['$_ts'];
  case 3:
    _$_l = !_$bx;
  case 4:
    _$UX(0);
  case 5:
    if (!_$_l) _$nI += 1;
  case 6:
    _$bj = [4, 16, 64, 256, 1024, 4096, 16384, 65536];
  case 7:
    return;
}

插件

function getCaseAll(cases, caseAll = []) {
    if (!types.isSwitchStatement(cases[0].consequent[0])) return cases;
    for (let i = 0; i < cases.length; i++) {
        let caseNode = cases[i];
        if (!types.isSwitchStatement(caseNode.consequent[0])) {
            if (types.isSwitchStatement(cases[i - 1].consequent[0])) caseAll.push(caseNode);
            break;
        }
        caseAll = caseAll.concat(getCaseAll(caseNode.consequent[0].cases));
    }
    return caseAll;
}

const mergeSwitch = {
    SwitchStatement(path) {
        if (path.parentPath.isSwitchCase()) return;
        let nextPath = path.get("cases.0.consequent.0");
        if (!types.isSwitchStatement(nextPath)) return;
        path.node.cases = getCaseAll(path.node.cases);
    }
}

缓存关键数据

插件

这里是为方便后续操作做准备。

/**
 * 向上查询某类型的ParentPath
 * home.php?mod=space&uid=952169 path
 * @param type
 * @returns {null|*}
 */
function findParentPath(path, type) {
    while (!path.isProgram()) {
        path = path.parentPath;
        if (!path[`is${type}`]()) return path.parentPath;
    }
}
/**
 * 节点筛选器
 * @param list  [node/path...] 元素node或path都可
 * @param filter 类型 array [str...] 类型列表
 * @param filterMode 过滤器模式 默认false | false - 只输出配置的类型 true - 过滤(不输出)配置的类型
 * @param isCode 默认true返回代码 false返回节点列表
 * @returns {string|array} code/itemList
 */
function nodeFilter(list, filter = [true], filterMode = false, isCode = true) {
    let code = "", itemList = [];
    if (!list.length) return "";
    let isPath = typeof list[0].isReturnStatement === "function";
    if (isPath) list = list.reverse();
    list.forEach(node => {
        if (isPath) node = node.node;
        if (filter[0] === true ||
            (!filterMode === filter.includes(node.type))) {
            isCode ? code += `${generator(node).code}\n` : itemList.push(node);
        }
    })
    return isCode ? code : itemList;
}
/***
 * 获取需要用到的对象名和节点
 * @param path
 * @param resultPath
 */
function getFuncInfo(path, resultPath) {
    let info = Object();
    info["switchPath"] = path.get('body.body.1');
    let expressionNode = path.node.body.body[0];
    let arrayName = expressionNode.expression.right.object.name;
    let largeArrayInit = path.scope.getBinding(arrayName).path.node.init;
    let largeArrayName = largeArrayInit.object.name;
    let largeArrayIndex = largeArrayInit.property.value;
    info["array"] = eval(generator(path.scope.getBinding(largeArrayName).path.node.init).code)[largeArrayIndex];
    info["indexName"] = expressionNode.expression.right.property.argument.name;
    info["variable"] = nodeFilter(path.getAllPrevSiblings(), ['VariableDeclaration', 'FunctionDeclaration'], false, false);
    info["path"] = resultPath;
    return info;
}
let funcInfo = {};
/***
 * 缓存关键数据
 * @type {{WhileStatement(*): void}}
 */
const cacheCriticalData = {
    WhileStatement(path) {
        let resultPath = findParentPath(path, "FunctionDeclaration");
        if (!resultPath) return;
        let funcName = "main";
        if (!resultPath.isFunctionExpression()) {
            funcName = resultPath.node.id.name;
        }
        //  缓存path和关键变量名以便后续使用
        funcInfo[funcName] = getFuncInfo(path, resultPath);
    }
}

合并调用信息前的准备

插件

let cache = {};
const mergeCallInfo = {
    CallExpression(path) {
        let name = path.node.callee.name;
        if (Object.keys(funcInfo).includes(name)) {
            let now = funcInfo[name];
            const {cases} = now.switchPath.node;
            let value = path.node.arguments[0].value;
            let replaceBody = [];
            let callCode = path.toString();
            if (Object.keys(cache).includes(callCode)) return;
            let constantViolations = (() => {
                let list = [];
                now.path.scope.getBinding(now.indexName).constantViolations.forEach(p => list.push(p.node.start))
                return list;
            })();
            for (let i = value; i < now.array.length; i++) {
                let index = now.array[i];
                let case_body = cases[index].consequent[0];
                if (types.isIfStatement(case_body)) case_body.start = case_body.consequent.start;
                if (case_body && constantViolations.includes(case_body.start)) {
                    if (types.isIfStatement(case_body)) {
                        let node = JSON.parse(JSON.stringify(path.node));
                        node.arguments[0].value = evaluationExpression(case_body.consequent, now.indexName, i);
                        case_body.consequent = node;
                    } else {
                        i = evaluationExpression(case_body, now.indexName, i);
                        case_body = null;
                    }
                }
                if (!case_body) continue;
                replaceBody.push(case_body);
                if (types.isReturnStatement(case_body)) break;
            }
            if (!replaceBody.length) return;
            replaceBody = now.variable.concat(replaceBody);
            cache[callCode] = {
                type: "ExpressionStatement",
                expression: {
                    type: "CallExpression",
                    callee: {
                        type: "FunctionExpression",
                        params: now.path.node.params,
                        body: {
                            type: "BlockStatement",
                            body: replaceBody
                        }
                    },
                    arguments: path.node.arguments
                }
            };
        }
    }
}

$#合并调用

例子

 switch (_$8w) {
        case 0:
          _$hk['$_ts'] = {};
        case 1:
          _$qA = _$vT.substr(_$yG, _$B_).split(_$NB.fromCharCode(255));
        case 2:
          var _$6U = _$UX(10);
        case 3:
          var _$B_ = _$z6();
        case 4:
          _$6U += "boDAnZapOCX8xJU2au447jYLkgwNztHO7AuauIp4P26lQTtdW5d$Q3e1G5F9IC3qE8ksXFTNV0jGl75dTsyxNioGl4Svu60uHKu3zrllyNPYY939zhkvUkumErxFngcRvZax5JQGjs3gejM9wARz_JsdQepMi5S6GKrhg3LvVtwUD70h1ZXQA3OjFPNF";
        case 5:
          _$pY = _$8_ === undefined || _$8_ === "";
        case 6:
          return 0;
        case 7:
          return _$UX(12, _$6U);
        case 8:
          var _$nE = _$z6();
        case 9:
          _$8_._$hk = 12;
        case 10:
          var _$dQ = _$z6();
----------------------------------------------
   _$8_._$DK = 7;
  _$8_._$hk = 12;
  _$8_._$6n = 4;
  _$8_._$Hn = "_$74";
  _$8_._$Li = "_$v5";
  _$8_._$gP = "_$pl";
  _$8_._$jq = "_$ez";
  _$8_._$u5 = "_$2X";
  _$8_._$Zu = "_$Gn";
  _$8_._$XK = "_$qK";
  _$8_._$jS = "_$Ui";
  _$8_._$pY = "_$qL";
  _$8_._$J6 = "_$nE";
  _$8_._$OA = "gabGed5GyIa";
  _$8_._$2t = "JTKWP2.d7Dq";
  _$8_._$uO = "Cr9JCX._VGtwUqL.MQKwjE";
  _$8_._$B2 = "8ew8MTOflwq";
  _$8_._$NB = _$KM;
  _$8_._$Lc = "hLBEA6IMPqBY1gfp_t9V1G";
  _$8_._$tQ = 57;

插件

因为直接替换卡住了,所以返璞归真正则替换吧!

function processCharacters(str) {
    return str.replace(/\$/g, "\\$").replace(/\[/g, "\\[")
        .replace(/\]/g, "\\]").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/\+/g, "\\+");
}
function replaceMergeCall() {
    let cacheKeys = Object.keys(cache);
    let {code} = generator(ast);
    cacheKeys = [...new Set(cacheKeys)];
    cacheKeys = [...cacheKeys, ...cacheKeys, ...cacheKeys];
    cacheKeys.forEach(key => {
        let re = new RegExp(processCharacters(key), "g");
        let callCode = nodeFilter([cache[key]]);
        code = code.replace(re, callCode.replace(/\'/g, '"'));
    })
    ast = parser.parse(code.replace(/;\n;/g, ";"));
}

拆分逗号表达式

插件

copy的蔡老板的插件,有现成的何必动手。

const decode_comma = {
    //破解逗号表达式,兼容之前的脚本
    ExpressionStatement(path) {
        let {expression} = path.node;
        if (!types.isSequenceExpression(expression)) return;
        let body = [];
        expression.expressions.forEach(express => {
            body.push(types.expressionStatement(express));
        })
        path.replaceInline(body);
    }
}

删除未引用

插件

/***
 * 删除未引用
 * @type {{VariableDeclarator(*): void}}
 */
const unreferenced = {
    'VariableDeclarator|FunctionDeclaration'(path) {
        const func_name = path.node.id.name;
        const binding = path.scope.getBinding(func_name);
        // 如果变量没有被引用过,那么删除也没关系
        // 此处不能用有无修改过进行判断,因为没有被修改过并不意味着没用
        if (binding && !binding.referenced) path.remove();
    }
}

定制的删除未引用

插件

ast学的不深就乱写了,本着能用就行。

const forUnreferenced = {
    VariableDeclarator(path) {
        let _path = path.parentPath.parentPath.parentPath;
        if (!_path.isFunctionExpression() || !_path.node.params.length) return;
        let body = _path.node.body.body;
        let start = body[0].start;
        let end = body[body.length - 1].end;
        let name = path.node.id.name;
        const binding = path.scope.getBinding(name);
        if (!binding) return;
        let referencePaths = binding.referencePaths;
        let referenced = 0;
        for (let i = 0; i < binding.references; i++) {
            let rp = referencePaths[i];
            if (start < rp.node.start && rp.node.start < end) referenced++;
        }
        if (referenced) return;
        path.remove();
    }
}

替换值函数

只return数字的函数。

const replaceValueFunc = {
    FunctionDeclaration(path) {
        let {body, id, params} = path.node;
        if (params.length || body.body.length !== 1) return;
        const binding = path.scope.getBinding(id.name);
        if (!binding) return;
        let referencePaths = path.scope.getBinding(id.name).referencePaths;
        referencePaths.forEach(rp => {
            rp.parentPath.replaceInline(body.body[0].argument)
        })
        path.remove();
    }
}

取反if

处理这if节点  if(!xx) function (xx) { xxx }(xx)

const negateJudgment = {
    IfStatement(path) {
        let {test, consequent} = path.node;
        if (!types.isUnaryExpression(test)) return;
        if (!types.isCallExpression(consequent.expression)) return;
        path.node.consequent = consequent.expression.callee.body;
    }
}

解码控制流

到这里只有7个case了

const decodeControlFlow = {
    WhileStatement(path) {
        let {body} = path.node;
        let switchNode = body.body[1];
        let {cases} = switchNode;
        let replace_body = [];
        funcInfo['main'].array.forEach(index => {
                let case_body = cases[index].consequent;
                if (types.isContinueStatement(case_body[case_body.length - 1])) {
                    case_body.pop();
                }
                replace_body = replace_body.concat(case_body);
            }
        );
        path.replaceInline(replace_body);
    }
}

到这里解混淆的绝大部分,具体流程也清晰可见了。

完整插件


const fs = require('fs');
//babel库相关,解析,转换,构建,生产
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const types = require("@babel/types");
const generator = require("@babel/generator").default;
//读取文件
let encode_file = "./encode.js", decode_file = "./decode_result.js";
if (process.argv.length > 2) {
    encode_file = process.argv[2];
}
if (process.argv.length > 3) {
    decode_file = process.argv[3];
}
let jsCode = fs.readFileSync(encode_file, {encoding: "utf-8"});
//转换为ast树
let ast = parser.parse(jsCode);
function ifToSwitchNode(path, pathStr = "test.left") {
    function getNodes(path, list = []) {
        if (!path.isIfStatement()) {
            list.push({
                type: "SwitchCase",
                consequent: path.node.body,
                test: types.valueToNode(list[list.length - 2].right.value)
            })
            return list;
        }
        items.forEach(n => {
            let tmep = path.get(n);
            list.push(tmep.node);
        })
        return getNodes(path.get("alternate"), list);
    }
    function reductionTest(test) {
        switch (test.operator) {
            case "<":
                test = types.valueToNode(test.right.value - 1)
                break;
            case "===":
                test = types.valueToNode(test.right.value)
                break;
        }
        return test;
    }
    let items = ["test", "consequent"];
    let nodes = getNodes(path);
    let cases = [], count = Math.trunc(nodes.length / items.length);
    if (nodes.length % 2) cases.push(nodes.pop());
    for (let i = 0; i < count; i++) {
        cases.push({
            type: "SwitchCase",
            consequent: nodes.pop().body,
            test: reductionTest(nodes.pop())
        })
    }
    return {
        type: "SwitchStatement",
        discriminant: path.get(pathStr).node,
        cases: cases.reverse()
    }
}
const ifToSwitch = {
    IfStatement(path) {
        let {node} = path;
        let {alternate} = node;
        if (alternate === null) return;
        let newNode = ifToSwitchNode(path);
        path.replaceInline(newNode)
    }
}
function getCaseAll(cases, caseAll = []) {
    if (!types.isSwitchStatement(cases[0].consequent[0])) return cases;
    for (let i = 0; i < cases.length; i++) {
        let caseNode = cases[i];
        if (!types.isSwitchStatement(caseNode.consequent[0])) {
            if (types.isSwitchStatement(cases[i - 1].consequent[0])) caseAll.push(caseNode);
            break;
        }
        caseAll = caseAll.concat(getCaseAll(caseNode.consequent[0].cases));
    }
    return caseAll;
}
const mergeSwitch = {
    SwitchStatement(path) {
        if (path.parentPath.isSwitchCase()) return;
        let nextPath = path.get("cases.0.consequent.0");
        if (!types.isSwitchStatement(nextPath)) return;
        path.node.cases = getCaseAll(path.node.cases);
    }
}
/**
 * 向上查询某类型的ParentPath
 * @param path
 * @param type
 * @returns {null|*}
 */
function findParentPath(path, type) {
    while (!path.isProgram()) {
        path = path.parentPath;
        if (!path[`is${type}`]()) return path.parentPath;
    }
}
/***
 * 获取需要用到的对象名和节点
 * @param path
 * @param resultPath
 */
function getFuncInfo(path, resultPath) {
    let info = Object();
    info["switchPath"] = path.get('body.body.1');
    let expressionNode = path.node.body.body[0];
    let arrayName = expressionNode.expression.right.object.name;
    let largeArrayInit = path.scope.getBinding(arrayName).path.node.init;
    let largeArrayName = largeArrayInit.object.name;
    let largeArrayIndex = largeArrayInit.property.value;
    info["array"] = eval(generator(path.scope.getBinding(largeArrayName).path.node.init).code)[largeArrayIndex];
    info["indexName"] = expressionNode.expression.right.property.argument.name;
    info["variable"] = nodeFilter(path.getAllPrevSiblings(), ['VariableDeclaration', 'FunctionDeclaration'], false, false);
    info["path"] = resultPath;
    return info;
}
let funcInfo = {};
/***
 * 缓存关键数据
 * @type {{WhileStatement(*): void}}
 */
const cacheCriticalData = {
    WhileStatement(path) {
        let resultPath = findParentPath(path, "FunctionDeclaration");
        if (!resultPath) return;
        let funcName = "main";
        if (!resultPath.isFunctionExpression()) {
            funcName = resultPath.node.id.name;
        }
        //  缓存path和关键变量名以便后续使用
        funcInfo[funcName] = getFuncInfo(path, resultPath);
    }
}
/**
 * 节点筛选器
 * @param list  [node/path...] 元素node或path都可
 * @param filter 类型 array [str...] 类型列表
 * @param filterMode 过滤器模式 默认false | false - 只输出配置的类型 true - 过滤(不输出)配置的类型
 * @param isCode 默认true返回代码 false返回节点列表
 * @returns {string|array} code/itemList
 */
function nodeFilter(list, filter = [true], filterMode = false, isCode = true) {
    let code = "", itemList = [];
    if (!list.length) return "";
    let isPath = typeof list[0].isReturnStatement === "function";
    if (isPath) list = list.reverse();
    list.forEach(node => {
        if (isPath) node = node.node;
        if (filter[0] === true ||
            (!filterMode === filter.includes(node.type))) {
            isCode ? code += `${generator(node).code}\n` : itemList.push(node);
        }
    })
    return isCode ? code : itemList;
}
/**
 * 计算表达式
 * @param node 表达式 node  type: Expression
 * @param name
 * @param value
 * @returns {any} 输出表达式code执行的结果
 */
function evaluationExpression(node, name, value) {
    let replaceList = [[name, value]];
    if (types.isExpressionStatement(node)) {
        //  处理赋值操作直接返回value
        if (node.expression.operator === "=") return node.expression.right.value;
        replaceList = replaceList.concat([["\\+=", "+"], ["\\-=", "-"]]);
    }
    let reg, code = generator(node).code;
    replaceList.forEach(item => {
        //  动态生成正则 需要注意$字符
        reg = new RegExp(`${item[0].replace(/\$/g, "\\$")}`, "g");
        //  获取testCode | 将替换标识符为value 例子 -> let v = 1 | test节点代码 v >= 1 | 替换后 1 >= 1
        code = code.replace(reg, item[1]);
    });
    try {
        return eval(code);
    } catch (e) {
        console.error(e)
        debugger
    }
}
let cache = {};
const mergeCallInfo = {
    CallExpression(path) {
        let name = path.node.callee.name;
        if (Object.keys(funcInfo).includes(name)) {
            let now = funcInfo[name];
            const {cases} = now.switchPath.node;
            let value = path.node.arguments[0].value;
            let replaceBody = [];
            let callCode = path.toString();
            if (Object.keys(cache).includes(callCode)) return;
            let constantViolations = (() => {
                let list = [];
                now.path.scope.getBinding(now.indexName).constantViolations.forEach(p => list.push(p.node.start))
                return list;
            })();
            for (let i = value; i < now.array.length; i++) {
                let index = now.array[i];
                let case_body = cases[index].consequent[0];
                if (types.isIfStatement(case_body)) case_body.start = case_body.consequent.start;
                if (case_body && constantViolations.includes(case_body.start)) {
                    if (types.isIfStatement(case_body)) {
                        let node = JSON.parse(JSON.stringify(path.node));
                        node.arguments[0].value = evaluationExpression(case_body.consequent, now.indexName, i);
                        case_body.consequent = node;
                    } else {
                        i = evaluationExpression(case_body, now.indexName, i);
                        case_body = null;
                    }
                }
                if (!case_body) continue;
                replaceBody.push(case_body);
                if (types.isReturnStatement(case_body)) break;
            }
            if (!replaceBody.length) return;
            replaceBody = now.variable.concat(replaceBody);
            cache[callCode] = {
                type: "ExpressionStatement",
                expression: {
                    type: "CallExpression",
                    callee: {
                        type: "FunctionExpression",
                        params: now.path.node.params,
                        body: {
                            type: "BlockStatement",
                            body: replaceBody
                        }
                    },
                    arguments: path.node.arguments
                }
            };
        }
    }
}
function processCharacters(str) {
    return str.replace(/\$/g, "\\$").replace(/\[/g, "\\[")
        .replace(//g, "\\]").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/\+/g, "\\+");
}
function replaceMergeCall() {
    let cacheKeys = Object.keys(cache);
    let {code} = generator(ast);
    cacheKeys = [...new Set(cacheKeys)];
    cacheKeys = [...cacheKeys, ...cacheKeys, ...cacheKeys];
    cacheKeys.forEach(key => {
        let re = new RegExp(processCharacters(key), "g");
        let callCode = nodeFilter([cache[key]]);
        code = code.replace(re, callCode.replace(/\'/g, '"'));
    })
    ast = parser.parse(code.replace(/;\n;/g, ";"));
}
const decode_comma = {
    //破解逗号表达式,兼容之前的脚本
    ExpressionStatement(path) {
        let {expression} = path.node;
        if (!types.isSequenceExpression(expression)) return;
        let body = [];
        expression.expressions.forEach(express => {
            body.push(types.expressionStatement(express));
        })
        path.replaceInline(body);
    }
}
/***
 * 删除未引用
 * @type {{VariableDeclarator(*): void}}
 */
const unreferenced = {
    'VariableDeclarator|FunctionDeclaration'(path) {
        const func_name = path.node.id.name;
        const binding = path.scope.getBinding(func_name);
        // 如果变量没有被引用过,那么删除也没关系
        // 此处不能用有无修改过进行判断,因为没有被修改过并不意味着没用
        if (binding && !binding.referenced) path.remove();
    }
}
const replaceValueFunc = {
    FunctionDeclaration(path) {
        let {body, id, params} = path.node;
        if (params.length || body.body.length !== 1) return;
        const binding = path.scope.getBinding(id.name);
        if (!binding) return;
        let referencePaths = path.scope.getBinding(id.name).referencePaths;
        referencePaths.forEach(rp => {
            rp.parentPath.replaceInline(body.body[0].argument)
        })
        path.remove();
    }
}
const forUnreferenced = {
    VariableDeclarator(path) {
        let _path = path.parentPath.parentPath.parentPath;
        if (!_path.isFunctionExpression() || !_path.node.params.length) return;
        let body = _path.node.body.body;
        let start = body[0].start;
        let end = body[body.length - 1].end;
        let name = path.node.id.name;
        const binding = path.scope.getBinding(name);
        if (!binding) return;
        let referencePaths = binding.referencePaths;
        let referenced = 0;
        for (let i = 0; i < binding.references; i++) {
            let rp = referencePaths[i];
            if (start < rp.node.start && rp.node.start < end) referenced++;
        }
        if (referenced) return;
        path.remove();
    }
}
const negateJudgment = {
    IfStatement(path) {
        let {test, consequent} = path.node;
        if (!types.isUnaryExpression(test)) return;
        if (!types.isCallExpression(consequent.expression)) return;
        path.node.consequent = consequent.expression.callee.body;
    }
}
const decodeControlFlow = {
    WhileStatement(path) {
        let {body} = path.node;
        let switchNode = body.body[1];
        let {cases} = switchNode;
        let replace_body = [];
        funcInfo['main'].array.forEach(index => {
                let case_body = cases[index].consequent;
                if (types.isContinueStatement(case_body[case_body.length - 1])) {
                    case_body.pop();
                }
                replace_body = replace_body.concat(case_body);
            }
        );
        path.replaceInline(replace_body);
    }
}
console.time("处理完毕,耗时")
traverse(ast, ifToSwitch)
traverse(ast, mergeSwitch)
traverse(ast, cacheCriticalData)
traverse(ast, mergeCallInfo)
replaceMergeCall()
traverse(ast, decode_comma)
traverse(ast, unreferenced)
traverse(ast, forUnreferenced)
traverse(ast, replaceValueFunc)
traverse(ast, negateJudgment)
traverse(ast, decodeControlFlow)
console.timeEnd("处理完毕,耗时")
//生成新的js code,并保存到文件中输出
let {code} = generator(ast, opts = {jsescOption: {"minimal": true}});
fs.writeFile(decode_file, code, (err) => {
});

免费评分

参与人数 17吾爱币 +17 热心值 +15 收起 理由
Staminaxin + 1 + 1 我很赞同!
allspark + 1 + 1 用心讨论,共获提升!
onlywey + 1 + 1 用心讨论,共获提升!
popolu1472 + 1 + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
SSBB007 + 1 我很赞同!
likewebxcj + 1 热心回复!
wangchaolin + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
JonesDean + 1 + 1 碉堡了
N1san + 1 + 1 热心回复!
wangkaixuan0122 + 1 + 1 我很赞同!
漁滒 + 3 + 1 我很赞同!
抱歉、 + 1 用心讨论,共获提升!
悦来客栈的老板 + 1 + 1 我很赞同!
Yangzaipython + 1 用心讨论,共获提升!
helian147 + 1 + 1 热心回复!
gorkys + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Ram9943 发表于 2023-3-23 12:38
我丢,大佬太强了
wasm2023 发表于 2023-3-23 21:42
fengyun123123 发表于 2023-3-23 22:16
 楼主| alanhays 发表于 2023-3-23 22:54
wasm2023 发表于 2023-3-23 21:42
大佬,v7解混淆啥时候添加呀

简单看了一下免费V7,挺简单的。vip版不知道,假如您这里有样本请发我。预计7天内吧。
wasm2023 发表于 2023-3-24 00:01
已私发,密码wasm2023?
悦来客栈的老板 发表于 2023-3-24 08:58
这么好的文章必须顶起来啊,又学到知识了。
ranlele 发表于 2023-3-24 09:14
牛啊,大佬,感谢分享
 楼主| alanhays 发表于 2023-3-24 10:02
悦来客栈的老板 发表于 2023-3-24 08:58
这么好的文章必须顶起来啊,又学到知识了。

真大佬来了,我就是跟着您学习的。
 楼主| alanhays 发表于 2023-3-24 10:03
wasm2023 发表于 2023-3-24 00:01
已私发,密码wasm2023?

已经解出来,就写了一个插件,加上V6原来的插件就跑出来了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-3-29 01:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表