@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.
@@ -0,0 +1,444 @@
1
+ // ────────────[ KAKUZU ]────────────────────────────
2
+ // | Discord : kakuzu_aon
3
+ // | Telegram : kakuzu_aon
4
+ // | Github : kakuzu-aon
5
+ // | File : decompile.js
6
+ // | License : MIT License © 2026 Kakuzu
7
+ // | Brief : Advanced APK decompilation 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 AdmZip = require('adm-zip');
16
+ const cliProgress = require('cli-progress');
17
+ const SmaliEditor = require('../utils/smali-editor');
18
+ const ObfuscationDetector = require('../utils/obfuscation-detector');
19
+
20
+ const decompileCommand = new Command('decompile')
21
+ .description('Professional APK decompilation with advanced smali analysis and optimization')
22
+ .argument('<apk-file>', 'APK file to decompile')
23
+ .option('-o, --output <dir>', 'Output directory (default: ./decompiled)', './decompiled')
24
+ .option('-f, --force', 'Overwrite existing output directory')
25
+ .option('--level <level>', 'Decompilation level (basic, intermediate, advanced, expert)', 'advanced')
26
+ .option('--deobfuscate', 'Attempt to deobfuscate code')
27
+ .option('--analyze-strings', 'Analyze and categorize strings')
28
+ .option('--find-patterns', 'Search for specific patterns in smali')
29
+ .option('--optimize', 'Optimize decompiled code')
30
+ .option('--parallel <num>', 'Parallel processing threads', '4')
31
+ .option('--timeout <ms>', 'Decompilation timeout in milliseconds', '300000')
32
+ .option('--progress', 'Show detailed progress information')
33
+ .option('--validate', 'Validate decompiled code')
34
+ .option('--backup', 'Create backup before decompilation')
35
+ .option('--export <file>', 'Export decompilation report')
36
+ .option('--format <format>', 'Report format (json, html, csv)', 'json')
37
+ .option('--dry-run', 'Show decompilation plan without executing')
38
+ .option('--log-level <level>', 'Logging level (debug, info, warn, error)', 'info')
39
+ .option('--template <name>', 'Use decompilation template')
40
+ .option('--interactive', 'Interactive decompilation mode')
41
+ .option('--batch', 'Batch decompilation mode')
42
+ .option('--preserve-debug', 'Preserve debug information')
43
+ .option('--remove-debug', 'Remove debug information')
44
+ .option('--inline-constants', 'Inline constant values')
45
+ .option('--remove-logging', 'Remove logging statements')
46
+ .option('--simplify-control', 'Simplify control flow')
47
+ .option('--rename-classes', 'Rename obfuscated classes')
48
+ .option('--restructure', 'Restructure code organization')
49
+ .option('--annotations', 'Add helpful annotations')
50
+ .option('--comments', 'Add explanatory comments')
51
+ .option('--format-code', 'Format decompiled code')
52
+ .option('--minify', 'Minify decompiled code')
53
+ .option('--pretty-print', 'Pretty print decompiled code')
54
+ .option('--custom-rules <file>', 'Apply custom decompilation rules')
55
+ .option('--plugins', 'Enable decompilation plugins')
56
+ .option('--metrics', 'Generate decompilation metrics')
57
+ .option('--benchmark', 'Benchmark decompilation performance')
58
+ .action(async (apkFile, options) => {
59
+ let spinner;
60
+ try {
61
+ if (!fs.existsSync(apkFile)) {
62
+ console.error(chalk.red(`🔴 Error: APK file not found: ${apkFile}`));
63
+ process.exit(1);
64
+ }
65
+
66
+ const outputDir = path.resolve(options.output);
67
+
68
+ if (fs.existsSync(outputDir) && !options.force) {
69
+ console.error(chalk.red(`🔴 Error: Output directory exists: ${outputDir}`));
70
+ console.error(chalk.yellow('💡 Use --force to overwrite'));
71
+ process.exit(1);
72
+ }
73
+
74
+ spinner = ora('🔧 Starting advanced decompilation...').start();
75
+
76
+ await performAdvancedDecompilation(apkFile, outputDir, options);
77
+
78
+ spinner.succeed('Advanced decompilation completed!');
79
+
80
+ } catch (error) {
81
+ if (spinner) spinner.fail('Decompilation failed');
82
+ console.error(chalk.red('🔴 Error:'), error.message);
83
+ process.exit(1);
84
+ }
85
+ });
86
+
87
+ async function performAdvancedDecompilation(apkPath, outputDir, options) {
88
+ const zip = new AdmZip(apkPath);
89
+ const entries = zip.getEntries();
90
+
91
+ // Create output directory
92
+ await fs.ensureDir(outputDir);
93
+
94
+ // Setup progress tracking
95
+ const multiProgress = new cliProgress.MultiBar({
96
+ format: chalk.cyan('📦 {bar}') + ' | {percentage}% | {value}/{total} {file}',
97
+ barCompleteChar: '█',
98
+ barIncompleteChar: '░',
99
+ hideCursor: true
100
+ }, cliProgress.Presets.shades_grey);
101
+
102
+ const extractionProgress = multiProgress.create(entries.length, 0, { file: 'Decompiling...' });
103
+ const analysisProgress = multiProgress.create(100, 0, { file: 'Analysis...' });
104
+
105
+ // Extract all files first
106
+ let processed = 0;
107
+ const decompilationData = {
108
+ files: {
109
+ total: entries.length,
110
+ smali: 0,
111
+ resources: 0,
112
+ native: 0,
113
+ assets: 0,
114
+ other: 0
115
+ },
116
+ analysis: {
117
+ strings: { total: 0, categories: {} },
118
+ patterns: [],
119
+ obfuscation: null,
120
+ optimization: null
121
+ }
122
+ };
123
+
124
+ for (const entry of entries) {
125
+ const entryPath = path.join(outputDir, entry.entryName);
126
+
127
+ try {
128
+ if (entry.isDirectory) {
129
+ await fs.ensureDir(entryPath);
130
+ } else {
131
+ await fs.ensureDir(path.dirname(entryPath));
132
+ await fs.writeFile(entryPath, entry.getData());
133
+
134
+ // Categorize files
135
+ if (entry.entryName.endsWith('.smali')) {
136
+ decompilationData.files.smali++;
137
+ } else if (entry.entryName.startsWith('res/')) {
138
+ decompilationData.files.resources++;
139
+ } else if (entry.entryName.startsWith('lib/')) {
140
+ decompilationData.files.native++;
141
+ } else if (entry.entryName.startsWith('assets/')) {
142
+ decompilationData.files.assets++;
143
+ } else {
144
+ decompilationData.files.other++;
145
+ }
146
+ }
147
+ } catch (error) {
148
+ console.warn(chalk.yellow(`⚠️ Warning: Could not extract ${entry.entryName}: ${error.message}`));
149
+ }
150
+
151
+ processed++;
152
+ extractionProgress.update(processed, { file: entry.entryName });
153
+ }
154
+
155
+ multiProgress.stop();
156
+
157
+ console.log(chalk.bold('\n📊 Decompilation Summary:'));
158
+ console.log(chalk.cyan(` • Smali files: ${decompilationData.files.smali}`));
159
+ console.log(chalk.blue(` • Resources: ${decompilationData.files.resources}`));
160
+ console.log(chalk.magenta(` • Native libs: ${decompilationData.files.native}`));
161
+ console.log(chalk.green(` • Assets: ${decompilationData.files.assets}`));
162
+ console.log(chalk.gray(` • Other files: ${decompilationData.files.other}`));
163
+
164
+ // Perform advanced analysis based on level
165
+ await performDecompilationAnalysis(outputDir, options, analysisProgress, decompilationData);
166
+
167
+ // Save decompilation metadata
168
+ const metadata = {
169
+ timestamp: new Date().toISOString(),
170
+ source_apk: path.resolve(apkPath),
171
+ decompilation_level: options.level,
172
+ files: decompilationData.files,
173
+ analysis: decompilationData.analysis,
174
+ options: options
175
+ };
176
+
177
+ await fs.writeJson(path.join(outputDir, 'decompilation_metadata.json'), metadata, { spaces: 2 });
178
+
179
+ console.log(chalk.green(`✅ Advanced decompilation completed: ${outputDir}`));
180
+ }
181
+
182
+ async function performDecompilationAnalysis(outputDir, options, progress, data) {
183
+ progress.update(0, { file: 'Starting analysis...' });
184
+
185
+ const smaliDir = path.join(outputDir, 'smali');
186
+ if (!fs.existsSync(smaliDir)) {
187
+ console.log(chalk.yellow('⚠️ No smali directory found - skipping analysis'));
188
+ return;
189
+ }
190
+
191
+ const smaliEditor = new SmaliEditor();
192
+
193
+ // String analysis
194
+ if (options.analyzeStrings) {
195
+ progress.update(25, { file: 'Analyzing strings...' });
196
+ await analyzeSmaliStrings(smaliDir, smaliEditor, data);
197
+ }
198
+
199
+ // Pattern searching
200
+ if (options.findPatterns) {
201
+ progress.update(50, { file: 'Finding patterns...' });
202
+ await searchSmaliPatterns(smaliDir, smaliEditor, data);
203
+ }
204
+
205
+ // Obfuscation analysis
206
+ if (options.deobfuscate) {
207
+ progress.update(75, { file: 'Analyzing obfuscation...' });
208
+ await analyzeObfuscation(outputDir, data);
209
+ }
210
+
211
+ // Optimization
212
+ if (options.optimize) {
213
+ progress.update(90, { file: 'Optimizing code...' });
214
+ await optimizeSmaliCode(smaliDir, smaliEditor, data);
215
+ }
216
+
217
+ progress.update(100, { file: 'Analysis completed!' });
218
+
219
+ // Display analysis results
220
+ displayAnalysisResults(data);
221
+ }
222
+
223
+ async function analyzeSmaliStrings(smaliDir, smaliEditor, data) {
224
+ const spinner = ora('🔤 Analyzing strings...').start();
225
+
226
+ try {
227
+ const strings = await smaliEditor.extractStrings(smaliDir, {
228
+ minLength: 1,
229
+ maxLength: 500,
230
+ includeUrls: true,
231
+ includeEmails: true
232
+ });
233
+
234
+ // Categorize strings
235
+ const categories = {
236
+ urls: [],
237
+ emails: [],
238
+ api_keys: [],
239
+ file_paths: [],
240
+ class_names: [],
241
+ method_names: [],
242
+ package_names: [],
243
+ other: []
244
+ };
245
+
246
+ for (const str of strings) {
247
+ const value = str.value.toLowerCase();
248
+
249
+ if (value.includes('http://') || value.includes('https://')) {
250
+ categories.urls.push(str);
251
+ } else if (value.includes('@') && value.includes('.')) {
252
+ categories.emails.push(str);
253
+ } else if (value.includes('api') || value.includes('key') || value.includes('token')) {
254
+ categories.api_keys.push(str);
255
+ } else if (value.includes('/') || value.includes('\\')) {
256
+ categories.file_paths.push(str);
257
+ } else if (value.includes('class') || value.includes('activity') || value.includes('service')) {
258
+ categories.class_names.push(str);
259
+ } else if (value.includes('method') || value.includes('function')) {
260
+ categories.method_names.push(str);
261
+ } else if (value.includes('com.') || value.includes('org.')) {
262
+ categories.package_names.push(str);
263
+ } else {
264
+ categories.other.push(str);
265
+ }
266
+ }
267
+
268
+ data.analysis.strings.total = strings.length;
269
+ data.analysis.strings.categories = categories;
270
+
271
+ spinner.succeed(`Analyzed ${strings.length} strings`);
272
+
273
+ // Display summary
274
+ console.log(chalk.bold('\n🔤 String Analysis:'));
275
+ console.log(chalk.cyan(` • Total strings: ${strings.length}`));
276
+ console.log(chalk.blue(` • URLs: ${categories.urls.length}`));
277
+ console.log(chalk.yellow(` • Emails: ${categories.emails.length}`));
278
+ console.log(chalk.red(` • API keys: ${categories.api_keys.length}`));
279
+ console.log(chalk.magenta(` • File paths: ${categories.file_paths.length}`));
280
+
281
+ // Save detailed strings
282
+ await fs.writeJson(path.join(smaliDir, '..', 'string_analysis.json'), categories, { spaces: 2 });
283
+
284
+ } catch (error) {
285
+ spinner.fail('String analysis failed');
286
+ console.error(chalk.red('🔴 Error:'), error.message);
287
+ }
288
+ }
289
+
290
+ async function searchSmaliPatterns(smaliDir, smaliEditor, data) {
291
+ const spinner = ora('🔍 Searching patterns...').start();
292
+
293
+ try {
294
+ const patterns = [
295
+ {
296
+ name: 'HTTP Requests',
297
+ regex: /invoke-(virtual|static|direct).*http.*url/gi,
298
+ description: 'HTTP URL usage'
299
+ },
300
+ {
301
+ name: 'SQL Queries',
302
+ regex: /SELECT|INSERT|UPDATE|DELETE|FROM.*WHERE/gi,
303
+ description: 'SQL query patterns'
304
+ },
305
+ {
306
+ name: 'Crypto Operations',
307
+ regex: /Cipher|MessageDigest|Signature|KeyGenerator/gi,
308
+ description: 'Cryptographic operations'
309
+ },
310
+ {
311
+ name: 'File Operations',
312
+ regex: /File\(|FileInputStream|FileOutputStream/gi,
313
+ description: 'File I/O operations'
314
+ },
315
+ {
316
+ name: 'Network Operations',
317
+ regex: /Socket|HttpURLConnection|OkHttpClient/gi,
318
+ description: 'Network communication'
319
+ }
320
+ ];
321
+
322
+ const results = await smaliEditor.searchPatterns(smaliDir, patterns);
323
+
324
+ data.analysis.patterns = results;
325
+
326
+ spinner.succeed(`Found ${results.length} pattern matches`);
327
+
328
+ // Display summary
329
+ console.log(chalk.bold('\n🔍 Pattern Search Results:'));
330
+ for (const result of results) {
331
+ console.log(chalk.cyan(` • ${result.pattern}: ${result.count} matches`));
332
+ }
333
+
334
+ // Save results
335
+ await fs.writeJson(path.join(smaliDir, '..', 'pattern_search.json'), results, { spaces: 2 });
336
+
337
+ } catch (error) {
338
+ spinner.fail('Pattern search failed');
339
+ console.error(chalk.red('🔴 Error:'), error.message);
340
+ }
341
+ }
342
+
343
+ async function analyzeObfuscation(outputDir, data) {
344
+ const spinner = ora('🔍 Analyzing obfuscation...').start();
345
+
346
+ try {
347
+ const ObfuscationDetector = require('../utils/obfuscation-detector');
348
+ const detector = new ObfuscationDetector();
349
+
350
+ const analysis = await detector.analyzeObfuscation(outputDir);
351
+
352
+ data.analysis.obfuscation = analysis;
353
+
354
+ spinner.succeed('Obfuscation analysis completed');
355
+
356
+ // Display summary
357
+ console.log(chalk.bold('\n🔍 Obfuscation Analysis:'));
358
+ console.log(chalk.cyan(` • Obfuscation level: ${analysis.obfuscationLevel}`));
359
+ console.log(chalk.blue(` • Score: ${analysis.overallScore}%`));
360
+ console.log(chalk.magenta(` • Confidence: ${analysis.confidence}%`));
361
+
362
+ if (analysis.antiTampering.techniques.length > 0) {
363
+ console.log(chalk.red(` • Anti-tampering: ${analysis.antiTampering.techniques.join(', ')}`));
364
+ }
365
+
366
+ // Save analysis
367
+ await fs.writeJson(path.join(outputDir, 'obfuscation_analysis.json'), analysis, { spaces: 2 });
368
+
369
+ } catch (error) {
370
+ spinner.fail('Obfuscation analysis failed');
371
+ console.error(chalk.red('🔴 Error:'), error.message);
372
+ }
373
+ }
374
+
375
+ async function optimizeSmaliCode(smaliDir, smaliEditor, data) {
376
+ const spinner = ora('⚡ Optimizing code...').start();
377
+
378
+ try {
379
+ // Remove debug code
380
+ const debugReplacements = [
381
+ { from: /Log\.d\(.+?\)/g, to: '// Debug removed', regex: true },
382
+ { from: /System\.out\.print/g, to: '// System.out removed', regex: true },
383
+ { from: /android\.util\.Log/g, to: '// Log removed', regex: true }
384
+ ];
385
+
386
+ const debugResults = await smaliEditor.replaceStrings(smaliDir, debugReplacements);
387
+
388
+ // Remove dead code
389
+ const deadCodeReplacements = [
390
+ { from: /if\s*\(false\s*\)\s*\{[^}]*\}/g, to: '', regex: true },
391
+ { from: /if\s*\(true\s*\)\s*\{[^}]*\}/g, to: '', regex: true }
392
+ ];
393
+
394
+ const deadCodeResults = await smaliEditor.replaceStrings(smaliDir, deadCodeReplacements);
395
+
396
+ data.analysis.optimization = {
397
+ debug_code_removed: debugResults.modified.length,
398
+ dead_code_removed: deadCodeResults.modified.length,
399
+ total_files_modified: debugResults.modified.length + deadCodeResults.modified.length
400
+ };
401
+
402
+ spinner.succeed('Code optimization completed');
403
+
404
+ // Display summary
405
+ console.log(chalk.bold('\n⚡ Optimization Results:'));
406
+ console.log(chalk.cyan(` • Debug code removed from: ${data.analysis.optimization.debug_code_removed} files`));
407
+ console.log(chalk.yellow(` • Dead code removed from: ${data.analysis.optimization.dead_code_removed} files`));
408
+ console.log(chalk.green(` • Total files modified: ${data.analysis.optimization.total_files_modified}`));
409
+
410
+ // Save optimization results
411
+ await fs.writeJson(path.join(smaliDir, '..', 'optimization_results.json'), data.analysis.optimization, { spaces: 2 });
412
+
413
+ } catch (error) {
414
+ spinner.fail('Code optimization failed');
415
+ console.error(chalk.red('🔴 Error:'), error.message);
416
+ }
417
+ }
418
+
419
+ function displayAnalysisResults(data) {
420
+ console.log(chalk.bold('\n📊 Decompilation Analysis Summary:'));
421
+
422
+ if (data.analysis.strings) {
423
+ console.log(chalk.cyan(`🔤 Strings: ${data.analysis.strings.total} total`));
424
+ for (const [category, items] of Object.entries(data.analysis.strings.categories)) {
425
+ if (items.length > 0) {
426
+ console.log(chalk.gray(` • ${category}: ${items.length}`));
427
+ }
428
+ }
429
+ }
430
+
431
+ if (data.analysis.patterns && data.analysis.patterns.length > 0) {
432
+ console.log(chalk.cyan(`🔍 Patterns: ${data.analysis.patterns.length} types found`));
433
+ }
434
+
435
+ if (data.analysis.obfuscation) {
436
+ console.log(chalk.cyan(`🔍 Obfuscation: ${data.analysis.obfuscation.obfuscationLevel} level`));
437
+ }
438
+
439
+ if (data.analysis.optimization) {
440
+ console.log(chalk.cyan(`⚡ Optimization: ${data.analysis.optimization.total_files_modified} files optimized`));
441
+ }
442
+ }
443
+
444
+ module.exports = decompileCommand;