expose-kit 0.10.0 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +261 -258
- package/dist/index.js +185 -32
- package/dist/package.json +4 -2
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,230 +1,233 @@
|
|
|
1
|
-
# Expose Kit
|
|
2
|
-

|
|
3
|
-
[](https://discord.gg/evex)
|
|
4
|
-
|
|
5
|
-
> A universal toolkit for JavaScript deobfuscation
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## What is this?
|
|
10
|
-
|
|
11
|
-
JavaScript deobfuscation tools are everywhere.
|
|
12
|
-
But many of them are **too aggressive**, rewriting code until it breaks.
|
|
13
|
-
|
|
14
|
-
Expose Kit takes a **different approach**.
|
|
15
|
-
|
|
16
|
-
- No brute force
|
|
17
|
-
- Step-by-step, verifiable transforms
|
|
18
|
-
- Designed to *not* break your code silently
|
|
19
|
-
|
|
20
|
-
Each transformation is meant to be **checked and validated**, so you always know *when* something goes wrong.
|
|
21
|
-
|
|
22
|
-
Alongside deobfuscation, Expose Kit also provides a set of **practical utilities** for working with obfuscated JavaScript.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Installation
|
|
27
|
-
|
|
28
|
-
Just one step:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
npm i -g expose-kit
|
|
32
|
-
# or
|
|
33
|
-
bun i -g expose-kit
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
expose --help
|
|
38
|
-
expose parsable sample.js
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## Usage Notes
|
|
44
|
-
|
|
45
|
-
### Default arguments
|
|
46
|
-
|
|
47
|
-
- The first argument is the input file
|
|
48
|
-
(`--file` / `--input` can also be used)
|
|
49
|
-
- If required options are missing, Expose Kit will **prompt you**
|
|
50
|
-
- A timeout is enabled by default to avoid hangs
|
|
51
|
-
Use `--unlimited` for long-running execution
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## Recommended Workflow
|
|
56
|
-
|
|
57
|
-
First, an important premise:
|
|
58
|
-
|
|
59
|
-
> It is **impossible** to create a static deobfuscation tool that *never* breaks.
|
|
60
|
-
|
|
61
|
-
Reasons include:
|
|
62
|
-
- Unpredictable execution (`eval`, dynamic code)
|
|
63
|
-
- Bugs or edge cases in AST manipulation
|
|
64
|
-
|
|
65
|
-
Because of this, you should **verify the code at every step**.
|
|
66
|
-
|
|
67
|
-
### 1. Always verify with `parsable`
|
|
68
|
-
|
|
69
|
-
After each transformation, run:
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
expose parsable file.js
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
This ensures the syntax is still valid.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
### 2. Make scopes safe first
|
|
80
|
-
|
|
81
|
-
One of the most common causes of breakage is **variable name confusion**.
|
|
82
|
-
|
|
83
|
-
If you try to write your own deobfuscation logic (e.g. in Python), you’ll quickly realize how painful it is to track scopes correctly.
|
|
84
|
-
|
|
85
|
-
That’s why you should **always start with**:
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
expose safe-scope input.js
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
This renames bindings per scope, producing code like:
|
|
92
|
-
|
|
93
|
-
```js
|
|
94
|
-
Before: var x = 810;((x) => console.log(x))(114514);
|
|
95
|
-
After: var x = 810;((_x) => console.log(_x))(114514);
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
With this alone:
|
|
99
|
-
- The code becomes far more resistant to breakage
|
|
100
|
-
- Writing custom deobfuscation logic becomes much easier
|
|
101
|
-
- You no longer need to worry about scope collisions
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
### 3. Apply transforms step by step
|
|
106
|
-
|
|
107
|
-
After `safe-scope`, combine common techniques like:
|
|
108
|
-
- `expand-array`, `expand-object` and more
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Expose Kit will also clearly indicate whether a **diff** exists, making inspection easy.
|
|
114
|
-
|
|
115
|
-
Repeat this process, and the original code will gradually reveal itself.
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Commands
|
|
120
|
-
|
|
121
|
-
### `expose parsable`
|
|
122
|
-
|
|
123
|
-
Check whether a file is syntactically valid.
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
parsable: const x = 810;
|
|
127
|
-
not parsable: const ;x; == 810;
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
```bash
|
|
131
|
-
expose parsable path/to/file.js
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
- Default args only
|
|
136
|
-
|
|
137
|
-
---
|
|
138
|
-
|
|
139
|
-
### `expose safe-scope`
|
|
140
|
-
|
|
141
|
-
Rename bindings per scope for safer transformations.
|
|
142
|
-
|
|
143
|
-
```bash
|
|
144
|
-
expose safe-scope path/to/file.js --output path/to/file.safe-scope.js
|
|
145
|
-
```
|
|
146
|
-
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/safe-scope/mocks).
|
|
147
|
-
|
|
148
|
-
Args:
|
|
149
|
-
- `--o, --output <file>`
|
|
150
|
-
Output file path
|
|
151
|
-
- No extension → `file.safe-scope.js`
|
|
152
|
-
- With extension → `file.safe-scope.<ext>`
|
|
153
|
-
|
|
154
|
-
---
|
|
155
|
-
|
|
156
|
-
### `expose pre-evaluate`
|
|
157
|
-
|
|
158
|
-
Pre-evaluate const numeric/string expressions. (Safe evaluate)
|
|
159
|
-
|
|
160
|
-
```js
|
|
161
|
-
const a = 1 + 2 * 3; // => 7
|
|
162
|
-
const c = "aaaa";
|
|
163
|
-
const b = "a" + c; // => "aaaaa"
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
```bash
|
|
167
|
-
expose pre-evaluate path/to/file.js --output path/to/file.pre-evaluate.js
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
Args:
|
|
171
|
-
- `--o, --output <file>`
|
|
172
|
-
Output file path
|
|
173
|
-
- No extension → `file.pre-evaluate.js`
|
|
174
|
-
- With extension → `file.pre-evaluate.<ext>`
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
1
|
+
# Expose Kit
|
|
2
|
+

