吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4262|回复: 14
收起左侧

[Web逆向] 某数控制流改写

[复制链接]
lsq665 发表于 2023-5-10 17:40
本帖最后由 lsq665 于 2023-8-4 11:54 编辑

仅供学习,不得用于商业用途,侵删。

某数控制流有好多种,例如
Quicker_20230510_153811.png
Quicker_20230510_153637.png
虽然判断条件的形式不同,但整体结构都基本相同,所以可以对这种结构统一进行改写
,伪代码如下:
[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
_$OR = [1,2,3,4];
while (1) {
    _$r4 = _$OR[_$NE++];
    if (test1) {
        statement1
    } else if (test2) {
        statement2
    } else if (test3) {
        statement3
    } else {
        statement4
    }
}


上面的代码可以改写为另一种形式,伪代码如下:
[JavaScript] 纯文本查看 复制代码
1
2
3
4
5
6
7
_$OR = [1,2,3,4];
while (1) {
    _$r4 = _$OR[_$NE++];
    if (test1) statement1;
    if (!test1 && test2) statement2;
    if (!test1 && !test2 && test3) statement3;
    if (!test1 && !test2 && !test3) statement4;


由于这些if条件是互斥的,一个索引数组的值只会进入到一个if语句中,所以如果将这些if的条件收集起来进行遍历,就可以得到每个索引对应的语句,伪代码如下:
[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
let cases = [];
let arr = [['test1',statement1],['!test1 && test2',statement2],['!test1 && !test2 && test3',statement3],['!test1 && !test2 && !test3',statement4]];
for (let index of [1,2,3,4]){
    for (let [condition,statement] of arr){
        if (condition){
            cases.push([index,statement])
        }
    }
}
/*
=> [
     [1,statement1],
     [2,statement2],
     [3,statement3],
     [4,statement4]
 ]
 */

最终会生成一个索引与语句对应的数组,可以用来生成最终的switch case语句。

所有最终的改写过程是先将索引数组写到最终调用位置,然后通过递归if语句获取条件和对应的语句,然后通过索引数组进行遍历生成索引于语句对应的数组,最后转化为switch语句;
实现代码如下:
[JavaScript] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;
const t = require('@babel/types');
const fs = require('fs');
 
const start = Date.now();
 
 
const jscode = fs.readFileSync("./input.js", {
    encoding: "utf-8"
});
let code;
let ast = parser.parse(jscode);
 
 
// ---------------------------还原数组 如果第一句是数组
`
(function() {
    var _$rD = 0
      , _$zG = $_ts.scj
      , _$cj = [[],[],[],[],[]];
      ......... 
})()
`
traverse(ast,{
    Program(path){
        if (!path.get('body.0')?.get('expression')?.get('callee')?.get('body')?.get('body.0')?.isVariableDeclaration()) return;
        let func_statement_path_1 = path.get('body')[0].get('expression.callee.body.body')[0];
        func_statement_path_1.get('declarations').forEach(function (v) {
            if (v.get('init').isArrayExpression()){
                let binding = func_statement_path_1.scope.getBinding(v.node.id.name);
                let arr = v.node.init.elements;
                binding && binding.constantViolations.length == 0 && binding.referencePaths.forEach(function (vv) {
                    if (vv.parentPath.isMemberExpression()
                        && vv.parent.object.name == v.node.id.name
                        && vv.parentPath.get('property').isNumericLiteral()
                    ){
                        vv.parentPath.replaceWith(arr[vv.parent.property.value]);
                    }
                })
            }
        });
    }
});
 
 
// ---------------------------还原控制流
traverse(ast, {  // 给if语句把 {} 都加上
    IfStatement(path) {
        let {consequent, alternate} = path.node;
        if (consequent && !t.isBlockStatement(consequent)) {
            path.get('consequent').replaceWith(t.BlockStatement([consequent]));
        }
        if (alternate && !t.isBlockStatement(alternate)) {
            path.get('alternate').replaceWith(t.BlockStatement([alternate]));
        }
    }
});
 
function judge_include_identifier(path, idt) {
    // path:if语句的test节点的path对象,用于判断 “判断条件中”是否有不是指定的标识符,避免遍历非控制流的if语句
    // idt 标识符
    let flag = true;
    // 如果test节点有控制流的标识符,返回true,否则返回false
    path.traverse({
        Identifier(path_) {
            if (path_.node.name != idt) {
                flag = false
            }
        }
    })
    return flag
}
 
function parseIfStatement(path, test_li, idt, li) {
    // path: if语句的path对象, test_li: 用来当前存储条件,idt:控制流中条件中的标识符 ,li:存储结果
    let {consequent, alternate, test} = path.node;
    // -----------------------------递归 test==true--------------------------------------------
    // if成立时的结果存在 且为{}语句 且{}中是if语句 且{}中if语句的条件包含指定标识符【递归条件】
    if (consequent && t.isBlockStatement(consequent)
        && t.isIfStatement(consequent.body[0])
        && judge_include_identifier(path.get('consequent.body')[0].get('test'), idt)
    ) {
        // 符合条件就进入子if语句中,将当前的条件加入到数组【是if==true的语句,直接加】
        test_li.push(test);
        parseIfStatement(path.get('consequent.body')[0], test_li, idt, li);
        test_li.pop(); // 子语句遍历结束后弹出条件,保持状态。
    } else {
        // 没有控制流,递归结束
        test_li.push(test);
        // 根据数组构造判断条件的字符串
        let condition = test_li.map(function (v) {
            return generator(v).code
        }).join(' && ');
        test_li.pop();
        let case1 = path.node.consequent.body;
        li[condition] = case1;
    }
    // ----------------------递归 test==false 即 else中的语句---------------------------------------
    // else 语句存在 且 是{}语句 且{}中是if语句 且{}中if语句的条件包含指定标识符【递归条件】
    if (alternate && t.isBlockStatement(alternate)
        && t.isIfStatement(alternate.body[0])
        && judge_include_identifier(path.get('alternate.body')[0].get('test'), idt)
    ) {
        // else中条件对应 !test,所以添加的条件要取反
        test_li.push(t.UnaryExpression('!', test));
        parseIfStatement(path.get('alternate.body')[0], test_li, idt, li);
        test_li.pop();
    } else {
        // 在else中添加的条件要取反
        test_li.push(t.UnaryExpression('!', test));
        let condition = test_li.map(function (v) {
            return generator(v).code
        }).join(' && ');
        test_li.pop();
        let case1 = path.node.alternate.body;
        li[condition] = case1;
    }
}
 
traverse(ast, {
    WhileStatement(path) {
        let while_body = path?.get('body')?.get('body');
        if (t.isNumericLiteral(path.node.test, {value: 1})
            && while_body && while_body.length == 2
            && while_body[0].isExpressionStatement()
            && while_body[1].isIfStatement()
        ) { // 判断是否符合控制流特征
            let condition_identifier = while_body[0].node.expression.left.name; // 获取标识符名
            let if_statement = while_body[1];
            let li = {};
            parseIfStatement(if_statement, [], condition_identifier, li);  // 递归遍历if
 
            let cases = [];
 
            // 获取索引数组
            let var_statement_path = path.getSibling(path.key-1);
            // 根据索引数组还原
            // 判断是否包含数组
            if (var_statement_path.isVariableDeclaration()
                && var_statement_path.get('declarations').at(-1)?.get('init')?.isArrayExpression()) {
                let index_arr = eval(var_statement_path.get('declarations').at(-1).get('init')+'');
                index_arr = Array.from(new Set(index_arr)).sort(function (a,b){return a-b});
                for (let i of index_arr) {
                    let flag = false;
                    for (var [test, statement] of Object.entries(li)) {
                        eval(`
                        let ${condition_identifier} = i;
                        if (${test}) {
                            res_statement = statement;
                            flag = true;
                        }
                    `);
                        if (flag) break;
                    }
                    if (!flag) {
                        console.error('没有匹配的值:', i);
                        throw Error('没有匹配条件');
                    }
                    res_statement = Array.from(res_statement);  // 浅copy一下,避免多个index进入同一个控制流时会添加多个break,比较难看
                    res_statement.push(t.BreakStatement());
                    cases.push(t.SwitchCase(t.valueToNode(parseInt(i)), res_statement));
                }
            }
            else {
                console.log('没有获取到索引数组,结束!!!!!')
            }
            let sw = t.SwitchStatement(while_body[0].node.expression.left, cases);
            if_statement.replaceWith(sw);
        }
    }
});
 
 
 
code = generator(ast).code;
fs.writeFileSync('./output.js', code,{encoding:'utf-8'});
 
 
console.log('耗时=》', Date.now() - start);


以上代码只实现了索引大数组在最外层自执行函数第一句的情况,
Quicker_20230510_165233.png
向vm中的代码如果是这种形式的可以手动把索引大数字替换掉window.变量名 ;
如果索引数组是以自执行函数的参数的形式穿入的,也可以改成这段代码支持的形式,或者自己写解析逻辑。

某普的控制流改写如下:

某普控制流

某普控制流

某标控制流改写如下:

某标控制流

某标控制流




ps: 改写思路应该是没什么问题?如果改写结果不对可以自己改改看代码{:1_918:}  
改写了其实也没什么用,也就少按几次f11,哈哈:lol





















原本到上面是已经结束了的,但写文章的时候又想到另一种解法,而且还更简单,速度更快,所以也一起写了
开始依旧是要还原索引数组的;
还是开始的伪代码:
[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
_$OR = [1,2,3,4];
while (1) {
    _$r4 = _$OR[_$NE++];
    if (test1) {
        statement1
    } else if (test2) {
        statement2
    } else if (test3) {
        statement3
    } else {
        statement4
    }
}

上面是通过递归获取每个语句的完整条件,这里依旧是递归遍历if语句,将代码改写。改写为将每个语句赋予一个唯一的id,然后将id和对应的语句存起来,将if控制流改写为索引与id对应的形式
生成伪代码如下:
[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if (test1) {
    if (test2) {
        index_obj[_$_o] = 0;
    } else {
        if (test3) {
            index_obj[_$_o] = 1;
        } else {
            if (test4) {
                index_obj[_$_o] = 2;
            } else {
                index_obj[_$_o] = 3;
            }
        }
    }
} else {
    index_obj[_$_o] = 4;
}
 
 
/*
var li = {
    0:statement1,
    1:statement2,
    2:statement3,
    ...
}
*/

然后这个if语句变成了可以执行的形式,然后就可以通过索引数组遍历,获取索引与id的对应关系;
伪代码如下:
[JavaScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var index_obj = {};
for (let condition of [a,b,c,d,e]){
    if (test1) {
        if (test2) {
            index_obj[_$_o] = 0;
        } else {
            if (test3) {
                index_obj[_$_o] = 1;
            } else {
                if (test4) {
                    index_obj[_$_o] = 2;
                } else {
                    index_obj[_$_o] = 3;
                }
            }
        }
    } else {
        index_obj[_$_o] = 4;
    }
}
 
 
/*
=>{
    a:0,
    b:1,
    c:2,
    d:3,
    e:4
}
 */

现在有了索引与id,id与语句的对应关系,就可以获取到id与语句的对应关系生成对应的switch case 语句了。


实现代码用法和上面相同,代码可能有bug,如果用可以自己再看看。思路应该是可行的
实现代码如下:
[JavaScript] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;
const t = require('@babel/types');
const fs = require('fs');
 
const start = Date.now();
 
 
const jscode = fs.readFileSync("./input.js", {
    encoding: "utf-8"
});
let code;
let ast = parser.parse(jscode);
 
 
// ---------------------------还原数组 如果第一句是数组
traverse(ast,{
    Program(path){
        if (!path.get('body.0')?.get('expression')?.get('callee')?.get('body')?.get('body.0')?.isVariableDeclaration()) return;
        let func_statement_path_1 = path.get('body')[0].get('expression.callee.body.body')[0];
        func_statement_path_1.get('declarations').forEach(function (v) {
            if (v.get('init').isArrayExpression()){
                let binding = func_statement_path_1.scope.getBinding(v.node.id.name);
                let arr = v.node.init.elements;
                binding && binding.constantViolations.length == 0 && binding.referencePaths.forEach(function (vv) {
                    if (vv.parentPath.isMemberExpression()
                        && vv.parent.object.name == v.node.id.name
                        && vv.parentPath.get('property').isNumericLiteral()
                    ){
                        vv.parentPath.replaceWith(arr[vv.parent.property.value]);
                    }
                })
            }
        });
    }
})
 
 
// ---------------还原控制流
traverse(ast, {
    IfStatement(path) {
        let {consequent, alternate} = path.node;
        if (consequent && !t.isBlockStatement(consequent)) {
            path.get('consequent').replaceWith(t.BlockStatement([consequent]));
        }
        if (alternate && !t.isBlockStatement(alternate)) {
            path.get('alternate').replaceWith(t.BlockStatement([alternate]));
        }
    }
})
 
function judge_include_identifier(path, idt) {
    // path:if语句的test节点的path对象,用于判断 “判断条件中”是否有不是指定的标识符,避免遍历非控制流的if语句
    // idt 标识符
    let flag = true;
    // 如果test节点有控制流的标识符,返回true,否则返回false
    path.traverse({
        Identifier(path_) {
            if (path_.node.name != idt) {
                flag = false
            }
        }
    })
    return flag
}
 
function parseIfStatement(path, id_arr, idt, li) {
    // path: if语句的path对象, test_li: 用来当前存储条件,idt:控制流中条件中的标识符
    let {consequent, alternate, test} = path.node;
    // -----------------------------递归 test==true--------------------------------------------
    // if成立时的结果存在 且为{}语句 且{}中是if语句 且{}中if语句的条件包含指定标识符【递归条件】
    if (consequent && t.isBlockStatement(consequent)
        && t.isIfStatement(consequent.body[0])
        && judge_include_identifier(path.get('consequent.body')[0].get('test'), idt)
    ) {
        parseIfStatement(path.get('consequent.body')[0], id_arr, idt, li);
    } else {
        // 没有控制流,递归结束
        let case1 = path.node.consequent.body;
        let id_ = id_arr[0]++;
        li[id_] = case1;
        // index_obj[index] = id_;
        let replace_statement = t.BlockStatement([
            t.ExpressionStatement(t.AssignmentExpression('=', t.MemberExpression(t.Identifier('index_obj'),t.Identifier(idt), true),t.NumericLiteral(id_)))
        ]);
        path.get('consequent').replaceWith(replace_statement);
    }
    // ----------------------递归 test==false 即 else中的语句---------------------------------------
    // else 语句存在 且 是{}语句 且{}中是if语句 且{}中if语句的条件包含指定标识符【递归条件】
    if (alternate && t.isBlockStatement(alternate)
        && t.isIfStatement(alternate.body[0])
        && judge_include_identifier(path.get('alternate.body')[0].get('test'), idt)
    ) {
        parseIfStatement(path.get('alternate.body')[0], id_arr, idt, li);
    } else {
        let case1 = path.node.alternate.body;
        let id_ = id_arr[0]++;
        li[id_] = case1;
        // index_obj[index] = id_;   以index作为键,会有多个index进入到同一个语句中
        let replace_statement = t.BlockStatement([
            t.ExpressionStatement(t.AssignmentExpression('=', t.MemberExpression(t.Identifier('index_obj'),t.Identifier(idt), true),t.NumericLiteral(id_)))
        ]);
        path.get('alternate').replaceWith(replace_statement);
    }
}
 
traverse(ast, {
    WhileStatement(path) {
        let while_body = path?.get('body')?.get('body');
        if (t.isNumericLiteral(path.node.test, {value: 1})
            && while_body && while_body.length == 2
            && while_body[0].isExpressionStatement()
            && while_body[1].isIfStatement()
        ) {
            let condition_identifier = while_body[0].node.expression.left.name;
            let if_statement = while_body[1];
            let li = {};
            let id_arr = [0];
            parseIfStatement(if_statement, id_arr, condition_identifier, li);
            let cases = [];
            let index_obj = {};
 
            let var_statement_path = path.getSibling(path.key-1);
            if (var_statement_path.isVariableDeclaration()   // 使用索引数组遍历
                && var_statement_path.get('declarations').at(-1)?.get('init')?.isArrayExpression()) {
                let index_arr = eval(var_statement_path.get('declarations').at(-1).get('init') + '');
                index_arr = Array.from(new Set(index_arr)).sort(function (a, b) {
                    return a - b
                }); // 去重 排序
                eval(`
                    for (let ${condition_identifier} of index_arr) {
                        ${if_statement + ''}
                    }
                `);
            }else {
                console.log('没有获取到索引数组,结束!!!!!');
            }
 
            for (let [index,id_] of Object.entries(index_obj).sort(function (a,b){return a[0]-b[0]})){
                let res_statement = [...li[id_]];
                res_statement.push(t.BreakStatement());
                cases.push(t.SwitchCase(t.valueToNode(parseInt(index)), res_statement));
            }
 
            let sw = t.SwitchStatement(while_body[0].node.expression.left, cases);
            if_statement.replaceWith(sw);
        }
    }
})
 
 
 
 
code = generator(ast).code;
 
fs.writeFileSync('./output.js', code, {encoding:'utf-8'});
 
console.log('耗时=》', Date.now() - start)


控制流还原.zip

181.1 KB, 下载次数: 12, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 10威望 +2 吾爱币 +112 热心值 +8 收起 理由
笙若 + 1 + 1 谢谢@Thanks!
onlywey + 1 + 1 用心讨论,共获提升!
alanhays + 2 + 1 用心讨论,共获提升!
涛之雨 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
悦来客栈的老板 + 1 用心讨论,共获提升!
三滑稽甲苯 + 1 + 1 用心讨论,共获提升!
peiwithhao + 3 + 1 很强,但是我不懂
mn126kk72 + 1 + 1 用心讨论,共获提升!
helian147 + 1 + 1 热心回复!
RickSanchez + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

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

law.liu 发表于 2023-5-11 10:15
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;
const t = require('@babel/types');
const fs = require('fs');

const start = Date.now();

const jscode = fs.readFileSync("./input.js", {
encoding: "utf-8"
});
let code;
let ast = parser.parse(jscode);

// ---------------------------还原数组 如果第一句是数组
(function() {     var _$rD = 0       , _$zG = $_ts.scj       , _$cj = [[],[],[],[],[]];       .........   })()
traverse(ast,{
Program(path){
if (!path.get('body.0')?.get('expression')?.get('callee')?.get('body')?.get('body.0')?.isVariableDeclaration()) return;
let func_statement_path_1 = path.get('body')[0].get('expression.callee.body.body')[0];
func_statement_path_1.get('declarations').forEach(function (v) {
if (v.get('init').isArrayExpression()){
let binding = func_statement_path_1.scope.getBinding(v.node.id.name);
let arr = v.node.init.elements;
binding && binding.constantViolations.length == 0 && binding.referencePaths.forEach(function (vv) {
if (vv.parentPath.isMemberExpression()
&& vv.parent.object.name == v.node.id.name
&& vv.parentPath.get('property').isNumericLiteral()
){
vv.parentPath.replaceWith(arr[vv.parent.property.value]);
}
})
}
});
}
});

// ---------------------------还原控制流
traverse(ast, { // 给if语句把 {} 都加上
IfStatement(path) {
let {consequent, alternate} = path.node;
if (consequent && !t.isBlockStatement(consequent)) {
path.get('consequent').replaceWith(t.BlockStatement([consequent]));
}
if (alternate && !t.isBlockStatement(alternate)) {
path.get('alternate').replaceWith(t.BlockStatement([alternate]));
}
}
});

function judge_include_identifier(path, idt) {
// path:if语句的test节点的path对象,用于判断 “判断条件中”是否有不是指定的标识符,避免遍历非控制流的if语句
// idt 标识符
let flag = true;
// 如果test节点有控制流的标识符,返回true,否则返回false
path.traverse({
Identifier(path_) {
if (path_.node.name != idt) {
flag = false
}
}
})
return flag
}

function parseIfStatement(path, test_li, idt, li) {
// path: if语句的path对象, test_li: 用来当前存储条件,idt:控制流中条件中的标识符 ,li:存储结果
let {consequent, alternate, test} = path.node;
// -----------------------------递归 test==true--------------------------------------------
// if成立时的结果存在 且为{}语句 且{}中是if语句 且{}中if语句的条件包含指定标识符【递归条件】
if (consequent && t.isBlockStatement(consequent)
&& t.isIfStatement(consequent.body[0])
&& judge_include_identifier(path.get('consequent.body')[0].get('test'), idt)
) {
// 符合条件就进入子if语句中,将当前的条件加入到数组【是if==true的语句,直接加】
test_li.push(test);
parseIfStatement(path.get('consequent.body')[0], test_li, idt, li);
test_li.pop(); // 子语句遍历结束后弹出条件,保持状态。
} else {
// 没有控制流,递归结束
test_li.push(test);
// 根据数组构造判断条件的字符串
let condition = test_li.map(function (v) {
return generator(v).code
}).join(' && ');
test_li.pop();
let case1 = path.node.consequent.body;
li[condition] = case1;
}
// ----------------------递归 test==false 即 else中的语句---------------------------------------
// else 语句存在 且 是{}语句 且{}中是if语句 且{}中if语句的条件包含指定标识符【递归条件】
if (alternate && t.isBlockStatement(alternate)
&& t.isIfStatement(alternate.body[0])
&& judge_include_identifier(path.get('alternate.body')[0].get('test'), idt)
) {
// else中条件对应 !test,所以添加的条件要取反
test_li.push(t.UnaryExpression('!', test));
parseIfStatement(path.get('alternate.body')[0], test_li, idt, li);
test_li.pop();
} else {
// 在else中添加的条件要取反
test_li.push(t.UnaryExpression('!', test));
let condition = test_li.map(function (v) {
return generator(v).code
}).join(' && ');
test_li.pop();
let case1 = path.node.alternate.body;
li[condition] = case1;
}
}

traverse(ast, {
WhileStatement(path) {
let while_body = path?.get('body')?.get('body');
if (t.isNumericLiteral(path.node.test, {value: 1})
&& while_body && while_body.length == 2
&& while_body[0].isExpressionStatement()
&& while_body[1].isIfStatement()
) { // 判断是否符合控制流特征
let condition_identifier = while_body[0].node.expression.left.name; // 获取标识符名
let if_statement = while_body[1];
let li = {};
parseIfStatement(if_statement, [], condition_identifier, li); // 递归遍历if

scheme
Copy
        let cases = [];

        // 获取索引数组
        let var_statement_path = path.getSibling(path.key-1);
        // 根据索引数组还原
        // 判断是否包含数组
        if (var_statement_path.isVariableDeclaration()
            && var_statement_path.get('declarations').at(-1)?.get('init')?.isArrayExpression()) {
            let index_arr = eval(var_statement_path.get('declarations').at(-1).get('init')+'');
            index_arr = Array.from(new Set(index_arr)).sort(function (a,b){return a-b});
            for (let i of index_arr) {
                let flag = false;
                for (var [test, statement] of Object.entries(li)) {
                    eval(`
                    let ${condition_identifier} = i;
                    if (${test}) {
                        res_statement = statement;
                        flag = true;
                    }
                `);
                    if (flag) break;
                }
                if (!flag) {
                    console.error('没有匹配的值:', i);
                    throw Error('没有匹配条件');
                }
                res_statement = Array.from(res_statement);  // 浅copy一下,避免多个index进入同一个控制流时会添加多个break,比较难看
                res_statement.push(t.BreakStatement());
                cases.push(t.SwitchCase(t.valueToNode(parseInt(i)), res_statement));
            }
        }
        else {
            console.log('没有获取到索引数组,结束!!!!!')
        }
        let sw = t.SwitchStatement(while_body[0].node.expression.left, cases);
        if_statement.replaceWith(sw);
    }
}
});

code = generator(ast).code;
fs.writeFileSync('./output.js', code,{encoding:'utf-8'});

console.log('耗时=》', Date.now() - start);


从代码分析来看,这段代码应该可以正常运行,但有一些注意事项:

确保已经安装了所有必要的依赖库。你可以使用 npm 或 yarn 来安装这些库:
[Asm] 纯文本查看 复制代码
1
2
npm install @babel/parser @babel/traverse @babel/generator @babel/types
```

确保在与此脚本相同的目录下存在一个名为 input.js 的文件,因为这段代码将从该文件中读取 JavaScript 代码。

在运行此脚本之前,请确保你了解它的功能,因为它将读取 input.js 文件并生成一个新的名为 output.js 的文件。如果你已经有一个名为 output.js 的文件,它将被覆盖。此外,代码中的 eval() 函数可能会导致安全问题,特别是当处理不受信任的输入时。请确保你理解 eval() 的潜在风险。

如果你已经满足了上述条件,那么这段代码应该可以正常运行。请记住,这段代码的作用是根据 input.js 文件中的代码,对其进行解析、还原和优化,然后将结果输出到 output.js 文件中。
codebat 发表于 2023-5-10 21:05
悦来客栈的老板 发表于 2023-5-11 08:36
 楼主| lsq665 发表于 2023-5-11 09:11
1.zip (390.33 KB, 下载次数: 30)
 楼主| lsq665 发表于 2023-5-11 09:12
codebat 发表于 2023-5-10 21:05
控制流可以补环境解决的吗?

不太懂你的意思,补环境直接无视混淆就好了
 楼主| lsq665 发表于 2023-5-11 09:13
悦来客栈的老板 发表于 2023-5-11 08:36
可以把还原前后的代码发上来嘛?

传了。蔡老板指点一下
weishi9527 发表于 2023-5-11 10:09
看一下这个行不行
Labraff 发表于 2023-5-11 10:29
建议直接copy给ChatGPT哈哈哈哈
darenxu123 发表于 2023-5-12 11:37
这个有点难啊感觉,不知道能不能学会
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2025-5-25 12:11

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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