@guardbee/mcp-reverse-shield 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +117 -2
- package/TR.md +114 -0
- package/ZH.md +61 -0
- package/dist/__tests__/android.test.d.ts +2 -0
- package/dist/__tests__/android.test.d.ts.map +1 -0
- package/dist/__tests__/android.test.js +114 -0
- package/dist/__tests__/android.test.js.map +1 -0
- package/dist/__tests__/electron.test.d.ts +2 -0
- package/dist/__tests__/electron.test.d.ts.map +1 -0
- package/dist/__tests__/electron.test.js +128 -0
- package/dist/__tests__/electron.test.js.map +1 -0
- package/dist/__tests__/live.test.d.ts +2 -0
- package/dist/__tests__/live.test.d.ts.map +1 -0
- package/dist/__tests__/live.test.js +67 -0
- package/dist/__tests__/live.test.js.map +1 -0
- package/dist/__tests__/native.test.d.ts +2 -0
- package/dist/__tests__/native.test.d.ts.map +1 -0
- package/dist/__tests__/native.test.js +111 -0
- package/dist/__tests__/native.test.js.map +1 -0
- package/dist/__tests__/scanner.test.d.ts +2 -0
- package/dist/__tests__/scanner.test.d.ts.map +1 -0
- package/dist/__tests__/scanner.test.js +127 -0
- package/dist/__tests__/scanner.test.js.map +1 -0
- package/dist/__tests__/testFixtures.d.ts +61 -0
- package/dist/__tests__/testFixtures.d.ts.map +1 -0
- package/dist/__tests__/testFixtures.js +416 -0
- package/dist/__tests__/testFixtures.js.map +1 -0
- package/dist/__tests__/web.test.d.ts +2 -0
- package/dist/__tests__/web.test.d.ts.map +1 -0
- package/dist/__tests__/web.test.js +156 -0
- package/dist/__tests__/web.test.js.map +1 -0
- package/dist/apk.d.ts +9 -0
- package/dist/apk.d.ts.map +1 -0
- package/dist/apk.js +132 -0
- package/dist/apk.js.map +1 -0
- package/dist/asar.d.ts +10 -0
- package/dist/asar.d.ts.map +1 -0
- package/dist/asar.js +73 -0
- package/dist/asar.js.map +1 -0
- package/dist/axml.d.ts +20 -0
- package/dist/axml.d.ts.map +1 -0
- package/dist/axml.js +104 -0
- package/dist/axml.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +172 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +102 -0
- package/dist/config.js.map +1 -0
- package/dist/dex.d.ts +16 -0
- package/dist/dex.d.ts.map +1 -0
- package/dist/dex.js +63 -0
- package/dist/dex.js.map +1 -0
- package/dist/electron.d.ts +26 -0
- package/dist/electron.d.ts.map +1 -0
- package/dist/electron.js +146 -0
- package/dist/electron.js.map +1 -0
- package/dist/finding.d.ts +30 -0
- package/dist/finding.d.ts.map +1 -0
- package/dist/finding.js +38 -0
- package/dist/finding.js.map +1 -0
- package/dist/fsutil.d.ts +20 -0
- package/dist/fsutil.d.ts.map +1 -0
- package/dist/fsutil.js +80 -0
- package/dist/fsutil.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/live.d.ts +14 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +144 -0
- package/dist/live.js.map +1 -0
- package/dist/native.d.ts +18 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +411 -0
- package/dist/native.js.map +1 -0
- package/dist/rules.d.ts +22 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +354 -0
- package/dist/rules.js.map +1 -0
- package/dist/sarif.d.ts +3 -0
- package/dist/sarif.d.ts.map +1 -0
- package/dist/sarif.js +60 -0
- package/dist/sarif.js.map +1 -0
- package/dist/scanner.d.ts +27 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +169 -0
- package/dist/scanner.js.map +1 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +88 -0
- package/dist/server.js.map +1 -0
- package/dist/web.d.ts +56 -0
- package/dist/web.d.ts.map +1 -0
- package/dist/web.js +301 -0
- package/dist/web.js.map +1 -0
- package/dist/zip.d.ts +21 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +112 -0
- package/dist/zip.js.map +1 -0
- package/package.json +52 -3
package/dist/apk.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Finding } from "./finding.js";
|
|
2
|
+
export interface ApkResult {
|
|
3
|
+
findings: Finding[];
|
|
4
|
+
notes: string[];
|
|
5
|
+
scannedFiles: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function isApk(filePath: string): boolean;
|
|
8
|
+
export declare function analyzeApk(filePath: string): ApkResult | null;
|
|
9
|
+
//# sourceMappingURL=apk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apk.d.ts","sourceRoot":"","sources":["../src/apk.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAY5C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAiH7D"}
|
package/dist/apk.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { closeSync, openSync, statSync } from "fs";
|
|
2
|
+
import { attribute, parseAxml } from "./axml.js";
|
|
3
|
+
import { assessDexObfuscation, readTypeDescriptors } from "./dex.js";
|
|
4
|
+
import { finding } from "./finding.js";
|
|
5
|
+
import { readAt } from "./fsutil.js";
|
|
6
|
+
import { analyzeNative } from "./native.js";
|
|
7
|
+
import { analyzeWebFiles } from "./web.js";
|
|
8
|
+
import { extractZipEntry, locateCentralDirectory, readZipEntries } from "./zip.js";
|
|
9
|
+
const APK_SIG_BLOCK_MAGIC = "APK Sig Block 42";
|
|
10
|
+
const HERMES_MAGIC = Buffer.from([0xc6, 0x1f, 0xbc, 0x03, 0xc1, 0x03, 0x19, 0x1f]);
|
|
11
|
+
const MAX_ENTRY_BYTES = 64 * 1024 * 1024;
|
|
12
|
+
const MAX_NATIVE_LIBS = 40;
|
|
13
|
+
export function isApk(filePath) {
|
|
14
|
+
return /\.apk$/i.test(filePath);
|
|
15
|
+
}
|
|
16
|
+
export function analyzeApk(filePath) {
|
|
17
|
+
const size = statSync(filePath).size;
|
|
18
|
+
const fd = openSync(filePath, "r");
|
|
19
|
+
try {
|
|
20
|
+
const entries = readZipEntries(fd, size);
|
|
21
|
+
const manifestEntry = entries.find((e) => e.name === "AndroidManifest.xml");
|
|
22
|
+
if (!manifestEntry)
|
|
23
|
+
return null;
|
|
24
|
+
const read = (e) => (e.uncompressedSize > MAX_ENTRY_BYTES ? null : extractZipEntry(fd, e));
|
|
25
|
+
const at = (name) => `${filePath}!/${name}`;
|
|
26
|
+
const findings = [];
|
|
27
|
+
const notes = [];
|
|
28
|
+
let scannedFiles = 1;
|
|
29
|
+
// ── Manifest ──
|
|
30
|
+
const manifestBuf = read(manifestEntry);
|
|
31
|
+
const elements = manifestBuf ? parseAxml(manifestBuf) : null;
|
|
32
|
+
const manifest = elements?.find((e) => e.name === "manifest");
|
|
33
|
+
const application = elements?.find((e) => e.name === "application");
|
|
34
|
+
const packageName = String(manifest?.attributes.find((a) => a.name === "package")?.value ?? "");
|
|
35
|
+
if (!elements)
|
|
36
|
+
notes.push("AndroidManifest.xml is not binary XML (unpacked or re-encoded APK?)");
|
|
37
|
+
if (packageName)
|
|
38
|
+
notes.push(`package ${packageName}`);
|
|
39
|
+
if (attribute(application, "debuggable")?.value === true) {
|
|
40
|
+
findings.push(finding("apk_debuggable", at("AndroidManifest.xml"), { match: 'android:debuggable="true"' }));
|
|
41
|
+
}
|
|
42
|
+
if (attribute(application, "testOnly")?.value === true) {
|
|
43
|
+
findings.push(finding("apk_test_only", at("AndroidManifest.xml"), { match: 'android:testOnly="true"' }));
|
|
44
|
+
}
|
|
45
|
+
const allowBackup = attribute(application, "allowBackup");
|
|
46
|
+
if (application && allowBackup?.value !== false) {
|
|
47
|
+
findings.push(finding("apk_allow_backup", at("AndroidManifest.xml"), {
|
|
48
|
+
match: allowBackup ? 'android:allowBackup="true"' : "android:allowBackup not set (defaults to true)",
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
// ── Code: R8/ProGuard ──
|
|
52
|
+
const dexEntries = entries.filter((e) => /^classes\d*\.dex$/.test(e.name));
|
|
53
|
+
const descriptors = [];
|
|
54
|
+
for (const e of dexEntries) {
|
|
55
|
+
const buf = read(e);
|
|
56
|
+
if (buf)
|
|
57
|
+
descriptors.push(...readTypeDescriptors(buf));
|
|
58
|
+
}
|
|
59
|
+
scannedFiles += dexEntries.length;
|
|
60
|
+
if (descriptors.length > 0) {
|
|
61
|
+
// The application id can differ from the code namespace (e.g. a ".debug"
|
|
62
|
+
// suffix), so also try the packages of the classes the manifest names.
|
|
63
|
+
const componentClasses = (elements ?? [])
|
|
64
|
+
.flatMap((el) => el.attributes.filter((a) => a.name === "name" && typeof a.value === "string").map((a) => String(a.value)))
|
|
65
|
+
.map((n) => (n.startsWith(".") ? packageName + n : n))
|
|
66
|
+
.filter((n) => n.includes("."));
|
|
67
|
+
const candidates = new Set([packageName, ...componentClasses.map((n) => n.slice(0, n.lastIndexOf(".")))].filter(Boolean));
|
|
68
|
+
const verdict = [...candidates]
|
|
69
|
+
.map((pkg) => ({ pkg, ...assessDexObfuscation(descriptors, pkg) }))
|
|
70
|
+
.sort((a, b) => b.appClasses - a.appClasses)[0];
|
|
71
|
+
if (verdict) {
|
|
72
|
+
notes.push(`${verdict.pkg}: ${verdict.appClasses} app classes in ${dexEntries.length} dex file(s), ${verdict.shortNamed} with 1–2 letter names`);
|
|
73
|
+
if (!verdict.obfuscated) {
|
|
74
|
+
findings.push(finding("apk_no_obfuscation", at(dexEntries[0].name), {
|
|
75
|
+
match: `${verdict.appClasses} classes under ${verdict.pkg}, ${verdict.shortNamed} renamed; e.g. ${verdict.sample.join(", ")}`,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// ── React Native / web assets ──
|
|
81
|
+
const jsBundle = entries.find((e) => e.name === "assets/index.android.bundle");
|
|
82
|
+
if (jsBundle) {
|
|
83
|
+
const buf = read(jsBundle);
|
|
84
|
+
if (buf && buf.subarray(0, 8).equals(HERMES_MAGIC)) {
|
|
85
|
+
notes.push("React Native bundle is Hermes bytecode");
|
|
86
|
+
}
|
|
87
|
+
else if (buf) {
|
|
88
|
+
findings.push(finding("apk_js_bundle_plaintext", at(jsBundle.name), { match: `${(buf.length / 1024).toFixed(0)} KiB of JavaScript` }));
|
|
89
|
+
findings.push(...analyzeWebFiles([{ key: "index.android.bundle.js", display: at(jsBundle.name), size: buf.length, read: () => buf }]));
|
|
90
|
+
scannedFiles++;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const webAssets = entries.filter((e) => /^assets\/.*\.(?:m?js|map)$/i.test(e.name) && !e.name.includes("node_modules"));
|
|
94
|
+
if (webAssets.length > 0) {
|
|
95
|
+
scannedFiles += webAssets.length;
|
|
96
|
+
findings.push(...analyzeWebFiles(webAssets.map((e) => ({ key: e.name, display: at(e.name), size: e.uncompressedSize, read: () => read(e) }))));
|
|
97
|
+
}
|
|
98
|
+
// ── Native libraries ──
|
|
99
|
+
const libs = entries.filter((e) => /^lib\/[^/]+\/[^/]+\.so$/.test(e.name)).slice(0, MAX_NATIVE_LIBS);
|
|
100
|
+
const seen = new Set();
|
|
101
|
+
for (const e of libs) {
|
|
102
|
+
const buf = read(e);
|
|
103
|
+
const result = buf ? analyzeNative(buf, at(e.name)) : null;
|
|
104
|
+
scannedFiles++;
|
|
105
|
+
for (const f of result?.findings ?? []) {
|
|
106
|
+
// Same library for several ABIs: report each issue once per library name.
|
|
107
|
+
const key = `${f.patternId}:${e.name.split("/").pop()}`;
|
|
108
|
+
if (f.patternId !== "native_debug_info" && f.patternId !== "native_symbols_not_stripped")
|
|
109
|
+
continue;
|
|
110
|
+
if (!seen.has(key)) {
|
|
111
|
+
seen.add(key);
|
|
112
|
+
findings.push(f);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// ── Signing ──
|
|
117
|
+
const located = locateCentralDirectory(fd, size);
|
|
118
|
+
const hasSigBlock = located !== null && located.cdOffset >= 16 && readAt(fd, located.cdOffset - 16, 16).toString("latin1") === APK_SIG_BLOCK_MAGIC;
|
|
119
|
+
const hasV1 = entries.some((e) => /^META-INF\/[^/]+\.(?:RSA|DSA|EC)$/i.test(e.name));
|
|
120
|
+
if (!hasSigBlock && !hasV1)
|
|
121
|
+
findings.push(finding("apk_unsigned", filePath, { match: "no APK Signing Block and no META-INF signature" }));
|
|
122
|
+
else if (!hasSigBlock)
|
|
123
|
+
findings.push(finding("apk_v1_only_signature", filePath, { match: "META-INF signature only, no APK Signing Block (v2+)" }));
|
|
124
|
+
else
|
|
125
|
+
notes.push(`signed with APK Signature Scheme v2+${hasV1 ? " and v1" : ""}`);
|
|
126
|
+
return { findings, notes, scannedFiles };
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
closeSync(fd);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=apk.js.map
|
package/dist/apk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apk.js","sourceRoot":"","sources":["../src/apk.ts"],"names":[],"mappings":"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"}
|
package/dist/asar.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ArtifactFile } from "./web.js";
|
|
2
|
+
/**
|
|
3
|
+
* Lists an ASAR archive's files. Layout: a Chromium Pickle holding the header
|
|
4
|
+
* size (u32 4, u32 headerPickleSize), then a Pickle holding the JSON index
|
|
5
|
+
* (u32 payloadSize, u32 jsonLength, json). File data starts right after the
|
|
6
|
+
* header pickle; each entry's offset is relative to that. Entries marked
|
|
7
|
+
* `unpacked` live in `<archive>.unpacked/` instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readAsar(archivePath: string): ArtifactFile[] | null;
|
|
10
|
+
//# sourceMappingURL=asar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asar.d.ts","sourceRoot":"","sources":["../src/asar.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAY7C;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,IAAI,CAwDnE"}
|
package/dist/asar.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { closeSync, existsSync, openSync, readFileSync, statSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { readAt } from "./fsutil.js";
|
|
4
|
+
const MAX_HEADER_BYTES = 64 * 1024 * 1024;
|
|
5
|
+
/**
|
|
6
|
+
* Lists an ASAR archive's files. Layout: a Chromium Pickle holding the header
|
|
7
|
+
* size (u32 4, u32 headerPickleSize), then a Pickle holding the JSON index
|
|
8
|
+
* (u32 payloadSize, u32 jsonLength, json). File data starts right after the
|
|
9
|
+
* header pickle; each entry's offset is relative to that. Entries marked
|
|
10
|
+
* `unpacked` live in `<archive>.unpacked/` instead.
|
|
11
|
+
*/
|
|
12
|
+
export function readAsar(archivePath) {
|
|
13
|
+
const fileSize = statSync(archivePath).size;
|
|
14
|
+
if (fileSize < 16)
|
|
15
|
+
return null;
|
|
16
|
+
const fd = openSync(archivePath, "r");
|
|
17
|
+
let header;
|
|
18
|
+
let dataStart;
|
|
19
|
+
try {
|
|
20
|
+
const prefix = readAt(fd, 0, 16);
|
|
21
|
+
const headerPickleSize = prefix.readUInt32LE(4);
|
|
22
|
+
const jsonLength = prefix.readUInt32LE(12);
|
|
23
|
+
if (prefix.readUInt32LE(0) !== 4 || jsonLength > MAX_HEADER_BYTES || 16 + jsonLength > fileSize)
|
|
24
|
+
return null;
|
|
25
|
+
header = JSON.parse(readAt(fd, 16, jsonLength).toString("utf8"));
|
|
26
|
+
dataStart = 8 + headerPickleSize;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
closeSync(fd);
|
|
33
|
+
}
|
|
34
|
+
const files = [];
|
|
35
|
+
const unpackedRoot = `${archivePath}.unpacked`;
|
|
36
|
+
const visit = (node, prefix) => {
|
|
37
|
+
for (const [name, child] of Object.entries(node.files ?? {})) {
|
|
38
|
+
const key = prefix ? `${prefix}/${name}` : name;
|
|
39
|
+
if (child.files) {
|
|
40
|
+
visit(child, key);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (child.link !== undefined || typeof child.size !== "number")
|
|
44
|
+
continue;
|
|
45
|
+
const size = child.size;
|
|
46
|
+
const display = `${archivePath}!/${key}`;
|
|
47
|
+
if (child.unpacked) {
|
|
48
|
+
const onDisk = join(unpackedRoot, ...key.split("/"));
|
|
49
|
+
files.push({ key, display, size, read: () => (existsSync(onDisk) ? readFileSync(onDisk) : null) });
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const offset = dataStart + Number(child.offset ?? 0);
|
|
53
|
+
files.push({
|
|
54
|
+
key,
|
|
55
|
+
display,
|
|
56
|
+
size,
|
|
57
|
+
read: () => {
|
|
58
|
+
const rfd = openSync(archivePath, "r");
|
|
59
|
+
try {
|
|
60
|
+
return readAt(rfd, offset, size);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
closeSync(rfd);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
visit(header, "");
|
|
71
|
+
return files;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=asar.js.map
|
package/dist/asar.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asar.js","sourceRoot":"","sources":["../src/asar.ts"],"names":[],"mappings":"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"}
|
package/dist/axml.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface AxmlAttribute {
|
|
2
|
+
name: string;
|
|
3
|
+
resourceId: number | null;
|
|
4
|
+
/** Booleans as true/false, strings as text, anything else as the raw 32-bit value. */
|
|
5
|
+
value: boolean | string | number;
|
|
6
|
+
}
|
|
7
|
+
export interface AxmlElement {
|
|
8
|
+
name: string;
|
|
9
|
+
attributes: AxmlAttribute[];
|
|
10
|
+
}
|
|
11
|
+
/** Returns the elements in document order, or null when the buffer is not AXML. */
|
|
12
|
+
export declare function parseAxml(buf: Buffer): AxmlElement[] | null;
|
|
13
|
+
/** android.R.attr ids, which are stable across platform versions. */
|
|
14
|
+
export declare const ATTR: {
|
|
15
|
+
readonly debuggable: 16842767;
|
|
16
|
+
readonly allowBackup: 16843392;
|
|
17
|
+
readonly testOnly: 16843378;
|
|
18
|
+
};
|
|
19
|
+
export declare function attribute(element: AxmlElement | undefined, name: keyof typeof ATTR): AxmlAttribute | undefined;
|
|
20
|
+
//# sourceMappingURL=axml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axml.d.ts","sourceRoot":"","sources":["../src/axml.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,sFAAsF;IACtF,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAqCD,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,GAAG,IAAI,CAyC3D;AAED,qEAAqE;AACrE,eAAO,MAAM,IAAI;;;;CAIP,CAAC;AAEX,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,OAAO,IAAI,GAAG,aAAa,GAAG,SAAS,CAE9G"}
|
package/dist/axml.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Android's compiled XML (AXML), as found in an APK's AndroidManifest.xml:
|
|
2
|
+
// a RES_XML chunk holding a string pool, a resource-id map for attribute
|
|
3
|
+
// names, then start/end element chunks whose attributes carry typed values.
|
|
4
|
+
const RES_STRING_POOL_TYPE = 0x0001;
|
|
5
|
+
const RES_XML_TYPE = 0x0003;
|
|
6
|
+
const RES_XML_RESOURCE_MAP_TYPE = 0x0180;
|
|
7
|
+
const RES_XML_START_ELEMENT_TYPE = 0x0102;
|
|
8
|
+
const UTF8_FLAG = 0x100;
|
|
9
|
+
const TYPE_STRING = 0x03;
|
|
10
|
+
const TYPE_INT_BOOLEAN = 0x12;
|
|
11
|
+
function readStringPool(buf, start) {
|
|
12
|
+
const headerSize = buf.readUInt16LE(start + 2);
|
|
13
|
+
const count = buf.readUInt32LE(start + 8);
|
|
14
|
+
const flags = buf.readUInt32LE(start + 16);
|
|
15
|
+
const stringsStart = start + buf.readUInt32LE(start + 20);
|
|
16
|
+
const utf8 = (flags & UTF8_FLAG) !== 0;
|
|
17
|
+
const strings = [];
|
|
18
|
+
for (let i = 0; i < count; i++) {
|
|
19
|
+
let p = stringsStart + buf.readUInt32LE(start + headerSize + i * 4);
|
|
20
|
+
if (utf8) {
|
|
21
|
+
// char count, then byte count; each is 1 byte, or 2 when the high bit is set
|
|
22
|
+
p += buf[p] & 0x80 ? 2 : 1;
|
|
23
|
+
let len = buf[p];
|
|
24
|
+
if (len & 0x80) {
|
|
25
|
+
len = ((len & 0x7f) << 8) | buf[p + 1];
|
|
26
|
+
p += 2;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
p += 1;
|
|
30
|
+
}
|
|
31
|
+
strings.push(buf.toString("utf8", p, p + len));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
let len = buf.readUInt16LE(p);
|
|
35
|
+
if (len & 0x8000) {
|
|
36
|
+
len = ((len & 0x7fff) << 16) | buf.readUInt16LE(p + 2);
|
|
37
|
+
p += 4;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
p += 2;
|
|
41
|
+
}
|
|
42
|
+
strings.push(buf.toString("utf16le", p, p + len * 2));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return strings;
|
|
46
|
+
}
|
|
47
|
+
/** Returns the elements in document order, or null when the buffer is not AXML. */
|
|
48
|
+
export function parseAxml(buf) {
|
|
49
|
+
if (buf.length < 8 || buf.readUInt16LE(0) !== RES_XML_TYPE)
|
|
50
|
+
return null;
|
|
51
|
+
const elements = [];
|
|
52
|
+
let strings = [];
|
|
53
|
+
let resourceIds = [];
|
|
54
|
+
let p = buf.readUInt16LE(2);
|
|
55
|
+
while (p + 8 <= buf.length) {
|
|
56
|
+
const type = buf.readUInt16LE(p);
|
|
57
|
+
const headerSize = buf.readUInt16LE(p + 2);
|
|
58
|
+
const size = buf.readUInt32LE(p + 4);
|
|
59
|
+
if (size < 8 || p + size > buf.length)
|
|
60
|
+
break;
|
|
61
|
+
if (type === RES_STRING_POOL_TYPE) {
|
|
62
|
+
strings = readStringPool(buf, p);
|
|
63
|
+
}
|
|
64
|
+
else if (type === RES_XML_RESOURCE_MAP_TYPE) {
|
|
65
|
+
resourceIds = [];
|
|
66
|
+
for (let o = p + headerSize; o + 4 <= p + size; o += 4)
|
|
67
|
+
resourceIds.push(buf.readUInt32LE(o));
|
|
68
|
+
}
|
|
69
|
+
else if (type === RES_XML_START_ELEMENT_TYPE) {
|
|
70
|
+
const ext = p + headerSize;
|
|
71
|
+
const name = strings[buf.readUInt32LE(ext + 4)] ?? "";
|
|
72
|
+
const attrStart = buf.readUInt16LE(ext + 8);
|
|
73
|
+
const attrSize = buf.readUInt16LE(ext + 10);
|
|
74
|
+
const attrCount = buf.readUInt16LE(ext + 12);
|
|
75
|
+
const attributes = [];
|
|
76
|
+
for (let i = 0; i < attrCount; i++) {
|
|
77
|
+
const a = ext + attrStart + i * attrSize;
|
|
78
|
+
const nameIdx = buf.readUInt32LE(a + 4);
|
|
79
|
+
const rawValue = buf.readUInt32LE(a + 8);
|
|
80
|
+
const dataType = buf[a + 15];
|
|
81
|
+
const data = buf.readUInt32LE(a + 16);
|
|
82
|
+
let value = data;
|
|
83
|
+
if (dataType === TYPE_INT_BOOLEAN)
|
|
84
|
+
value = data !== 0;
|
|
85
|
+
else if (dataType === TYPE_STRING)
|
|
86
|
+
value = strings[rawValue !== 0xffffffff ? rawValue : data] ?? "";
|
|
87
|
+
attributes.push({ name: strings[nameIdx] ?? "", resourceId: resourceIds[nameIdx] ?? null, value });
|
|
88
|
+
}
|
|
89
|
+
elements.push({ name, attributes });
|
|
90
|
+
}
|
|
91
|
+
p += size;
|
|
92
|
+
}
|
|
93
|
+
return elements;
|
|
94
|
+
}
|
|
95
|
+
/** android.R.attr ids, which are stable across platform versions. */
|
|
96
|
+
export const ATTR = {
|
|
97
|
+
debuggable: 0x0101000f,
|
|
98
|
+
allowBackup: 0x01010280,
|
|
99
|
+
testOnly: 0x01010272,
|
|
100
|
+
};
|
|
101
|
+
export function attribute(element, name) {
|
|
102
|
+
return element?.attributes.find((a) => a.resourceId === ATTR[name] || (a.resourceId === null && a.name === name));
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=axml.js.map
|
package/dist/axml.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axml.js","sourceRoot":"","sources":["../src/axml.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { dirname, resolve } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { configFilePath, loadConfig } from "./config.js";
|
|
6
|
+
import { scanUrl } from "./live.js";
|
|
7
|
+
import { buildSarif } from "./sarif.js";
|
|
8
|
+
import { scanPath } from "./scanner.js";
|
|
9
|
+
import { startServer } from "./server.js";
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
function getVersion() {
|
|
12
|
+
try {
|
|
13
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"));
|
|
14
|
+
return pkg.version;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return "0.0.0";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const SEV_ICON = {
|
|
21
|
+
critical: "🔴",
|
|
22
|
+
high: "🟠",
|
|
23
|
+
medium: "🟡",
|
|
24
|
+
low: "🔵",
|
|
25
|
+
};
|
|
26
|
+
function printText(result) {
|
|
27
|
+
const kinds = result.kinds.length > 0 ? result.kinds.join(", ") : "nothing recognised";
|
|
28
|
+
if (result.findings.length === 0) {
|
|
29
|
+
console.log(`✅ Grade ${result.grade} — no reverse-engineering exposure found in ${result.scannedFiles} file(s) (${kinds}, ${result.durationMs}ms)`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const counts = {};
|
|
33
|
+
for (const f of result.findings)
|
|
34
|
+
counts[f.severity] = (counts[f.severity] ?? 0) + 1;
|
|
35
|
+
console.log(`🛡️ Grade ${result.grade} — ${result.findings.length} reverse-engineering exposure(s) in ${result.scannedFiles} file(s) (${kinds}, ${result.durationMs}ms)`);
|
|
36
|
+
console.log(` Critical: ${counts["critical"] ?? 0} High: ${counts["high"] ?? 0} Medium: ${counts["medium"] ?? 0} Low: ${counts["low"] ?? 0}`);
|
|
37
|
+
console.log("");
|
|
38
|
+
for (const f of result.findings) {
|
|
39
|
+
console.log(`${SEV_ICON[f.severity] ?? "⚪"} [${f.severity.toUpperCase()}] ${f.patternName} (${f.target}/${f.category})`);
|
|
40
|
+
if (f.file)
|
|
41
|
+
console.log(` Where : ${f.file}${f.line > 1 ? `:${f.line}:${f.column}` : ""}`);
|
|
42
|
+
if (f.match)
|
|
43
|
+
console.log(` Evidence : ${f.match}`);
|
|
44
|
+
console.log(` Fix : ${f.recommendation}`);
|
|
45
|
+
console.log("");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const n of result.notes)
|
|
49
|
+
console.log(` • ${n}`);
|
|
50
|
+
}
|
|
51
|
+
function parseArgs(args) {
|
|
52
|
+
const positionals = [];
|
|
53
|
+
let failOn = "any";
|
|
54
|
+
let format = "text";
|
|
55
|
+
let maxFiles = 5000;
|
|
56
|
+
for (const arg of args) {
|
|
57
|
+
if (arg.startsWith("--fail-on="))
|
|
58
|
+
failOn = arg.split("=")[1] ?? "any";
|
|
59
|
+
else if (arg.startsWith("--format="))
|
|
60
|
+
format = arg.split("=")[1] ?? "text";
|
|
61
|
+
else if (arg.startsWith("--max-files="))
|
|
62
|
+
maxFiles = parseInt(arg.split("=")[1] ?? "5000", 10);
|
|
63
|
+
else if (!arg.startsWith("--"))
|
|
64
|
+
positionals.push(arg);
|
|
65
|
+
}
|
|
66
|
+
return { positionals, failOn, format, maxFiles };
|
|
67
|
+
}
|
|
68
|
+
function shouldFail(findings, failOn) {
|
|
69
|
+
if (failOn === "none")
|
|
70
|
+
return false;
|
|
71
|
+
if (failOn === "any")
|
|
72
|
+
return findings.length > 0;
|
|
73
|
+
const RANK = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
74
|
+
const threshold = RANK[failOn] ?? 1;
|
|
75
|
+
return findings.some((f) => (RANK[f.severity] ?? 3) <= threshold);
|
|
76
|
+
}
|
|
77
|
+
async function runCli(rawArgs) {
|
|
78
|
+
const { positionals, failOn: cliFail, format, maxFiles: cliMax } = parseArgs(rawArgs);
|
|
79
|
+
const target = positionals[0];
|
|
80
|
+
if (!target) {
|
|
81
|
+
console.error("Usage: guardbee-reverse-shield scan <path|url> [--fail-on=any] [--format=text|json|sarif]");
|
|
82
|
+
process.exit(2);
|
|
83
|
+
}
|
|
84
|
+
let result;
|
|
85
|
+
let failOn = cliFail;
|
|
86
|
+
if (/^https?:\/\//i.test(target)) {
|
|
87
|
+
result = await scanUrl(target);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const cfg = loadConfig(target, {
|
|
91
|
+
...(cliFail !== "any" ? { failOn: cliFail } : {}),
|
|
92
|
+
...(cliMax !== 5000 ? { maxFiles: cliMax } : {}),
|
|
93
|
+
});
|
|
94
|
+
const cfgPath = configFilePath(target);
|
|
95
|
+
if (cfgPath && format === "text")
|
|
96
|
+
process.stderr.write(`[guardbee] Using config: ${cfgPath}\n`);
|
|
97
|
+
failOn = cfg.failOn;
|
|
98
|
+
try {
|
|
99
|
+
result = scanPath(target, { maxFiles: cfg.maxFiles, exclude: cfg.exclude });
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
console.error(err.message);
|
|
103
|
+
process.exit(2);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (format === "json") {
|
|
107
|
+
console.log(JSON.stringify(result, null, 2));
|
|
108
|
+
}
|
|
109
|
+
else if (format === "sarif") {
|
|
110
|
+
console.log(JSON.stringify(buildSarif(getVersion(), result.findings), null, 2));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
printText(result);
|
|
114
|
+
}
|
|
115
|
+
// exitCode, not exit(): a large JSON/SARIF report piped to another process
|
|
116
|
+
// would otherwise be cut off before stdout drains.
|
|
117
|
+
process.exitCode = shouldFail(result.findings, failOn) ? 1 : 0;
|
|
118
|
+
}
|
|
119
|
+
function printHelp() {
|
|
120
|
+
console.log(`@guardbee/mcp-reverse-shield
|
|
121
|
+
|
|
122
|
+
How much does your shipped app give a reverse engineer for free?
|
|
123
|
+
|
|
124
|
+
Usage (MCP server):
|
|
125
|
+
guardbee-reverse-shield [serve]
|
|
126
|
+
|
|
127
|
+
Usage (CLI):
|
|
128
|
+
guardbee-reverse-shield scan <path> Scan an artifact or a build output directory
|
|
129
|
+
guardbee-reverse-shield scan <url> Scan a live site's same-site bundles and source maps
|
|
130
|
+
|
|
131
|
+
Recognised artifacts:
|
|
132
|
+
Web .js .mjs .cjs bundles, .map source maps, build output folders, live URLs
|
|
133
|
+
Electron .app bundles, app folders with resources/, app.asar (fuses + bundled code)
|
|
134
|
+
Android .apk (manifest flags, R8 obfuscation, signing, RN bundle, native libs)
|
|
135
|
+
Native ELF, Mach-O (incl. universal), PE executables and libraries
|
|
136
|
+
.NET PE assemblies with a CLR header (obfuscation, embedded PDB)
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
--fail-on=<level> Exit 1 if issues at this severity or above are found
|
|
140
|
+
Levels: any (default) | critical | high | medium | low | none
|
|
141
|
+
--format=<fmt> Output format: text (default) | json | sarif
|
|
142
|
+
--max-files=<n> Max files to check in a directory (default: 5000)
|
|
143
|
+
|
|
144
|
+
Exit codes:
|
|
145
|
+
0 No issues found (or none above --fail-on threshold)
|
|
146
|
+
1 Issues found at or above threshold
|
|
147
|
+
2 Error / bad arguments
|
|
148
|
+
`);
|
|
149
|
+
}
|
|
150
|
+
const [, , firstArg, ...rest] = process.argv;
|
|
151
|
+
if (!firstArg || firstArg === "serve") {
|
|
152
|
+
startServer().catch((err) => {
|
|
153
|
+
process.stderr.write(`[guardbee-reverse-shield] Fatal error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else if (firstArg === "--help" || firstArg === "-h") {
|
|
158
|
+
printHelp();
|
|
159
|
+
process.exit(0);
|
|
160
|
+
}
|
|
161
|
+
else if (firstArg === "scan") {
|
|
162
|
+
runCli(rest).catch((err) => {
|
|
163
|
+
console.error("Error:", err.message);
|
|
164
|
+
process.exit(2);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
console.error(`Unknown command: ${firstArg}`);
|
|
169
|
+
console.error("Run with --help for usage.");
|
|
170
|
+
process.exit(2);
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ReverseShieldConfig {
|
|
2
|
+
failOn: string;
|
|
3
|
+
maxFiles: number;
|
|
4
|
+
exclude: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function loadConfig(searchDir: string, cliOverrides?: Partial<ReverseShieldConfig>): ReverseShieldConfig;
|
|
7
|
+
export declare function configFilePath(searchDir: string): string | null;
|
|
8
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAkFD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAAG,mBAAmB,CAmBlH;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE/D"}
|