|
|
3
|
+
[](https://discord.gg/evex)
|
|
4
|
+
|
|
5
|
+
> A universal toolkit for JavaScript deobfuscation
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What is this?
|
|
10
|
+
|
|
11
|
+
JavaScript deobfuscation tools are everywhere.
|
|
12
|
+
But many of them are **too aggressive**, rewriting code until it breaks.
|
|
13
|
+
|
|
14
|
+
Expose Kit takes a **different approach**.
|
|
15
|
+
|
|
16
|
+
- No brute force
|
|
17
|
+
- Step-by-step, verifiable transforms
|
|
18
|
+
- Designed to *not* break your code silently
|
|
19
|
+
|
|
20
|
+
Each transformation is meant to be **checked and validated**, so you always know *when* something goes wrong.
|
|
21
|
+
|
|
22
|
+
Alongside deobfuscation, Expose Kit also provides a set of **practical utilities** for working with obfuscated JavaScript.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Just one step:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm i -g expose-kit
|
|
32
|
+
# or
|
|
33
|
+
bun i -g expose-kit
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
expose --help
|
|
38
|
+
expose parsable sample.js
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Usage Notes
|
|
44
|
+
|
|
45
|
+
### Default arguments
|
|
46
|
+
|
|
47
|
+
- The first argument is the input file
|
|
48
|
+
(`--file` / `--input` can also be used)
|
|
49
|
+
- If required options are missing, Expose Kit will **prompt you**
|
|
50
|
+
- A timeout is enabled by default to avoid hangs
|
|
51
|
+
Use `--unlimited` for long-running execution
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Recommended Workflow
|
|
56
|
+
|
|
57
|
+
First, an important premise:
|
|
58
|
+
|
|
59
|
+
> It is **impossible** to create a static deobfuscation tool that *never* breaks.
|
|
60
|
+
|
|
61
|
+
Reasons include:
|
|
62
|
+
- Unpredictable execution (`eval`, dynamic code)
|
|
63
|
+
- Bugs or edge cases in AST manipulation
|
|
64
|
+
|
|
65
|
+
Because of this, you should **verify the code at every step**.
|
|
66
|
+
|
|
67
|
+
### 1. Always verify with `parsable`
|
|
68
|
+
|
|
69
|
+
After each transformation, run:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
expose parsable file.js
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This ensures the syntax is still valid.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### 2. Make scopes safe first
|
|
80
|
+
|
|
81
|
+
One of the most common causes of breakage is **variable name confusion**.
|
|
82
|
+
|
|
83
|
+
If you try to write your own deobfuscation logic (e.g. in Python), you’ll quickly realize how painful it is to track scopes correctly.
|
|
84
|
+
|
|
85
|
+
That’s why you should **always start with**:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
expose safe-scope input.js
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This renames bindings per scope, producing code like:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
Before: var x = 810;((x) => console.log(x))(114514);
|
|
95
|
+
After: var x = 810;((_x) => console.log(_x))(114514);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
With this alone:
|
|
99
|
+
- The code becomes far more resistant to breakage
|
|
100
|
+
- Writing custom deobfuscation logic becomes much easier
|
|
101
|
+
- You no longer need to worry about scope collisions
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### 3. Apply transforms step by step
|
|
106
|
+
|
|
107
|
+
After `safe-scope`, combine common techniques like:
|
|
108
|
+
- `expand-array`, `expand-object` and more
|
|
109
|
+
|
|
110
|
+
After **each step**, run `parsable` and `remove-unused` again.
|
|
111
|
+
(even if it's not frequent, we might overlook something broken)
|
|
112
|
+
|
|
113
|
+
Expose Kit will also clearly indicate whether a **diff** exists, making inspection easy.
|
|
114
|
+
|
|
115
|
+
Repeat this process, and the original code will gradually reveal itself.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Commands
|
|
120
|
+
|
|
121
|
+
### `expose parsable`
|
|
122
|
+
|
|
123
|
+
Check whether a file is syntactically valid.
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
parsable: const x = 810;
|
|
127
|
+
not parsable: const ;x; == 810;
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
expose parsable path/to/file.js
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
- Default args only
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### `expose safe-scope`
|
|
140
|
+
|
|
141
|
+
Rename bindings per scope for safer transformations.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
expose safe-scope path/to/file.js --output path/to/file.safe-scope.js
|
|
145
|
+
```
|
|
146
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/safe-scope/mocks).
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
- `--o, --output <file>`
|
|
150
|
+
Output file path
|
|
151
|
+
- No extension → `file.safe-scope.js`
|
|
152
|
+
- With extension → `file.safe-scope.<ext>`
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### `expose pre-evaluate`
|
|
157
|
+
|
|
158
|
+
Pre-evaluate const numeric/string expressions. (Safe evaluate)
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
const a = 1 + 2 * 3; // => 7
|
|
162
|
+
const c = "aaaa";
|
|
163
|
+
const b = "a" + c; // => "aaaaa"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
expose pre-evaluate path/to/file.js --output path/to/file.pre-evaluate.js
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
- `--o, --output <file>`
|
|
172
|
+
Output file path
|
|
173
|
+
- No extension → `file.pre-evaluate.js`
|
|
174
|
+
- With extension → `file.pre-evaluate.<ext>`
|
|
175
|
+
|
|
176
|
+
Notes:
|
|
177
|
+
- Inlines zero-arg functions that return safe array literals by hoisting them to a var.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### `expose expand-array`
|
|
182
|
+
|
|
183
|
+
Expand array index access for primitive values.
|
|
184
|
+
```js
|
|
185
|
+
var a = [1, 1, 4, 5, 1, 4];
|
|
186
|
+
// before
|
|
187
|
+
console.log(a[0], a[2], a[3]);
|
|
188
|
+
// after
|
|
189
|
+
console.log(1, 4, 5);
|
|
190
|
+
```
|
|
191
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/expand-array/mocks).
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
expose expand-array path/to/file.js --target arrayName --output path/to/file.expand-array.js
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
- `--target <name>`
|
|
199
|
+
Target array variable name
|
|
200
|
+
- `--o, --output <file>`
|
|
201
|
+
Output file path
|
|
202
|
+
|
|
203
|
+
Notes:
|
|
204
|
+
- Each replacement is validated by reparsing; unsafe replacements are skipped.
|
|
205
|
+
(This array is intended to be immutable, so caution is required)
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
206
209
|
### `expose expand-object`
|
|
207
|
-
|
|
208
|
-
Expand object property access for primitive values.
|
|
209
|
-
```js
|
|
210
|
-
const obj = { a: 1, b: 2 };
|
|
211
|
-
// before
|
|
212
|
-
console.log(obj.a, obj["b"]);
|
|
213
|
-
// after
|
|
214
|
-
console.log(1, 2);
|
|
215
|
-
```
|
|
216
|
-
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/expand-object/mocks).
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
expose expand-object path/to/file.js --target objectName --output path/to/file.expand-object.js
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
Args:
|
|
223
|
-
- `--target <name>`
|
|
224
|
-
Target object variable name
|
|
225
|
-
- `--o, --output <file>`
|
|
226
|
-
Output file path
|
|
227
|
-
|
|
210
|
+
|
|
211
|
+
Expand object property access for primitive values.
|
|
212
|
+
```js
|
|
213
|
+
const obj = { a: 1, b: 2 };
|
|
214
|
+
// before
|
|
215
|
+
console.log(obj.a, obj["b"]);
|
|
216
|
+
// after
|
|
217
|
+
console.log(1, 2);
|
|
218
|
+
```
|
|
219
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/expand-object/mocks).
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
expose expand-object path/to/file.js --target objectName --output path/to/file.expand-object.js
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
- `--target <name>`
|
|
227
|
+
Target object variable name
|
|
228
|
+
- `--o, --output <file>`
|
|
229
|
+
Output file path
|
|
230
|
+
|
|
228
231
|
Notes:
|
|
229
232
|
- Each replacement is validated by reparsing; unsafe replacements are skipped.
|
|
230
233
|
(This object is intended to be immutable, so caution is required)
|
|
@@ -376,35 +379,35 @@ Notes:
|
|
|
376
379
|
### `expose remove-unused`
|
|
377
380
|
|
|
378
381
|
Remove unused variabless.
|
|
379
|
-
```js
|
|
380
|
-
// before
|
|
381
|
-
var a = 0, b = 1;
|
|
382
|
-
console.log(a);
|
|
383
|
-
// after
|
|
384
|
-
var a = 0;
|
|
385
|
-
console.log(a);
|
|
386
|
-
```
|
|
387
|
-
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/remove-unused/mocks).
|
|
388
|
-
|
|
389
|
-
```bash
|
|
390
|
-
expose remove-unused path/to/file.js --output path/to/file.remove-unused.js
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
Args:
|
|
394
|
-
- `--o, --output <file>`
|
|
395
|
-
Output file path
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
## Community & Support
|
|
399
|
-
|
|
400
|
-
- Missing a feature? → [Create an issue](https://github.com/EdamAme-x/expose-kit/issues)
|
|
401
|
-
- Not sure which command to use? → Join our [Discord](https://evex.land)
|
|
402
|
-
|
|
403
|
-
---
|
|
404
|
-
|
|
405
|
-
## Author
|
|
406
|
-
|
|
407
|
-
- [EdamAme-x](https://github.com/EdamAme-x)
|
|
408
|
-
|
|
409
|
-
Built for research, not abuse.
|
|
410
|
-
Want stronger obfuscation? Then build something this tool can’t reverse.
|
|
382
|
+
```js
|
|
383
|
+
// before
|
|
384
|
+
var a = 0, b = 1;
|
|
385
|
+
console.log(a);
|
|
386
|
+
// after
|
|
387
|
+
var a = 0;
|
|
388
|
+
console.log(a);
|
|
389
|
+
```
|
|
390
|
+
Example is [here](https://github.com/evex-dev/expose-kit/tree/main/commands/remove-unused/mocks).
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
expose remove-unused path/to/file.js --output path/to/file.remove-unused.js
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
- `--o, --output <file>`
|
|
398
|
+
Output file path
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
## Community & Support
|
|
402
|
+
|
|
403
|
+
- Missing a feature? → [Create an issue](https://github.com/EdamAme-x/expose-kit/issues)
|
|
404
|
+
- Not sure which command to use? → Join our [Discord](https://evex.land)
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Author
|
|
409
|
+
|
|
410
|
+
- [EdamAme-x](https://github.com/EdamAme-x)
|
|
411
|
+
|
|
412
|
+
Built for research, not abuse.
|
|
413
|
+
Want stronger obfuscation? Then build something this tool can’t reverse.
|
package/dist/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import chalk4 from "chalk";
|
|
|
8
8
|
|
|
9
9
|
// utils/cli/createCommand.ts
|
|
10
10
|
var createCommand = (creator) => {
|
|
11
|
-
return (
|
|
12
|
-
creator(
|
|
11
|
+
return (program3) => {
|
|
12
|
+
creator(program3);
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -85,8 +85,8 @@ var showError = (message) => {
|
|
|
85
85
|
};
|
|
86
86
|
|
|
87
87
|
// commands/parsable/index.ts
|
|
88
|
-
var parsable_default = createCommand((
|
|
89
|
-
|
|
88
|
+
var parsable_default = createCommand((program3) => {
|
|
89
|
+
program3.command("parsable").description("Check if the file is parsable").argument("[file]", "The file to check").option("--input, --file <file>", "The file to check").option("--unlimited", "Unlimited timeout").action(
|
|
90
90
|
async (fileArgument, options) => {
|
|
91
91
|
await timeout(
|
|
92
92
|
async ({ finish }) => {
|
|
@@ -215,8 +215,8 @@ var renameBindingsByScope = (code, filename) => {
|
|
|
215
215
|
});
|
|
216
216
|
return patchDefault(generate)(ast).code;
|
|
217
217
|
};
|
|
218
|
-
var safe_scope_default = createCommand((
|
|
219
|
-
|
|
218
|
+
var safe_scope_default = createCommand((program3) => {
|
|
219
|
+
program3.command("safe-scope").description("Rename bindings per scope for safer transforms").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
220
220
|
async (fileArgument, options) => {
|
|
221
221
|
await timeout(
|
|
222
222
|
async ({ finish }) => {
|
|
@@ -450,8 +450,8 @@ var expandArrayAccess = async (code, filename, targetName) => {
|
|
|
450
450
|
replacedCount
|
|
451
451
|
};
|
|
452
452
|
};
|
|
453
|
-
var expand_array_default = createCommand((
|
|
454
|
-
|
|
453
|
+
var expand_array_default = createCommand((program3) => {
|
|
454
|
+
program3.command("expand-array").description("Expand array index access for primitive values").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--target <name>", "Target array variable name").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
455
455
|
async (fileArgument, options) => {
|
|
456
456
|
await timeout(
|
|
457
457
|
async ({ finish }) => {
|
|
@@ -721,8 +721,8 @@ var expandObjectAccess = async (code, filename, targetName) => {
|
|
|
721
721
|
replacedCount
|
|
722
722
|
};
|
|
723
723
|
};
|
|
724
|
-
var expand_object_default = createCommand((
|
|
725
|
-
|
|
724
|
+
var expand_object_default = createCommand((program3) => {
|
|
725
|
+
program3.command("expand-object").description("Expand object property access for primitive values").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--target <name>", "Target object variable name").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
726
726
|
async (fileArgument, options) => {
|
|
727
727
|
await timeout(
|
|
728
728
|
async ({ finish }) => {
|
|
@@ -908,8 +908,8 @@ var packObjectProperties = (code, filename) => {
|
|
|
908
908
|
removedStatements
|
|
909
909
|
};
|
|
910
910
|
};
|
|
911
|
-
var object_packer_default = createCommand((
|
|
912
|
-
|
|
911
|
+
var object_packer_default = createCommand((program3) => {
|
|
912
|
+
program3.command("object-packer").description("Pack consecutive object property assignments into literals").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
913
913
|
async (fileArgument, options) => {
|
|
914
914
|
await timeout(
|
|
915
915
|
async ({ finish }) => {
|
|
@@ -1105,6 +1105,108 @@ var shouldSkipReferencedIdentifier = (path) => {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
return false;
|
|
1107
1107
|
};
|
|
1108
|
+
var getArrayReturnExpression = (node) => {
|
|
1109
|
+
if (node.params.length !== 0) return null;
|
|
1110
|
+
if (t4.isBlockStatement(node.body)) {
|
|
1111
|
+
if (node.body.body.length !== 1) return null;
|
|
1112
|
+
const statement = node.body.body[0];
|
|
1113
|
+
if (!t4.isReturnStatement(statement) || !statement.argument) return null;
|
|
1114
|
+
return t4.isArrayExpression(statement.argument) ? statement.argument : null;
|
|
1115
|
+
}
|
|
1116
|
+
return t4.isArrayExpression(node.body) ? node.body : null;
|
|
1117
|
+
};
|
|
1118
|
+
var isSafeArrayElement = (node) => {
|
|
1119
|
+
if (!node) return true;
|
|
1120
|
+
if (t4.isNumericLiteral(node) || t4.isStringLiteral(node) || t4.isBooleanLiteral(node) || t4.isNullLiteral(node)) {
|
|
1121
|
+
return true;
|
|
1122
|
+
}
|
|
1123
|
+
if (t4.isUnaryExpression(node) && (node.operator === "-" || node.operator === "+") && t4.isNumericLiteral(node.argument)) {
|
|
1124
|
+
return true;
|
|
1125
|
+
}
|
|
1126
|
+
if (t4.isArrayExpression(node)) {
|
|
1127
|
+
return node.elements.every((element) => {
|
|
1128
|
+
if (element === null) return true;
|
|
1129
|
+
if (t4.isSpreadElement(element)) return false;
|
|
1130
|
+
return isSafeArrayElement(element);
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
return false;
|
|
1134
|
+
};
|
|
1135
|
+
var isSafeArrayExpression = (node) => {
|
|
1136
|
+
return node.elements.every((element) => {
|
|
1137
|
+
if (element === null) return true;
|
|
1138
|
+
if (t4.isSpreadElement(element)) return false;
|
|
1139
|
+
return isSafeArrayElement(element);
|
|
1140
|
+
});
|
|
1141
|
+
};
|
|
1142
|
+
var collectArrayReturnFunctions = (ast) => {
|
|
1143
|
+
const results = [];
|
|
1144
|
+
let counter = 0;
|
|
1145
|
+
patchDefault(traverse5)(ast, {
|
|
1146
|
+
FunctionDeclaration(path) {
|
|
1147
|
+
if (!path.node.id) return;
|
|
1148
|
+
const arrayExpression = getArrayReturnExpression(path.node);
|
|
1149
|
+
if (!arrayExpression || !isSafeArrayExpression(arrayExpression)) return;
|
|
1150
|
+
const binding = path.scope.getBinding(path.node.id.name);
|
|
1151
|
+
if (!binding) return;
|
|
1152
|
+
const programScope = path.scope.getProgramParent();
|
|
1153
|
+
let replacementName = `${path.node.id.name}_${counter}`;
|
|
1154
|
+
counter += 1;
|
|
1155
|
+
while (programScope.hasBinding(replacementName)) {
|
|
1156
|
+
replacementName = `${path.node.id.name}_${counter}`;
|
|
1157
|
+
counter += 1;
|
|
1158
|
+
}
|
|
1159
|
+
results.push({
|
|
1160
|
+
binding,
|
|
1161
|
+
arrayNode: arrayExpression,
|
|
1162
|
+
replacementName,
|
|
1163
|
+
used: false
|
|
1164
|
+
});
|
|
1165
|
+
},
|
|
1166
|
+
VariableDeclarator(path) {
|
|
1167
|
+
if (!t4.isIdentifier(path.node.id)) return;
|
|
1168
|
+
const init = path.node.init;
|
|
1169
|
+
if (!init || !t4.isFunctionExpression(init) && !t4.isArrowFunctionExpression(init)) {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
const arrayExpression = getArrayReturnExpression(init);
|
|
1173
|
+
if (!arrayExpression || !isSafeArrayExpression(arrayExpression)) return;
|
|
1174
|
+
const binding = path.scope.getBinding(path.node.id.name);
|
|
1175
|
+
if (!binding || !binding.constant || binding.kind !== "const") return;
|
|
1176
|
+
const programScope = path.scope.getProgramParent();
|
|
1177
|
+
let replacementName = `${path.node.id.name}_${counter}`;
|
|
1178
|
+
counter += 1;
|
|
1179
|
+
while (programScope.hasBinding(replacementName)) {
|
|
1180
|
+
replacementName = `${path.node.id.name}_${counter}`;
|
|
1181
|
+
counter += 1;
|
|
1182
|
+
}
|
|
1183
|
+
results.push({
|
|
1184
|
+
binding,
|
|
1185
|
+
arrayNode: arrayExpression,
|
|
1186
|
+
replacementName,
|
|
1187
|
+
used: false
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
});
|
|
1191
|
+
return results;
|
|
1192
|
+
};
|
|
1193
|
+
var insertArrayReturnDeclarations = (ast, functions) => {
|
|
1194
|
+
const declarations = functions.filter((info) => info.used).map(
|
|
1195
|
+
(info) => t4.variableDeclaration("var", [
|
|
1196
|
+
t4.variableDeclarator(
|
|
1197
|
+
t4.identifier(info.replacementName),
|
|
1198
|
+
t4.cloneNode(info.arrayNode, true)
|
|
1199
|
+
)
|
|
1200
|
+
])
|
|
1201
|
+
);
|
|
1202
|
+
if (declarations.length === 0) return;
|
|
1203
|
+
const body = ast.program.body;
|
|
1204
|
+
let insertIndex = 0;
|
|
1205
|
+
while (insertIndex < body.length && t4.isExpressionStatement(body[insertIndex]) && "directive" in (body[insertIndex] || {})) {
|
|
1206
|
+
insertIndex += 1;
|
|
1207
|
+
}
|
|
1208
|
+
body.splice(insertIndex, 0, ...declarations);
|
|
1209
|
+
};
|
|
1108
1210
|
var preEvaluate = (code, filename) => {
|
|
1109
1211
|
const ast = parse6(code, createParseOptions(filename));
|
|
1110
1212
|
const state = {
|
|
@@ -1112,7 +1214,23 @@ var preEvaluate = (code, filename) => {
|
|
|
1112
1214
|
bindingStack: /* @__PURE__ */ new Set()
|
|
1113
1215
|
};
|
|
1114
1216
|
let replacedCount = 0;
|
|
1217
|
+
const arrayReturnFunctions = collectArrayReturnFunctions(ast);
|
|
1218
|
+
const arrayReturnMap = /* @__PURE__ */ new Map();
|
|
1219
|
+
for (const info of arrayReturnFunctions) {
|
|
1220
|
+
arrayReturnMap.set(info.binding, info);
|
|
1221
|
+
}
|
|
1115
1222
|
patchDefault(traverse5)(ast, {
|
|
1223
|
+
CallExpression(path) {
|
|
1224
|
+
if (!t4.isIdentifier(path.node.callee)) return;
|
|
1225
|
+
if (path.node.arguments.length !== 0) return;
|
|
1226
|
+
const binding = path.scope.getBinding(path.node.callee.name);
|
|
1227
|
+
if (!binding) return;
|
|
1228
|
+
const info = arrayReturnMap.get(binding);
|
|
1229
|
+
if (!info) return;
|
|
1230
|
+
path.replaceWith(t4.identifier(info.replacementName));
|
|
1231
|
+
info.used = true;
|
|
1232
|
+
replacedCount += 1;
|
|
1233
|
+
},
|
|
1116
1234
|
ReferencedIdentifier(path) {
|
|
1117
1235
|
if (shouldSkipReferencedIdentifier(path)) {
|
|
1118
1236
|
return;
|
|
@@ -1163,13 +1281,14 @@ var preEvaluate = (code, filename) => {
|
|
|
1163
1281
|
}
|
|
1164
1282
|
}
|
|
1165
1283
|
});
|
|
1284
|
+
insertArrayReturnDeclarations(ast, arrayReturnFunctions);
|
|
1166
1285
|
return {
|
|
1167
1286
|
code: patchDefault(generate5)(ast).code,
|
|
1168
1287
|
replacedCount
|
|
1169
1288
|
};
|
|
1170
1289
|
};
|
|
1171
|
-
var pre_evaluate_default = createCommand((
|
|
1172
|
-
|
|
1290
|
+
var pre_evaluate_default = createCommand((program3) => {
|
|
1291
|
+
program3.command("pre-evaluate").description("Pre-evaluate const numeric/string expressions").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1173
1292
|
async (fileArgument, options) => {
|
|
1174
1293
|
await timeout(
|
|
1175
1294
|
async ({ finish }) => {
|
|
@@ -1262,8 +1381,8 @@ var removeUpdaters = (code, filename) => {
|
|
|
1262
1381
|
replacedCount
|
|
1263
1382
|
};
|
|
1264
1383
|
};
|
|
1265
|
-
var remove_updater_default = createCommand((
|
|
1266
|
-
|
|
1384
|
+
var remove_updater_default = createCommand((program3) => {
|
|
1385
|
+
program3.command("remove-updater").description("Replace safe update expressions with += or -=").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1267
1386
|
async (fileArgument, options) => {
|
|
1268
1387
|
await timeout(
|
|
1269
1388
|
async ({ finish }) => {
|
|
@@ -1505,8 +1624,8 @@ var removeReassign = (code, filename) => {
|
|
|
1505
1624
|
wrapperReplacedCount
|
|
1506
1625
|
};
|
|
1507
1626
|
};
|
|
1508
|
-
var remove_reassign_default = createCommand((
|
|
1509
|
-
|
|
1627
|
+
var remove_reassign_default = createCommand((program3) => {
|
|
1628
|
+
program3.command("remove-reassign").description("Inline safe alias assignments and wrapper calls").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1510
1629
|
async (fileArgument, options) => {
|
|
1511
1630
|
await timeout(
|
|
1512
1631
|
async ({ finish }) => {
|
|
@@ -1611,8 +1730,8 @@ var removeUnusedVariables = (code, filename) => {
|
|
|
1611
1730
|
changed
|
|
1612
1731
|
};
|
|
1613
1732
|
};
|
|
1614
|
-
var remove_unused_default = createCommand((
|
|
1615
|
-
|
|
1733
|
+
var remove_unused_default = createCommand((program3) => {
|
|
1734
|
+
program3.command("remove-unused").description("Remove unused variables and declarations").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1616
1735
|
async (fileArgument, options) => {
|
|
1617
1736
|
await timeout(
|
|
1618
1737
|
async ({ finish }) => {
|
|
@@ -1682,11 +1801,15 @@ var isProxyFunctionExpression = (node) => {
|
|
|
1682
1801
|
return t8.isFunction(node) && node.params.every((param) => t8.isIdentifier(param)) && (t8.isBlockStatement(node.body) && node.body.body.length === 1 && t8.isReturnStatement(node.body.body[0]) && (node.body.body[0].argument === void 0 || t8.isExpression(node.body.body[0].argument) && isProxyValue(node.body.body[0].argument)) || t8.isArrowFunctionExpression(node) && t8.isExpression(node.body) && isProxyValue(node.body));
|
|
1683
1802
|
};
|
|
1684
1803
|
var isProxyValue = (node) => {
|
|
1685
|
-
if (t8.isFunction(node) || t8.isBlockStatement(node) || t8.isSequenceExpression(node)) {
|
|
1804
|
+
if (t8.isFunction(node) || t8.isBlockStatement(node) || t8.isSequenceExpression(node) || t8.isAssignmentExpression(node)) {
|
|
1686
1805
|
return false;
|
|
1687
1806
|
}
|
|
1688
1807
|
let isValid = true;
|
|
1689
|
-
|
|
1808
|
+
if (!t8.isExpression(node)) {
|
|
1809
|
+
return false;
|
|
1810
|
+
}
|
|
1811
|
+
const wrapper = t8.file(t8.program([t8.expressionStatement(node)]));
|
|
1812
|
+
walk(wrapper, {
|
|
1690
1813
|
"SequenceExpression|BlockStatement|Function|AssignmentExpression"(path) {
|
|
1691
1814
|
isValid = false;
|
|
1692
1815
|
path.stop();
|
|
@@ -1716,9 +1839,31 @@ var ProxyFunction = class {
|
|
|
1716
1839
|
])
|
|
1717
1840
|
);
|
|
1718
1841
|
const pathsToReplace = [];
|
|
1719
|
-
|
|
1842
|
+
const shouldSkipIdentifier = (path) => {
|
|
1843
|
+
const parent = path.parentPath;
|
|
1844
|
+
if (!parent) return false;
|
|
1845
|
+
if (parent.isMemberExpression() || parent.isOptionalMemberExpression()) {
|
|
1846
|
+
if (path.key === "property" && !parent.node.computed) {
|
|
1847
|
+
return true;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
if (parent.isObjectProperty()) {
|
|
1851
|
+
if (parent.node.shorthand) return true;
|
|
1852
|
+
if (parent.get("key") === path && !parent.node.computed) {
|
|
1853
|
+
return true;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
if (parent.isObjectMethod()) {
|
|
1857
|
+
if (parent.get("key") === path && !parent.node.computed) {
|
|
1858
|
+
return true;
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
return false;
|
|
1862
|
+
};
|
|
1863
|
+
const wrapper = t8.file(t8.program([t8.expressionStatement(expression)]));
|
|
1864
|
+
walk(wrapper, {
|
|
1720
1865
|
enter(path) {
|
|
1721
|
-
if (t8.isIdentifier(path.node) && !(path
|
|
1866
|
+
if (t8.isIdentifier(path.node) && !shouldSkipIdentifier(path) && paramMap.has(path.node.name)) {
|
|
1722
1867
|
const replacement = paramMap.get(path.node.name);
|
|
1723
1868
|
pathsToReplace.push([path, replacement]);
|
|
1724
1869
|
}
|
|
@@ -1794,8 +1939,8 @@ var inlineProxyFunctions = (code, filename) => {
|
|
|
1794
1939
|
replacedCount
|
|
1795
1940
|
};
|
|
1796
1941
|
};
|
|
1797
|
-
var fn_inliner_default = createCommand((
|
|
1798
|
-
|
|
1942
|
+
var fn_inliner_default = createCommand((program3) => {
|
|
1943
|
+
program3.command("fn-inliner").description("Inline proxy function calls into expressions").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1799
1944
|
async (fileArgument, options) => {
|
|
1800
1945
|
await timeout(
|
|
1801
1946
|
async ({ finish }) => {
|
|
@@ -1977,8 +2122,8 @@ var sequenceSplit = (code, filename) => {
|
|
|
1977
2122
|
changedCount
|
|
1978
2123
|
};
|
|
1979
2124
|
};
|
|
1980
|
-
var sequence_split_default = createCommand((
|
|
1981
|
-
|
|
2125
|
+
var sequence_split_default = createCommand((program3) => {
|
|
2126
|
+
program3.command("sequence-split").description("Split sequence expressions into statements").argument("[file]", "The file to transform").option("--input, --file <file>", "The file to transform").option("--o, --output <file>", "Output file path").option("--unlimited", "Unlimited timeout").action(
|
|
1982
2127
|
async (fileArgument, options) => {
|
|
1983
2128
|
await timeout(
|
|
1984
2129
|
async ({ finish }) => {
|
|
@@ -2078,13 +2223,21 @@ ${calmGradienrain(`Expose Kit v${VERSION}`)}
|
|
|
2078
2223
|
|
|
2079
2224
|
// index.ts
|
|
2080
2225
|
import { readFileSync as readFileSync12 } from "fs";
|
|
2226
|
+
import updateNotifier from "update-notifier";
|
|
2081
2227
|
var __filename = fileURLToPath(import.meta.url);
|
|
2082
2228
|
var __dirname = dirname11(__filename);
|
|
2083
2229
|
var pkg = JSON.parse(readFileSync12(join11(__dirname, "package.json"), "utf8"));
|
|
2230
|
+
var notifier = updateNotifier({
|
|
2231
|
+
pkg,
|
|
2232
|
+
updateCheckInterval: 0
|
|
2233
|
+
});
|
|
2234
|
+
if (notifier.update) {
|
|
2235
|
+
console.log(`${chalk4.yellow("Update available:")} ${notifier.update.latest}`);
|
|
2236
|
+
}
|
|
2084
2237
|
console.log(showCredit(pkg.version));
|
|
2085
2238
|
console.log();
|
|
2086
|
-
var
|
|
2087
|
-
|
|
2239
|
+
var program2 = new Command();
|
|
2240
|
+
program2.name("expose").description("CLI for Deobfuscating").version(
|
|
2088
2241
|
chalk4.bold("It's written above, lol"),
|
|
2089
2242
|
"-v, --version",
|
|
2090
2243
|
"display version number"
|
|
@@ -2103,6 +2256,6 @@ var commands = [
|
|
|
2103
2256
|
sequence_split_default
|
|
2104
2257
|
];
|
|
2105
2258
|
for (const command of commands) {
|
|
2106
|
-
command(
|
|
2259
|
+
command(program2);
|
|
2107
2260
|
}
|
|
2108
|
-
|
|
2261
|
+
program2.parse();
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expose-kit",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "EdamAmex <edame8080@gmail.com> (https://github.com/EdamAme-x)",
|
|
@@ -42,9 +42,11 @@
|
|
|
42
42
|
"@babel/types": "^7.28.5",
|
|
43
43
|
"@types/babel__generator": "^7.27.0",
|
|
44
44
|
"@types/babel__traverse": "^7.28.0",
|
|
45
|
+
"@types/update-notifier": "^6.0.8",
|
|
45
46
|
"chalk": "^5.6.2",
|
|
46
47
|
"commander": "^14.0.2",
|
|
47
|
-
"loading-cli": "^1.1.2"
|
|
48
|
+
"loading-cli": "^1.1.2",
|
|
49
|
+
"update-notifier": "^7.3.1"
|
|
48
50
|
},
|
|
49
51
|
"bin": {
|
|
50
52
|
"expose": "dist/index.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expose-kit",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "EdamAmex <edame8080@gmail.com> (https://github.com/EdamAme-x)",
|
|
@@ -42,9 +42,11 @@
|
|
|
42
42
|
"@babel/types": "^7.28.5",
|
|
43
43
|
"@types/babel__generator": "^7.27.0",
|
|
44
44
|
"@types/babel__traverse": "^7.28.0",
|
|
45
|
+
"@types/update-notifier": "^6.0.8",
|
|
45
46
|
"chalk": "^5.6.2",
|
|
46
47
|
"commander": "^14.0.2",
|
|
47
|
-
"loading-cli": "^1.1.2"
|
|
48
|
+
"loading-cli": "^1.1.2",
|
|
49
|
+
"update-notifier": "^7.3.1"
|
|
48
50
|
},
|
|
49
51
|
"bin": {
|
|
50
52
|
"expose": "dist/index.js",
|