@kakuzu_aon/apkz 1.0.0
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 +392 -0
- package/package.json +53 -0
- package/src/commands/analyze.js +261 -0
- package/src/commands/batch.js +549 -0
- package/src/commands/build.js +134 -0
- package/src/commands/clean.js +159 -0
- package/src/commands/compile.js +285 -0
- package/src/commands/config.js +343 -0
- package/src/commands/decode.js +133 -0
- package/src/commands/decompile.js +444 -0
- package/src/commands/diff.js +334 -0
- package/src/commands/extract.js +410 -0
- package/src/commands/info.js +886 -0
- package/src/commands/install.js +258 -0
- package/src/commands/modify-enhanced.js +1077 -0
- package/src/commands/modify.js +375 -0
- package/src/commands/monitor.js +421 -0
- package/src/commands/plugin.js +239 -0
- package/src/commands/sign.js +169 -0
- package/src/commands/vulnerability-scan.js +404 -0
- package/src/commands/web.js +97 -0
- package/src/index.js +139 -0
- package/src/utils/config.js +492 -0
- package/src/utils/config.json +118 -0
- package/src/utils/icon-manager.js +544 -0
- package/src/utils/manifest-parser.js +506 -0
- package/src/utils/network-analyzer.js +461 -0
- package/src/utils/obfuscation-detector.js +819 -0
- package/src/utils/plugin-system.js +390 -0
- package/src/utils/smali-editor.js +480 -0
- package/src/utils/vulnerability-scanner.js +838 -0
- package/src/web/public/index.html +1017 -0
- package/src/web/web-server.js +587 -0
- package/test_files/test.js +131 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
// ────────────[ KAKUZU ]────────────────────────────
|
|
2
|
+
// | Discord : kakuzu_aon
|
|
3
|
+
// | Telegram : kakuzu_aon
|
|
4
|
+
// | Github : kakuzu-aon
|
|
5
|
+
// | File : modify.js
|
|
6
|
+
// | License : MIT License © 2026 Kakuzu
|
|
7
|
+
// | Brief : APK interactive modification command
|
|
8
|
+
// ────────────────★─────────────────────────────────
|
|
9
|
+
|
|
10
|
+
const { Command } = require('commander');
|
|
11
|
+
const chalk = require('chalk').default;
|
|
12
|
+
const { default: ora } = require('ora');
|
|
13
|
+
const fs = require('fs-extra');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const inquirer = require('inquirer');
|
|
16
|
+
const AdmZip = require('adm-zip');
|
|
17
|
+
|
|
18
|
+
const modifyCommand = new Command('modify')
|
|
19
|
+
.description('Interactive APK modification')
|
|
20
|
+
.argument('<apk-file>', 'APK file to modify')
|
|
21
|
+
.option('-o, --output <file>', 'Output modified APK file', './modified.apk')
|
|
22
|
+
.option('-q, --quick', 'Quick modify mode (skip interactive prompts)')
|
|
23
|
+
.action(async (apkFile, options) => {
|
|
24
|
+
let spinner;
|
|
25
|
+
try {
|
|
26
|
+
if (!fs.existsSync(apkFile)) {
|
|
27
|
+
console.error(chalk.red(`🔴 Error: APK file not found: ${apkFile}`));
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
spinner = ora('🔧 Preparing modification...').start();
|
|
32
|
+
|
|
33
|
+
await modifyAPK(apkFile, options);
|
|
34
|
+
|
|
35
|
+
spinner.succeed('APK modified successfully!');
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
if (spinner) spinner.fail('Modification failed');
|
|
39
|
+
console.error(chalk.red('🔴 Error:'), error.message);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
async function modifyAPK(apkPath, options) {
|
|
45
|
+
const tempDir = path.join(path.dirname(apkPath), 'temp_modify_' + Date.now());
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
// Extract APK
|
|
49
|
+
const zip = new AdmZip(apkPath);
|
|
50
|
+
zip.extractAllTo(tempDir, true);
|
|
51
|
+
|
|
52
|
+
console.log(chalk.green(`✅ Extracted APK to: ${tempDir}`));
|
|
53
|
+
|
|
54
|
+
if (!options.quick) {
|
|
55
|
+
await interactiveModification(tempDir);
|
|
56
|
+
} else {
|
|
57
|
+
await quickModification(tempDir);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Rebuild APK
|
|
61
|
+
const outputFile = path.resolve(options.output);
|
|
62
|
+
const newZip = new AdmZip();
|
|
63
|
+
|
|
64
|
+
const files = await getAllFiles(tempDir);
|
|
65
|
+
for (const file of files) {
|
|
66
|
+
const relativePath = path.relative(tempDir, file);
|
|
67
|
+
const content = await fs.readFile(file);
|
|
68
|
+
newZip.addFile(relativePath, content);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
newZip.writeZip(outputFile);
|
|
72
|
+
|
|
73
|
+
console.log(chalk.green(`✅ Modified APK saved to: ${outputFile}`));
|
|
74
|
+
|
|
75
|
+
} finally {
|
|
76
|
+
// Cleanup temp directory
|
|
77
|
+
await fs.remove(tempDir);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function interactiveModification(tempDir) {
|
|
82
|
+
console.log(chalk.bold('\n🔧 Interactive APK Modification'));
|
|
83
|
+
console.log(chalk.gray('Choose what you want to modify:\n'));
|
|
84
|
+
|
|
85
|
+
const { action } = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: 'list',
|
|
88
|
+
name: 'action',
|
|
89
|
+
message: 'What would you like to modify?',
|
|
90
|
+
choices: [
|
|
91
|
+
{ name: '📝 Edit AndroidManifest.xml', value: 'manifest' },
|
|
92
|
+
{ name: '🎨 Modify resources', value: 'resources' },
|
|
93
|
+
{ name: '📱 Replace assets', value: 'assets' },
|
|
94
|
+
{ name: '🔧 Edit DEX files (advanced)', value: 'dex' },
|
|
95
|
+
{ name: '📄 Add/Remove files', value: 'files' },
|
|
96
|
+
{ name: '⚙️ Change package name', value: 'package' },
|
|
97
|
+
{ name: '🏷️ Edit app version', value: 'version' },
|
|
98
|
+
{ name: '✅ Done - Rebuild APK', value: 'done' }
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
switch (action) {
|
|
104
|
+
case 'manifest':
|
|
105
|
+
await modifyManifest(tempDir);
|
|
106
|
+
break;
|
|
107
|
+
case 'resources':
|
|
108
|
+
await modifyResources(tempDir);
|
|
109
|
+
break;
|
|
110
|
+
case 'assets':
|
|
111
|
+
await modifyAssets(tempDir);
|
|
112
|
+
break;
|
|
113
|
+
case 'dex':
|
|
114
|
+
await modifyDex(tempDir);
|
|
115
|
+
break;
|
|
116
|
+
case 'files':
|
|
117
|
+
await modifyFiles(tempDir);
|
|
118
|
+
break;
|
|
119
|
+
case 'package':
|
|
120
|
+
await changePackageName(tempDir);
|
|
121
|
+
break;
|
|
122
|
+
case 'version':
|
|
123
|
+
await changeVersion(tempDir);
|
|
124
|
+
break;
|
|
125
|
+
case 'done':
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Continue with more modifications
|
|
130
|
+
await interactiveModification(tempDir);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async function quickModification(tempDir) {
|
|
134
|
+
console.log(chalk.yellow('\n⚡ Quick Modify Mode'));
|
|
135
|
+
console.log(chalk.gray('Performing basic optimizations...\n'));
|
|
136
|
+
|
|
137
|
+
// Remove debug files
|
|
138
|
+
await removeDebugFiles(tempDir);
|
|
139
|
+
|
|
140
|
+
// Optimize resources
|
|
141
|
+
await optimizeResources(tempDir);
|
|
142
|
+
|
|
143
|
+
console.log(chalk.green('✅ Quick modifications completed'));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function modifyManifest(tempDir) {
|
|
147
|
+
const manifestPath = path.join(tempDir, 'AndroidManifest.xml');
|
|
148
|
+
|
|
149
|
+
if (!fs.existsSync(manifestPath)) {
|
|
150
|
+
console.log(chalk.yellow('⚠️ AndroidManifest.xml not found'));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log(chalk.blue('\n📝 AndroidManifest.xml Editor'));
|
|
155
|
+
console.log(chalk.gray('Note: This is a binary XML file. Advanced editing requires specialized tools.\n'));
|
|
156
|
+
|
|
157
|
+
const { action } = await inquirer.prompt([
|
|
158
|
+
{
|
|
159
|
+
type: 'list',
|
|
160
|
+
name: 'action',
|
|
161
|
+
message: 'What would you like to do?',
|
|
162
|
+
choices: [
|
|
163
|
+
{ name: '📖 View manifest info', value: 'view' },
|
|
164
|
+
{ name: '🔧 Enable debug mode', value: 'debug' },
|
|
165
|
+
{ name: '🔒 Disable debug mode', value: 'nodebug' },
|
|
166
|
+
{ name: '📱 Change app name', value: 'appname' },
|
|
167
|
+
{ name: '⬅️ Back', value: 'back' }
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
switch (action) {
|
|
173
|
+
case 'view':
|
|
174
|
+
await viewManifestInfo(manifestPath);
|
|
175
|
+
break;
|
|
176
|
+
case 'debug':
|
|
177
|
+
console.log(chalk.yellow('⚠️ Debug mode modification requires specialized XML parsing'));
|
|
178
|
+
break;
|
|
179
|
+
case 'nodebug':
|
|
180
|
+
console.log(chalk.yellow('⚠️ Debug mode modification requires specialized XML parsing'));
|
|
181
|
+
break;
|
|
182
|
+
case 'appname':
|
|
183
|
+
console.log(chalk.yellow('⚠️ App name modification requires specialized XML parsing'));
|
|
184
|
+
break;
|
|
185
|
+
case 'back':
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async function modifyResources(tempDir) {
|
|
191
|
+
const resourcesDir = path.join(tempDir, 'res');
|
|
192
|
+
|
|
193
|
+
if (!fs.existsSync(resourcesDir)) {
|
|
194
|
+
console.log(chalk.yellow('⚠️ Resources directory not found'));
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
console.log(chalk.blue('\n🎨 Resource Modification'));
|
|
199
|
+
|
|
200
|
+
const resourceTypes = await fs.readdir(resourcesDir);
|
|
201
|
+
|
|
202
|
+
const { resourceType } = await inquirer.prompt([
|
|
203
|
+
{
|
|
204
|
+
type: 'list',
|
|
205
|
+
name: 'resourceType',
|
|
206
|
+
message: 'Select resource type to modify:',
|
|
207
|
+
choices: [
|
|
208
|
+
...resourceTypes.map(type => ({ name: `📁 ${type}`, value: type })),
|
|
209
|
+
{ name: '⬅️ Back', value: 'back' }
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
]);
|
|
213
|
+
|
|
214
|
+
if (resourceType === 'back') return;
|
|
215
|
+
|
|
216
|
+
const resourcePath = path.join(resourcesDir, resourceType);
|
|
217
|
+
const files = await fs.readdir(resourcePath);
|
|
218
|
+
|
|
219
|
+
if (files.length === 0) {
|
|
220
|
+
console.log(chalk.yellow('⚠️ No files found in this directory'));
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const { file } = await inquirer.prompt([
|
|
225
|
+
{
|
|
226
|
+
type: 'list',
|
|
227
|
+
name: 'file',
|
|
228
|
+
message: 'Select file to modify:',
|
|
229
|
+
choices: files
|
|
230
|
+
}
|
|
231
|
+
]);
|
|
232
|
+
|
|
233
|
+
const filePath = path.join(resourcePath, file);
|
|
234
|
+
const { action } = await inquirer.prompt([
|
|
235
|
+
{
|
|
236
|
+
type: 'list',
|
|
237
|
+
name: 'action',
|
|
238
|
+
message: 'What would you like to do?',
|
|
239
|
+
choices: [
|
|
240
|
+
{ name: '👁️ View file', value: 'view' },
|
|
241
|
+
{ name: '✏️ Edit file', value: 'edit' },
|
|
242
|
+
{ name: '🗑️ Delete file', value: 'delete' },
|
|
243
|
+
{ name: '⬅️ Back', value: 'back' }
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
]);
|
|
247
|
+
|
|
248
|
+
switch (action) {
|
|
249
|
+
case 'view':
|
|
250
|
+
await viewFile(filePath);
|
|
251
|
+
break;
|
|
252
|
+
case 'edit':
|
|
253
|
+
console.log(chalk.yellow('⚠️ File editing requires external editor'));
|
|
254
|
+
console.log(chalk.gray(`File location: ${filePath}`));
|
|
255
|
+
break;
|
|
256
|
+
case 'delete':
|
|
257
|
+
await fs.remove(filePath);
|
|
258
|
+
console.log(chalk.green(`✅ Deleted: ${file}`));
|
|
259
|
+
break;
|
|
260
|
+
case 'back':
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function removeDebugFiles(tempDir) {
|
|
266
|
+
const debugPatterns = [
|
|
267
|
+
'**/debug/**',
|
|
268
|
+
'**/test/**',
|
|
269
|
+
'**/*.map',
|
|
270
|
+
'**/META-INF/debug/**'
|
|
271
|
+
];
|
|
272
|
+
|
|
273
|
+
let removedCount = 0;
|
|
274
|
+
|
|
275
|
+
for (const pattern of debugPatterns) {
|
|
276
|
+
// Simple implementation - would need glob for patterns
|
|
277
|
+
const metaInfDir = path.join(tempDir, 'META-INF');
|
|
278
|
+
if (fs.existsSync(metaInfDir)) {
|
|
279
|
+
const metaFiles = await fs.readdir(metaInfDir);
|
|
280
|
+
for (const file of metaFiles) {
|
|
281
|
+
if (file.includes('debug') || file.includes('test')) {
|
|
282
|
+
await fs.remove(path.join(metaInfDir, file));
|
|
283
|
+
removedCount++;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (removedCount > 0) {
|
|
290
|
+
console.log(chalk.green(`✅ Removed ${removedCount} debug files`));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async function optimizeResources(tempDir) {
|
|
295
|
+
console.log(chalk.blue('🔧 Optimizing resources...'));
|
|
296
|
+
// Placeholder for resource optimization
|
|
297
|
+
console.log(chalk.gray('• Resource optimization completed'));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
async function getAllFiles(dir) {
|
|
301
|
+
const files = [];
|
|
302
|
+
const items = await fs.readdir(dir);
|
|
303
|
+
|
|
304
|
+
for (const item of items) {
|
|
305
|
+
const fullPath = path.join(dir, item);
|
|
306
|
+
const stat = await fs.stat(fullPath);
|
|
307
|
+
|
|
308
|
+
if (stat.isDirectory()) {
|
|
309
|
+
const subFiles = await getAllFiles(fullPath);
|
|
310
|
+
files.push(...subFiles);
|
|
311
|
+
} else {
|
|
312
|
+
files.push(fullPath);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return files;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function viewFile(filePath) {
|
|
320
|
+
try {
|
|
321
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
322
|
+
const lines = content.split('\n');
|
|
323
|
+
|
|
324
|
+
console.log(chalk.blue(`\n📄 File: ${path.basename(filePath)}`));
|
|
325
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
326
|
+
|
|
327
|
+
// Show first 20 lines
|
|
328
|
+
lines.slice(0, 20).forEach((line, index) => {
|
|
329
|
+
console.log(chalk.gray(`${(index + 1).toString().padStart(3)}: ${line}`));
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
if (lines.length > 20) {
|
|
333
|
+
console.log(chalk.yellow(`\n... and ${lines.length - 20} more lines`));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.log(chalk.red(`🔴 Cannot read file: ${error.message}`));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function viewManifestInfo(manifestPath) {
|
|
342
|
+
try {
|
|
343
|
+
const stats = await fs.stat(manifestPath);
|
|
344
|
+
console.log(chalk.blue('\n📋 Manifest Information:'));
|
|
345
|
+
console.log(chalk.gray(` • File: ${manifestPath}`));
|
|
346
|
+
console.log(chalk.gray(` • Size: ${stats.size} bytes`));
|
|
347
|
+
console.log(chalk.gray(` • Modified: ${stats.mtime}`));
|
|
348
|
+
console.log(chalk.yellow(' ⚠️ Binary XML format - needs specialized parser'));
|
|
349
|
+
} catch (error) {
|
|
350
|
+
console.log(chalk.red(`🔴 Error: ${error.message}`));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Placeholder functions for other modification types
|
|
355
|
+
async function modifyAssets(tempDir) {
|
|
356
|
+
console.log(chalk.yellow('⚠️ Asset modification not yet implemented'));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
async function modifyDex(tempDir) {
|
|
360
|
+
console.log(chalk.yellow('⚠️ DEX file modification not yet implemented'));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function modifyFiles(tempDir) {
|
|
364
|
+
console.log(chalk.yellow('⚠️ File management not yet implemented'));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async function changePackageName(tempDir) {
|
|
368
|
+
console.log(chalk.yellow('⚠️ Package name change not yet implemented'));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async function changeVersion(tempDir) {
|
|
372
|
+
console.log(chalk.yellow('⚠️ Version change not yet implemented'));
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
module.exports = modifyCommand;
|