anais-apk-forensic 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.
Files changed (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/anais.sh +669 -0
  4. package/analysis_tools/__pycache__/apk_basic_info.cpython-313.pyc +0 -0
  5. package/analysis_tools/__pycache__/apk_basic_info.cpython-314.pyc +0 -0
  6. package/analysis_tools/__pycache__/check_zip_encryption.cpython-313.pyc +0 -0
  7. package/analysis_tools/__pycache__/check_zip_encryption.cpython-314.pyc +0 -0
  8. package/analysis_tools/__pycache__/detect_obfuscation.cpython-313.pyc +0 -0
  9. package/analysis_tools/__pycache__/detect_obfuscation.cpython-314.pyc +0 -0
  10. package/analysis_tools/__pycache__/dex_payload_hunter.cpython-314.pyc +0 -0
  11. package/analysis_tools/__pycache__/entropy_analyzer.cpython-314.pyc +0 -0
  12. package/analysis_tools/__pycache__/error_logger.cpython-313.pyc +0 -0
  13. package/analysis_tools/__pycache__/error_logger.cpython-314.pyc +0 -0
  14. package/analysis_tools/__pycache__/find_encrypted_payload.cpython-314.pyc +0 -0
  15. package/analysis_tools/__pycache__/fix_apk_headers.cpython-313.pyc +0 -0
  16. package/analysis_tools/__pycache__/fix_apk_headers.cpython-314.pyc +0 -0
  17. package/analysis_tools/__pycache__/manifest_analyzer.cpython-313.pyc +0 -0
  18. package/analysis_tools/__pycache__/manifest_analyzer.cpython-314.pyc +0 -0
  19. package/analysis_tools/__pycache__/network_analyzer.cpython-313.pyc +0 -0
  20. package/analysis_tools/__pycache__/network_analyzer.cpython-314.pyc +0 -0
  21. package/analysis_tools/__pycache__/report_generator.cpython-313.pyc +0 -0
  22. package/analysis_tools/__pycache__/report_generator.cpython-314.pyc +0 -0
  23. package/analysis_tools/__pycache__/report_generator_modular.cpython-314.pyc +0 -0
  24. package/analysis_tools/__pycache__/sast_scanner.cpython-313.pyc +0 -0
  25. package/analysis_tools/__pycache__/sast_scanner.cpython-314.pyc +0 -0
  26. package/analysis_tools/__pycache__/so_string_analyzer.cpython-314.pyc +0 -0
  27. package/analysis_tools/__pycache__/yara_enhanced_analyzer.cpython-314.pyc +0 -0
  28. package/analysis_tools/__pycache__/yara_results_processor.cpython-314.pyc +0 -0
  29. package/analysis_tools/apk_basic_info.py +85 -0
  30. package/analysis_tools/check_zip_encryption.py +142 -0
  31. package/analysis_tools/detect_obfuscation.py +650 -0
  32. package/analysis_tools/dex_payload_hunter.py +734 -0
  33. package/analysis_tools/entropy_analyzer.py +335 -0
  34. package/analysis_tools/error_logger.py +75 -0
  35. package/analysis_tools/find_encrypted_payload.py +485 -0
  36. package/analysis_tools/fix_apk_headers.py +154 -0
  37. package/analysis_tools/manifest_analyzer.py +214 -0
  38. package/analysis_tools/network_analyzer.py +287 -0
  39. package/analysis_tools/report_generator.py +506 -0
  40. package/analysis_tools/report_generator_modular.py +885 -0
  41. package/analysis_tools/sast_scanner.py +412 -0
  42. package/analysis_tools/so_string_analyzer.py +406 -0
  43. package/analysis_tools/yara_enhanced_analyzer.py +330 -0
  44. package/analysis_tools/yara_results_processor.py +368 -0
  45. package/analyzer_config.json +113 -0
  46. package/apkid/__init__.py +32 -0
  47. package/apkid/__pycache__/__init__.cpython-313.pyc +0 -0
  48. package/apkid/__pycache__/__init__.cpython-314.pyc +0 -0
  49. package/apkid/__pycache__/apkid.cpython-313.pyc +0 -0
  50. package/apkid/__pycache__/apkid.cpython-314.pyc +0 -0
  51. package/apkid/__pycache__/main.cpython-313.pyc +0 -0
  52. package/apkid/__pycache__/main.cpython-314.pyc +0 -0
  53. package/apkid/__pycache__/output.cpython-313.pyc +0 -0
  54. package/apkid/__pycache__/rules.cpython-313.pyc +0 -0
  55. package/apkid/apkid.py +266 -0
  56. package/apkid/main.py +98 -0
  57. package/apkid/output.py +177 -0
  58. package/apkid/rules/apk/common.yara +68 -0
  59. package/apkid/rules/apk/obfuscators.yara +118 -0
  60. package/apkid/rules/apk/packers.yara +1197 -0
  61. package/apkid/rules/apk/protectors.yara +301 -0
  62. package/apkid/rules/dex/abnormal.yara +104 -0
  63. package/apkid/rules/dex/anti-vm.yara +568 -0
  64. package/apkid/rules/dex/common.yara +60 -0
  65. package/apkid/rules/dex/compilers.yara +434 -0
  66. package/apkid/rules/dex/obfuscators.yara +602 -0
  67. package/apkid/rules/dex/packers.yara +761 -0
  68. package/apkid/rules/dex/protectors.yara +520 -0
  69. package/apkid/rules/dll/common.yara +38 -0
  70. package/apkid/rules/dll/obfuscators.yara +43 -0
  71. package/apkid/rules/elf/anti-vm.yara +43 -0
  72. package/apkid/rules/elf/common.yara +54 -0
  73. package/apkid/rules/elf/obfuscators.yara +991 -0
  74. package/apkid/rules/elf/packers.yara +1128 -0
  75. package/apkid/rules/elf/protectors.yara +794 -0
  76. package/apkid/rules/res/common.yara +43 -0
  77. package/apkid/rules/res/obfuscators.yara +46 -0
  78. package/apkid/rules/res/protectors.yara +46 -0
  79. package/apkid/rules.py +77 -0
  80. package/bin/anais +3 -0
  81. package/dist/cli.js +82 -0
  82. package/dist/index.js +123 -0
  83. package/dist/types/index.js +2 -0
  84. package/dist/utils/index.js +21 -0
  85. package/dist/utils/output.js +44 -0
  86. package/dist/utils/paths.js +107 -0
  87. package/docs/ARCHITECTURE.txt +353 -0
  88. package/docs/Workflow and Reference.md +445 -0
  89. package/package.json +70 -0
  90. package/rules/yara_general_rules.yar +323 -0
  91. package/scripts/dynamic_analysis_helper.sh +334 -0
  92. package/scripts/frida/dpt_dex_dumper.js +145 -0
  93. package/scripts/frida/frida_dex_dump.js +145 -0
  94. package/scripts/frida/frida_hooks.js +437 -0
  95. package/scripts/frida/frida_websocket_extractor.js +154 -0
  96. package/scripts/setup.sh +206 -0
  97. package/scripts/validate_framework.sh +224 -0
  98. package/src/cli.ts +91 -0
  99. package/src/index.ts +123 -0
  100. package/src/types/index.ts +44 -0
  101. package/src/utils/index.ts +6 -0
  102. package/src/utils/output.ts +50 -0
  103. package/src/utils/paths.ts +72 -0
  104. package/tsconfig.json +14 -0
@@ -0,0 +1,43 @@
1
+ /*
2
+ * Copyright (C) 2024 RedNaga. https://rednaga.io
3
+ * All rights reserved. Contact: rednaga@protonmail.com
4
+ *
5
+ *
6
+ * This file is part of APKiD
7
+ *
8
+ *
9
+ * Commercial License Usage
10
+ * ------------------------
11
+ * Licensees holding valid commercial APKiD licenses may use this file
12
+ * in accordance with the commercial license agreement provided with the
13
+ * Software or, alternatively, in accordance with the terms contained in
14
+ * a written agreement between you and RedNaga.
15
+ *
16
+ *
17
+ * GNU General Public License Usage
18
+ * --------------------------------
19
+ * Alternatively, this file may be used under the terms of the GNU General
20
+ * Public License version 3.0 as published by the Free Software Foundation
21
+ * and appearing in the file LICENSE.GPL included in the packaging of this
22
+ * file. Please visit http://www.gnu.org/copyleft/gpl.html and review the
23
+ * information to ensure the GNU General Public License version 3.0
24
+ * requirements will be met.
25
+ *
26
+ **/
27
+
28
+ rule is_res : file_type
29
+ {
30
+ meta:
31
+ description = "RES"
32
+
33
+ strings:
34
+ // Common patterns in resources.arsc (package ID, resource type,..)
35
+ $magic = { 02 00 0C 00 }
36
+ $type1 = { 01 00 1C 00 }
37
+ $type2 = { 03 00 00 00 }
38
+ $type3 = { 00 02 00 00 }
39
+
40
+ condition:
41
+ $magic at 0 and 1 of ($type*)
42
+ }
43
+
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Copyright (C) 2024 RedNaga. https://rednaga.io
3
+ * All rights reserved. Contact: rednaga@protonmail.com
4
+ *
5
+ *
6
+ * This file is part of APKiD
7
+ *
8
+ *
9
+ * Commercial License Usage
10
+ * ------------------------
11
+ * Licensees holding valid commercial APKiD licenses may use this file
12
+ * in accordance with the commercial license agreement provided with the
13
+ * Software or, alternatively, in accordance with the terms contained in
14
+ * a written agreement between you and RedNaga.
15
+ *
16
+ *
17
+ * GNU General Public License Usage
18
+ * --------------------------------
19
+ * Alternatively, this file may be used under the terms of the GNU General
20
+ * Public License version 3.0 as published by the Free Software Foundation
21
+ * and appearing in the file LICENSE.GPL included in the packaging of this
22
+ * file. Please visit http://www.gnu.org/copyleft/gpl.html and review the
23
+ * information to ensure the GNU General Public License version 3.0
24
+ * requirements will be met.
25
+ *
26
+ **/
27
+
28
+ include "common.yara"
29
+
30
+ rule mtprotector_res : obfuscator
31
+ {
32
+ meta:
33
+ description = "MT Protector"
34
+ url = "https://mt2.cn/download/"
35
+ sample = "462475fb14ef7b979d1102a61d334cffcdcfc24183be37af868d1dc681bc7126"
36
+ author = "Eduardo Novella"
37
+
38
+ strings:
39
+ $sign = {
40
+ 0000 0c0c // extra bytes
41
+ 4d54 5f50 726f 7465 6374 6f72 00 // ..MT_Protector.
42
+ }
43
+
44
+ condition:
45
+ is_res and all of them
46
+ }
@@ -0,0 +1,46 @@
1
+ /*
2
+ * Copyright (C) 2024 RedNaga. https://rednaga.io
3
+ * All rights reserved. Contact: rednaga@protonmail.com
4
+ *
5
+ *
6
+ * This file is part of APKiD
7
+ *
8
+ *
9
+ * Commercial License Usage
10
+ * ------------------------
11
+ * Licensees holding valid commercial APKiD licenses may use this file
12
+ * in accordance with the commercial license agreement provided with the
13
+ * Software or, alternatively, in accordance with the terms contained in
14
+ * a written agreement between you and RedNaga.
15
+ *
16
+ *
17
+ * GNU General Public License Usage
18
+ * --------------------------------
19
+ * Alternatively, this file may be used under the terms of the GNU General
20
+ * Public License version 3.0 as published by the Free Software Foundation
21
+ * and appearing in the file LICENSE.GPL included in the packaging of this
22
+ * file. Please visit http://www.gnu.org/copyleft/gpl.html and review the
23
+ * information to ensure the GNU General Public License version 3.0
24
+ * requirements will be met.
25
+ *
26
+ **/
27
+
28
+ include "common.yara"
29
+
30
+ rule bugsmirror : protector
31
+ {
32
+ meta:
33
+ description = "BugsMirror"
34
+ url = "https://www.bugsmirror.com/"
35
+ sample = "c9bbf66ac86bf02663b7bc28a735881d4aeaa8d90e9b8b752e9cf337a26f0bdd"
36
+ author = "Abhi"
37
+
38
+ strings:
39
+ $comment = { 00 ?? ?? 53 65 63 75 72 65 64 20 62 79 20
40
+ 42 75 67 73 6D 69 72 72 6F 72 00 } // Secured by Bugsmirror
41
+ $comment2 = { ?? 73 65 63 75 72 65 64 5F 62 79 5F 62 75
42
+ 67 73 6D 69 72 72 6F 72 00 } // secured_by_bugsmirror
43
+
44
+ condition:
45
+ is_res and any of them
46
+ }
package/apkid/rules.py ADDED
@@ -0,0 +1,77 @@
1
+ """
2
+ Copyright (C) 2023 RedNaga. https://rednaga.io
3
+ All rights reserved. Contact: rednaga@protonmail.com
4
+
5
+
6
+ This file is part of APKiD
7
+
8
+
9
+ Commercial License Usage
10
+ ------------------------
11
+ Licensees holding valid commercial APKiD licenses may use this file
12
+ in accordance with the commercial license agreement provided with the
13
+ Software or, alternatively, in accordance with the terms contained in
14
+ a written agreement between you and RedNaga.
15
+
16
+
17
+ GNU General Public License Usage
18
+ --------------------------------
19
+ Alternatively, this file may be used under the terms of the GNU General
20
+ Public License version 3.0 as published by the Free Software Foundation
21
+ and appearing in the file LICENSE.GPL included in the packaging of this
22
+ file. Please visit http://www.gnu.org/copyleft/gpl.html and review the
23
+ information to ensure the GNU General Public License version 3.0
24
+ requirements will be met.
25
+ """
26
+
27
+ import hashlib
28
+ import os
29
+ from typing import Dict
30
+ from typing import Optional
31
+
32
+ import yara
33
+
34
+
35
+ class RulesManager(object):
36
+ def __init__(self, rules_dir=None, rules_ext='.yara'):
37
+ if not rules_dir:
38
+ rules_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'rules')
39
+ self.rules_dir: str = rules_dir
40
+ self.rules_path: str = os.path.join(self.rules_dir, 'rules.yarc')
41
+ self.rules_ext: str = rules_ext
42
+ self.rules: Optional[yara.Rules] = None
43
+ self.rules_hash: Optional[str] = None
44
+
45
+ def load(self) -> yara.Rules:
46
+ self.rules = yara.load(self.rules_path)
47
+ return self.rules
48
+
49
+ def _collect_yara_files(self) -> Dict[str, str]:
50
+ files = {}
51
+ for root, dirnames, filenames in os.walk(self.rules_dir):
52
+ for filename in filenames:
53
+ if not filename.lower().endswith(self.rules_ext):
54
+ continue
55
+ path = os.path.join(root, filename)
56
+ files[path] = path
57
+ return files
58
+
59
+ def compile(self) -> yara.Rules:
60
+ yara_files = self._collect_yara_files()
61
+ self.rules = yara.compile(filepaths=yara_files)
62
+ return self.rules
63
+
64
+ def save(self) -> int:
65
+ self.rules.save(self.rules_path)
66
+ rules_count = len(set([r.identifier for r in self.rules]))
67
+ return rules_count
68
+
69
+ @property
70
+ def hash(self) -> str:
71
+ if not self.rules_hash:
72
+ h = hashlib.sha256()
73
+ for file_path in self._collect_yara_files():
74
+ with open(file_path, 'rb') as f:
75
+ h.update(f.read())
76
+ self.rules_hash = h.hexdigest()
77
+ return self.rules_hash
package/bin/anais ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../dist/cli.js');
package/dist/cli.js ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const index_1 = require("./index");
14
+ const utils_1 = require("./utils");
15
+ const main = () => __awaiter(void 0, void 0, void 0, function* () {
16
+ const args = process.argv.slice(2);
17
+ if (args.length === 0) {
18
+ (0, utils_1.printBanner)();
19
+ console.log("Usage:");
20
+ console.log(" anais <apk-file-path> Analyze an APK file");
21
+ console.log(" anais --version Show version");
22
+ console.log(" anais --help Show this help message");
23
+ process.exit(0);
24
+ }
25
+ if (args[0] === "--version" || args[0] === "-v") {
26
+ console.log("Anais APK Forensic CLI v1.0.0");
27
+ process.exit(0);
28
+ }
29
+ if (args[0] === "--help" || args[0] === "-h") {
30
+ (0, utils_1.printBanner)();
31
+ console.log("Usage:");
32
+ console.log(" anais <apk-file-path> Analyze an APK file");
33
+ console.log(" anais --version Show version");
34
+ console.log(" anais --help Show this help message");
35
+ console.log("\nDescription:");
36
+ console.log(" Comprehensive APK security analysis and SAST scanner");
37
+ console.log(" - Decompilation with APKTool and JADX");
38
+ console.log(" - YARA malware detection");
39
+ console.log(" - Obfuscation detection");
40
+ console.log(" - Network traffic analysis");
41
+ console.log(" - AndroidManifest analysis");
42
+ console.log(" - Entropy analysis for encrypted payloads");
43
+ process.exit(0);
44
+ }
45
+ const apkPath = args[0];
46
+ try {
47
+ console.log(`🔍 Anais APK Forensic Analysis\n`);
48
+ (0, utils_1.printSeparator)();
49
+ console.log();
50
+ const result = yield (0, index_1.executeForensicAnalysis)(apkPath);
51
+ console.log();
52
+ (0, utils_1.printSeparator)();
53
+ if (result.success) {
54
+ console.log(`\n${(0, utils_1.formatSuccess)("Analysis completed successfully!")}\n`);
55
+ if (result.workspaceDir) {
56
+ console.log(`📁 Workspace: ${result.workspaceDir}`);
57
+ }
58
+ if (result.reportPath) {
59
+ console.log(`📄 Report: ${result.reportPath}`);
60
+ }
61
+ if (result.jsonReportPath) {
62
+ console.log(`📊 JSON Report: ${result.jsonReportPath}`);
63
+ }
64
+ console.log("\n💡 Tip: Open the report with your preferred markdown viewer");
65
+ console.log(` e.g., cat "${result.reportPath}"\n`);
66
+ }
67
+ else {
68
+ console.log(`\n${(0, utils_1.formatError)("Analysis failed!")}\n`);
69
+ console.log(`Error: ${result.message}`);
70
+ if (result.error) {
71
+ console.log(`Details: ${result.error}`);
72
+ }
73
+ process.exit(1);
74
+ }
75
+ }
76
+ catch (error) {
77
+ console.error(`\n${(0, utils_1.formatError)("Unexpected error during analysis:")}`);
78
+ console.error(error);
79
+ process.exit(1);
80
+ }
81
+ });
82
+ main();
package/dist/index.js ADDED
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18
+ return new (P || (P = Promise))(function (resolve, reject) {
19
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
23
+ });
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.executeForensicAnalysis = void 0;
27
+ const child_process_1 = require("child_process");
28
+ const utils_1 = require("./utils");
29
+ __exportStar(require("./types"), exports);
30
+ const executeForensicAnalysis = (apkPath) => __awaiter(void 0, void 0, void 0, function* () {
31
+ return new Promise((resolve, reject) => {
32
+ // Resolve absolute path
33
+ const absoluteApkPath = (0, utils_1.resolveAbsolutePath)(apkPath);
34
+ // Check if APK file exists
35
+ if (!(0, utils_1.fileExists)(absoluteApkPath)) {
36
+ return resolve({
37
+ success: false,
38
+ apkPath,
39
+ message: `APK file not found: ${apkPath}`,
40
+ error: "File not found",
41
+ });
42
+ }
43
+ console.log(`\n📱 APK: ${(0, utils_1.getBasename)(absoluteApkPath)}`);
44
+ console.log(`📂 Path: ${absoluteApkPath}\n`);
45
+ // Get paths
46
+ const scriptDir = (0, utils_1.getProjectRoot)();
47
+ const anaisScript = (0, utils_1.getAnaisScriptPath)();
48
+ if (!(0, utils_1.fileExists)(anaisScript)) {
49
+ return resolve({
50
+ success: false,
51
+ apkPath,
52
+ message: `Analysis script not found: ${anaisScript}`,
53
+ error: "Script not found",
54
+ });
55
+ }
56
+ console.log(`🚀 Executing analysis...\n`);
57
+ // Spawn the bash script
58
+ const analysis = (0, child_process_1.spawn)("bash", [anaisScript, absoluteApkPath], {
59
+ cwd: scriptDir,
60
+ env: Object.assign(Object.assign({}, process.env), { PYTHONWARNINGS: "ignore" }),
61
+ });
62
+ let stdout = "";
63
+ let stderr = "";
64
+ let workspaceDir = "";
65
+ let reportPath = "";
66
+ // Capture stdout
67
+ analysis.stdout.on("data", (data) => {
68
+ const output = data.toString();
69
+ process.stdout.write(output);
70
+ stdout += output;
71
+ // Extract workspace directory from output
72
+ const workspaceMatch = output.match(/Workspace initialized: (.+)/);
73
+ if (workspaceMatch) {
74
+ workspaceDir = workspaceMatch[1].trim();
75
+ }
76
+ // Extract report path
77
+ const reportMatch = output.match(/Main report: (.+\.md)/);
78
+ if (reportMatch) {
79
+ reportPath = reportMatch[1].trim();
80
+ }
81
+ });
82
+ // Capture stderr (though we're logging warnings there)
83
+ analysis.stderr.on("data", (data) => {
84
+ stderr += data.toString();
85
+ // Don't print stderr to console as it's handled by the script
86
+ });
87
+ // Handle process completion
88
+ analysis.on("close", (code) => {
89
+ if (code === 0) {
90
+ const jsonReportPath = reportPath.replace(/\.md$/, ".json");
91
+ resolve({
92
+ success: true,
93
+ apkPath: absoluteApkPath,
94
+ workspaceDir,
95
+ reportPath,
96
+ jsonReportPath: (0, utils_1.fileExists)(jsonReportPath)
97
+ ? jsonReportPath
98
+ : undefined,
99
+ message: "Analysis completed successfully",
100
+ });
101
+ }
102
+ else {
103
+ resolve({
104
+ success: false,
105
+ apkPath: absoluteApkPath,
106
+ workspaceDir,
107
+ message: `Analysis failed with exit code ${code}`,
108
+ error: stderr || "Unknown error",
109
+ });
110
+ }
111
+ });
112
+ // Handle errors
113
+ analysis.on("error", (error) => {
114
+ reject({
115
+ success: false,
116
+ apkPath: absoluteApkPath,
117
+ message: "Failed to execute analysis script",
118
+ error: error.message,
119
+ });
120
+ });
121
+ });
122
+ });
123
+ exports.executeForensicAnalysis = executeForensicAnalysis;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Utility functions export
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ __exportStar(require("./output"), exports);
21
+ __exportStar(require("./paths"), exports);
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * Output formatting utilities
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.colors = void 0;
7
+ exports.formatSuccess = formatSuccess;
8
+ exports.formatError = formatError;
9
+ exports.formatInfo = formatInfo;
10
+ exports.formatWarning = formatWarning;
11
+ exports.printSeparator = printSeparator;
12
+ exports.printBanner = printBanner;
13
+ exports.colors = {
14
+ reset: "\x1b[0m",
15
+ bright: "\x1b[1m",
16
+ dim: "\x1b[2m",
17
+ red: "\x1b[31m",
18
+ green: "\x1b[32m",
19
+ yellow: "\x1b[33m",
20
+ blue: "\x1b[34m",
21
+ magenta: "\x1b[35m",
22
+ cyan: "\x1b[36m",
23
+ };
24
+ function formatSuccess(message) {
25
+ return `${exports.colors.green}✅ ${message}${exports.colors.reset}`;
26
+ }
27
+ function formatError(message) {
28
+ return `${exports.colors.red}❌ ${message}${exports.colors.reset}`;
29
+ }
30
+ function formatInfo(message) {
31
+ return `${exports.colors.blue}ℹ ${message}${exports.colors.reset}`;
32
+ }
33
+ function formatWarning(message) {
34
+ return `${exports.colors.yellow}⚠ ${message}${exports.colors.reset}`;
35
+ }
36
+ function printSeparator(length = 50) {
37
+ console.log("═".repeat(length));
38
+ }
39
+ function printBanner() {
40
+ console.log(`\n${exports.colors.cyan}╔═══════════════════════════════════════════════════════════╗${exports.colors.reset}`);
41
+ console.log(`${exports.colors.cyan}║ Anais APK Forensic Automation - CLI v1.0.0 ║${exports.colors.reset}`);
42
+ console.log(`${exports.colors.cyan}║ Comprehensive APK Security Analysis & SAST ║${exports.colors.reset}`);
43
+ console.log(`${exports.colors.cyan}╚═══════════════════════════════════════════════════════════╝${exports.colors.reset}\n`);
44
+ }
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getUserDocumentsPath = getUserDocumentsPath;
37
+ exports.getDefaultWorkspacePath = getDefaultWorkspacePath;
38
+ exports.ensureWorkspaceExists = ensureWorkspaceExists;
39
+ exports.getProjectRoot = getProjectRoot;
40
+ exports.getAnaisScriptPath = getAnaisScriptPath;
41
+ exports.fileExists = fileExists;
42
+ exports.resolveAbsolutePath = resolveAbsolutePath;
43
+ exports.getBasename = getBasename;
44
+ const fs = __importStar(require("fs"));
45
+ const os = __importStar(require("os"));
46
+ const path = __importStar(require("path"));
47
+ /**
48
+ * Get the user's Documents folder path
49
+ */
50
+ function getUserDocumentsPath() {
51
+ const homeDir = os.homedir();
52
+ return path.join(homeDir, "Documents");
53
+ }
54
+ /**
55
+ * Get the default analysis workspace path (Documents/Anais-Reports)
56
+ */
57
+ function getDefaultWorkspacePath() {
58
+ return path.join(getUserDocumentsPath(), "Anais-Reports");
59
+ }
60
+ /**
61
+ * Ensure the analysis workspace directory exists
62
+ */
63
+ function ensureWorkspaceExists() {
64
+ const workspacePath = getDefaultWorkspacePath();
65
+ if (!fs.existsSync(workspacePath)) {
66
+ fs.mkdirSync(workspacePath, { recursive: true });
67
+ }
68
+ }
69
+ /**
70
+ * Get the project root directory (where package is installed)
71
+ * When installed via npm, __dirname will be in node_modules/anais-apk-forensic/dist/utils
72
+ * We need to go up to the package root
73
+ */
74
+ function getProjectRoot() {
75
+ // Check if we're in node_modules (installed via npm)
76
+ const currentDir = path.resolve(__dirname, "../..");
77
+ if (currentDir.includes("node_modules")) {
78
+ // Go up to node_modules/anais-apk-forensic/
79
+ return path.resolve(__dirname, "../..");
80
+ }
81
+ // Otherwise we're in development mode (dist/utils -> root)
82
+ return path.resolve(__dirname, "../..");
83
+ }
84
+ /**
85
+ * Get the path to anais.sh script
86
+ */
87
+ function getAnaisScriptPath() {
88
+ return path.join(getProjectRoot(), "anais.sh");
89
+ }
90
+ /**
91
+ * Check if a file exists
92
+ */
93
+ function fileExists(filePath) {
94
+ return fs.existsSync(filePath);
95
+ }
96
+ /**
97
+ * Resolve absolute path
98
+ */
99
+ function resolveAbsolutePath(filePath) {
100
+ return path.resolve(filePath);
101
+ }
102
+ /**
103
+ * Get basename of a file
104
+ */
105
+ function getBasename(filePath) {
106
+ return path.basename(filePath);
107
+ }