expose-kit 0.2.0 → 0.2.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 +46 -4
- package/dist/index.js +138 -36
- package/dist/package.json +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,8 +21,6 @@ Expose Kit takes *a different path*.
|
|
|
21
21
|
|
|
22
22
|
Instead of brute force, it works **step by step**.
|
|
23
23
|
|
|
24
|
-
The goal is simple: **safe and universal toolkit**.
|
|
25
|
-
|
|
26
24
|
Alongside deobfuscation, Expose Kit includes a collection of practical utilities.
|
|
27
25
|
|
|
28
26
|
Everything you need is documented right here in this [README](README.md).
|
|
@@ -43,13 +41,57 @@ npm i -g expose-kit
|
|
|
43
41
|
<!-- For Highlight -->
|
|
44
42
|
```regex
|
|
45
43
|
expose --help
|
|
44
|
+
expose parsable sample.js
|
|
46
45
|
```
|
|
47
46
|
|
|
48
47
|
## Docs
|
|
49
|
-
|
|
48
|
+
By default, the first argument should be the file name (alternatively, `--file` or `--input` can be used).
|
|
49
|
+
|
|
50
|
+
If no options are provided, this tool will prompt you for the required values.
|
|
51
|
+
|
|
52
|
+
To avoid memory leaks and hung processes, a reasonable timeout is set by default.
|
|
53
|
+
When long-running execution is expected, the timeout can be disabled with `--unlimited`.
|
|
54
|
+
|
|
55
|
+
### Commands
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
#### `expose parsable`
|
|
59
|
+
|
|
60
|
+
Check if the file is parsable
|
|
61
|
+
```js
|
|
62
|
+
parsable: const x = 810;
|
|
63
|
+
not parsable: cons x; = 810;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
##### Example
|
|
67
|
+
```bash
|
|
68
|
+
expose parsable path/to/file.js
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
##### Args
|
|
72
|
+
- *Only default args*
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
#### `expose scope-safe`
|
|
76
|
+
|
|
77
|
+
Rename bindings per scope for safer transforms
|
|
78
|
+
```js
|
|
79
|
+
Before: var x = 810;((x) => console.log(x))(114514);
|
|
80
|
+
After: var x = 810;((_x) => console.log(_x))(114514);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
##### Example
|
|
84
|
+
```bash
|
|
85
|
+
expose scope-safe path/to/file.js --output path/to/file.scope-safe.js
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
##### Args
|
|
89
|
+
- `--o, --output <file>`: Output file path
|
|
90
|
+
If the input has no extension, `path/to/file.scope-safe.js` is used.
|
|
91
|
+
Otherwise, `path/to/file.scope-safe.<ext>` is used (same directory).
|
|
50
92
|
|
|
51
93
|
## Authors
|
|
52
94
|
- [EdamAme-x](https://github.com/EdamAme-x)
|
|
53
95
|
|
|
54
96
|
Built for research, not abuse.
|
|
55
|
-
Want stronger obfuscation? Then make something this tool can’t
|
|
97
|
+
Want stronger obfuscation? Then make something this tool can’t reverse.
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { dirname, join } from "path";
|
|
5
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
import chalk4 from "chalk";
|
|
8
8
|
|
|
@@ -23,15 +23,29 @@ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
23
23
|
|
|
24
24
|
// utils/common/createPrompt.ts
|
|
25
25
|
import chalk from "chalk";
|
|
26
|
+
import readline from "readline";
|
|
26
27
|
var PREFIX = chalk.bold(chalk.gray("?"));
|
|
27
|
-
var
|
|
28
|
+
var _prompt = "prompt" in globalThis ? globalThis.prompt : (question, defaultValue) => {
|
|
29
|
+
const rl = readline.createInterface({
|
|
30
|
+
input: process.stdin,
|
|
31
|
+
output: process.stdout
|
|
32
|
+
});
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
const q = defaultValue ? `${question} (${defaultValue}): ` : `${question}: `;
|
|
35
|
+
rl.question(q, (answer) => {
|
|
36
|
+
rl.close();
|
|
37
|
+
resolve(answer || defaultValue || "");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
var createPrompt = async (...args) => {
|
|
28
42
|
const question = args.shift();
|
|
29
43
|
if (!question) {
|
|
30
44
|
throw new Error("Question is required");
|
|
31
45
|
}
|
|
32
46
|
const defaultAnswer = args.shift();
|
|
33
|
-
const answer = defaultAnswer ?
|
|
34
|
-
return answer;
|
|
47
|
+
const answer = defaultAnswer ? _prompt(`${PREFIX} ${question}`, defaultAnswer) : _prompt(`${PREFIX} ${question}`);
|
|
48
|
+
return await answer;
|
|
35
49
|
};
|
|
36
50
|
|
|
37
51
|
// utils/babel/createParseOptions.ts
|
|
@@ -71,36 +85,124 @@ var showError = (message) => {
|
|
|
71
85
|
|
|
72
86
|
// commands/parsable/index.ts
|
|
73
87
|
var parsable_default = createCommand((program2) => {
|
|
74
|
-
program2.command("parsable").description("Check if the file is parsable").argument("[file]", "The file to check").option("--file <file>", "The file to check").
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
program2.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(
|
|
89
|
+
async (fileArgument, options) => {
|
|
90
|
+
await timeout(
|
|
91
|
+
async ({ finish }) => {
|
|
92
|
+
const filename = fileArgument ?? options.file ?? await createPrompt("Enter the file path:");
|
|
93
|
+
if (!filename) {
|
|
94
|
+
showError("No file provided");
|
|
95
|
+
return finish();
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const fileContent = readFileSync(filename, "utf8");
|
|
99
|
+
const loader = loading(
|
|
100
|
+
"Checking if the file is parsable..."
|
|
101
|
+
).start();
|
|
102
|
+
try {
|
|
103
|
+
parse(fileContent, createParseOptions(filename));
|
|
104
|
+
await sleep(500);
|
|
105
|
+
loader.succeed("File is parsable");
|
|
106
|
+
return finish();
|
|
107
|
+
} catch (error) {
|
|
108
|
+
loader.fail("File is not parsable");
|
|
109
|
+
showError(
|
|
110
|
+
`Error parsing file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
111
|
+
);
|
|
112
|
+
return finish();
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
showError(
|
|
116
|
+
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
117
|
+
);
|
|
118
|
+
return finish();
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
options.unlimited ? Infinity : 30 * 1e3
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// commands/scope-safe/index.ts
|
|
128
|
+
import { readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
129
|
+
import { basename, dirname, extname, join } from "path";
|
|
130
|
+
import { parse as parse2 } from "@babel/parser";
|
|
131
|
+
import traverse from "@babel/traverse";
|
|
132
|
+
import generate from "@babel/generator";
|
|
133
|
+
import loading2 from "loading-cli";
|
|
134
|
+
var createDefaultOutputPath = (inputPath) => {
|
|
135
|
+
const ext = extname(inputPath);
|
|
136
|
+
if (!ext) {
|
|
137
|
+
return `${inputPath}.scope-safe.js`;
|
|
138
|
+
}
|
|
139
|
+
const base = basename(inputPath, ext);
|
|
140
|
+
return join(dirname(inputPath), `${base}.scope-safe${ext}`);
|
|
141
|
+
};
|
|
142
|
+
var renameBindingsByScope = (code, filename) => {
|
|
143
|
+
const ast = parse2(code, createParseOptions(filename));
|
|
144
|
+
const renamedBindings = /* @__PURE__ */ new Set();
|
|
145
|
+
traverse(ast, {
|
|
146
|
+
Scopable(path) {
|
|
147
|
+
for (const [name, binding] of Object.entries(path.scope.bindings)) {
|
|
148
|
+
if (renamedBindings.has(binding)) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const shouldRename = !!path.scope.parent?.hasBinding(name);
|
|
152
|
+
if (!shouldRename) {
|
|
153
|
+
renamedBindings.add(binding);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const newName = path.scope.generateUid(name);
|
|
157
|
+
if (newName !== name) {
|
|
158
|
+
path.scope.rename(name, newName);
|
|
95
159
|
}
|
|
96
|
-
|
|
97
|
-
showError(
|
|
98
|
-
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
99
|
-
);
|
|
100
|
-
return finish();
|
|
160
|
+
renamedBindings.add(binding);
|
|
101
161
|
}
|
|
102
|
-
}
|
|
162
|
+
}
|
|
103
163
|
});
|
|
164
|
+
return generate(ast).code;
|
|
165
|
+
};
|
|
166
|
+
var scope_safe_default = createCommand((program2) => {
|
|
167
|
+
program2.command("scope-safe").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(
|
|
168
|
+
async (fileArgument, options) => {
|
|
169
|
+
await timeout(
|
|
170
|
+
async ({ finish }) => {
|
|
171
|
+
const filename = fileArgument ?? options.file ?? await createPrompt("Enter the file path:");
|
|
172
|
+
if (!filename) {
|
|
173
|
+
showError("No file provided");
|
|
174
|
+
return finish();
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const fileContent = readFileSync2(filename, "utf8");
|
|
178
|
+
const defaultOutputPath = createDefaultOutputPath(filename);
|
|
179
|
+
let outputPath = options.output ?? (await createPrompt(
|
|
180
|
+
"Enter the output file path:"
|
|
181
|
+
) || "").trim() ?? defaultOutputPath;
|
|
182
|
+
const loader = loading2("Renaming variables by scope...").start();
|
|
183
|
+
try {
|
|
184
|
+
const output = renameBindingsByScope(fileContent, filename);
|
|
185
|
+
writeFileSync(outputPath, output, "utf8");
|
|
186
|
+
loader.succeed(`Saved scope-safe file to: ${outputPath}`);
|
|
187
|
+
return finish();
|
|
188
|
+
} catch (error) {
|
|
189
|
+
loader.fail("Failed to apply scope-safe transform");
|
|
190
|
+
showError(
|
|
191
|
+
`Error transforming file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
192
|
+
);
|
|
193
|
+
return finish();
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
showError(
|
|
197
|
+
`Error reading file '${filename}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
198
|
+
);
|
|
199
|
+
return finish();
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
options.unlimited ? Infinity : 120 * 1e3
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
);
|
|
104
206
|
});
|
|
105
207
|
|
|
106
208
|
// utils/cli/showCredit.ts
|
|
@@ -117,7 +219,7 @@ var beautify = (strings, ...values) => {
|
|
|
117
219
|
return result;
|
|
118
220
|
};
|
|
119
221
|
var isNoColor = () => {
|
|
120
|
-
return
|
|
222
|
+
return Bun.env.NO_COLOR !== void 0 && Bun.argv.includes("--no-color");
|
|
121
223
|
};
|
|
122
224
|
var calmGradienrain = (text) => {
|
|
123
225
|
if (isNoColor()) {
|
|
@@ -154,10 +256,10 @@ ${calmGradienrain(`Expose Kit v${VERSION}`)}
|
|
|
154
256
|
`;
|
|
155
257
|
|
|
156
258
|
// index.ts
|
|
157
|
-
import { readFileSync as
|
|
259
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
158
260
|
var __filename = fileURLToPath(import.meta.url);
|
|
159
|
-
var __dirname =
|
|
160
|
-
var pkg = JSON.parse(
|
|
261
|
+
var __dirname = dirname2(__filename);
|
|
262
|
+
var pkg = JSON.parse(readFileSync3(join2(__dirname, "package.json"), "utf8"));
|
|
161
263
|
console.log(showCredit(pkg.version));
|
|
162
264
|
console.log();
|
|
163
265
|
var program = new Command();
|
|
@@ -166,7 +268,7 @@ program.name("expose").description("CLI for Deobfuscating").version(
|
|
|
166
268
|
"-v, --version",
|
|
167
269
|
"display version number"
|
|
168
270
|
);
|
|
169
|
-
var commands = [parsable_default];
|
|
271
|
+
var commands = [parsable_default, scope_safe_default];
|
|
170
272
|
for (const command of commands) {
|
|
171
273
|
command(program);
|
|
172
274
|
}
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expose-kit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "EdamAmex <edame8080@gmail.com> (https://github.com/EdamAme-x)",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"build": "tsup",
|
|
25
25
|
"postbuild": "publint",
|
|
26
26
|
"prepublishOnly": "bun copy",
|
|
27
|
-
"release": "np"
|
|
27
|
+
"release": "bun run build && np"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@biomejs/biome": "2.3.11",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expose-kit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "EdamAmex <edame8080@gmail.com> (https://github.com/EdamAme-x)",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"build": "tsup",
|
|
25
25
|
"postbuild": "publint",
|
|
26
26
|
"prepublishOnly": "bun copy",
|
|
27
|
-
"release": "np"
|
|
27
|
+
"release": "bun run build && np"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@biomejs/biome": "2.3.11",
|