@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,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;
|