@guardbee/mcp-reverse-shield 0.0.0-stage → 0.1.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/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/config.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { resolve, join } from "path";
|
|
3
|
+
const DEFAULTS = {
|
|
4
|
+
failOn: "any",
|
|
5
|
+
maxFiles: 5000,
|
|
6
|
+
exclude: [],
|
|
7
|
+
};
|
|
8
|
+
function findConfigFile(startDir) {
|
|
9
|
+
const names = ["guardbee.yml", "guardbee.yaml", ".guardbee.yml"];
|
|
10
|
+
let dir = resolve(startDir);
|
|
11
|
+
for (let i = 0; i < 5; i++) {
|
|
12
|
+
for (const name of names) {
|
|
13
|
+
const p = join(dir, name);
|
|
14
|
+
if (existsSync(p))
|
|
15
|
+
return p;
|
|
16
|
+
}
|
|
17
|
+
const parent = resolve(dir, "..");
|
|
18
|
+
if (parent === dir)
|
|
19
|
+
break;
|
|
20
|
+
dir = parent;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// Minimal YAML parser — only handles the flat key: value and list items we need
|
|
25
|
+
function parseYaml(content) {
|
|
26
|
+
const root = {};
|
|
27
|
+
let currentSection = null;
|
|
28
|
+
let currentKey = null;
|
|
29
|
+
let currentList = null;
|
|
30
|
+
for (const rawLine of content.split("\n")) {
|
|
31
|
+
const line = rawLine.replace(/#.*$/, "");
|
|
32
|
+
if (!line.trim())
|
|
33
|
+
continue;
|
|
34
|
+
const indent = line.match(/^(\s*)/)?.[1].length ?? 0;
|
|
35
|
+
if (indent === 0 && line.trim().endsWith(":")) {
|
|
36
|
+
if (currentKey && currentList) {
|
|
37
|
+
root[currentSection][currentKey] = currentList;
|
|
38
|
+
currentList = null;
|
|
39
|
+
currentKey = null;
|
|
40
|
+
}
|
|
41
|
+
currentSection = line.trim().slice(0, -1);
|
|
42
|
+
root[currentSection] = {};
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (indent === 2 && currentSection) {
|
|
46
|
+
if (currentKey && currentList) {
|
|
47
|
+
root[currentSection][currentKey] = currentList;
|
|
48
|
+
currentList = null;
|
|
49
|
+
currentKey = null;
|
|
50
|
+
}
|
|
51
|
+
const colonIdx = line.indexOf(":");
|
|
52
|
+
if (colonIdx === -1)
|
|
53
|
+
continue;
|
|
54
|
+
const key = line.slice(0, colonIdx).trim();
|
|
55
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
56
|
+
if (value === "") {
|
|
57
|
+
currentKey = key;
|
|
58
|
+
currentList = [];
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
root[currentSection][key] = value;
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (indent === 4 && currentList !== null) {
|
|
66
|
+
const item = line.trim().replace(/^-\s*/, "").replace(/^['"]|['"]$/g, "");
|
|
67
|
+
currentList.push(item);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (currentKey && currentList && currentSection) {
|
|
72
|
+
root[currentSection][currentKey] = currentList;
|
|
73
|
+
}
|
|
74
|
+
return root;
|
|
75
|
+
}
|
|
76
|
+
export function loadConfig(searchDir, cliOverrides = {}) {
|
|
77
|
+
const configPath = findConfigFile(searchDir);
|
|
78
|
+
if (!configPath)
|
|
79
|
+
return { ...DEFAULTS, ...cliOverrides };
|
|
80
|
+
let fileConfig = {};
|
|
81
|
+
try {
|
|
82
|
+
const raw = readFileSync(configPath, "utf8");
|
|
83
|
+
const parsed = parseYaml(raw);
|
|
84
|
+
const section = parsed["reverse-shield"];
|
|
85
|
+
if (section) {
|
|
86
|
+
if (typeof section["fail-on"] === "string")
|
|
87
|
+
fileConfig.failOn = section["fail-on"];
|
|
88
|
+
if (typeof section["max-files"] === "string")
|
|
89
|
+
fileConfig.maxFiles = parseInt(section["max-files"], 10);
|
|
90
|
+
if (Array.isArray(section["exclude"]))
|
|
91
|
+
fileConfig.exclude = section["exclude"];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// ignore parse errors, use defaults
|
|
96
|
+
}
|
|
97
|
+
return { ...DEFAULTS, ...fileConfig, ...cliOverrides };
|
|
98
|
+
}
|
|
99
|
+
export function configFilePath(searchDir) {
|
|
100
|
+
return findConfigFile(searchDir);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/dex.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function isDex(buf: Buffer): boolean;
|
|
2
|
+
/** Type descriptors such as `Lcom/example/app/MainActivity;` (primitives and arrays included). */
|
|
3
|
+
export declare function readTypeDescriptors(buf: Buffer): string[];
|
|
4
|
+
export interface ObfuscationVerdict {
|
|
5
|
+
appClasses: number;
|
|
6
|
+
shortNamed: number;
|
|
7
|
+
obfuscated: boolean;
|
|
8
|
+
sample: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* R8/ProGuard renames everything it is allowed to into one- or two-letter
|
|
12
|
+
* names, and usually moves it out of the app package. An unobfuscated build
|
|
13
|
+
* keeps dozens of descriptive classes under the application id.
|
|
14
|
+
*/
|
|
15
|
+
export declare function assessDexObfuscation(descriptors: string[], packageName: string): ObfuscationVerdict;
|
|
16
|
+
//# sourceMappingURL=dex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dex.d.ts","sourceRoot":"","sources":["../src/dex.ts"],"names":[],"mappings":"AAeA,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1C;AAED,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBzD;AAKD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAenG"}
|
package/dist/dex.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Dalvik executable: only the class descriptors are needed, which come from
|
|
2
|
+
// type_ids -> string_ids -> string data (uleb128 length, then MUTF-8 bytes).
|
|
3
|
+
function readUleb128(buf, p) {
|
|
4
|
+
let value = 0;
|
|
5
|
+
let shift = 0;
|
|
6
|
+
let b;
|
|
7
|
+
do {
|
|
8
|
+
b = buf[p++];
|
|
9
|
+
value |= (b & 0x7f) << shift;
|
|
10
|
+
shift += 7;
|
|
11
|
+
} while (b & 0x80 && shift < 35);
|
|
12
|
+
return { value, next: p };
|
|
13
|
+
}
|
|
14
|
+
export function isDex(buf) {
|
|
15
|
+
return buf.length >= 0x70 && buf.toString("latin1", 0, 4) === "dex\n";
|
|
16
|
+
}
|
|
17
|
+
/** Type descriptors such as `Lcom/example/app/MainActivity;` (primitives and arrays included). */
|
|
18
|
+
export function readTypeDescriptors(buf) {
|
|
19
|
+
if (!isDex(buf))
|
|
20
|
+
return [];
|
|
21
|
+
const stringIdsOff = buf.readUInt32LE(0x3c);
|
|
22
|
+
const typeIdsSize = buf.readUInt32LE(0x40);
|
|
23
|
+
const typeIdsOff = buf.readUInt32LE(0x44);
|
|
24
|
+
const out = [];
|
|
25
|
+
for (let i = 0; i < typeIdsSize; i++) {
|
|
26
|
+
const t = typeIdsOff + i * 4;
|
|
27
|
+
if (t + 4 > buf.length)
|
|
28
|
+
break;
|
|
29
|
+
const s = stringIdsOff + buf.readUInt32LE(t) * 4;
|
|
30
|
+
if (s + 4 > buf.length)
|
|
31
|
+
break;
|
|
32
|
+
const { next } = readUleb128(buf, buf.readUInt32LE(s));
|
|
33
|
+
const end = buf.indexOf(0, next);
|
|
34
|
+
if (end === -1)
|
|
35
|
+
break;
|
|
36
|
+
out.push(buf.toString("utf8", next, end));
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
// Generated by the build for every app; their names say nothing about R8.
|
|
41
|
+
const GENERATED = /^(R|R\$.*|BuildConfig|Manifest|Manifest\$.*|databinding\/.*|BR)$/;
|
|
42
|
+
/**
|
|
43
|
+
* R8/ProGuard renames everything it is allowed to into one- or two-letter
|
|
44
|
+
* names, and usually moves it out of the app package. An unobfuscated build
|
|
45
|
+
* keeps dozens of descriptive classes under the application id.
|
|
46
|
+
*/
|
|
47
|
+
export function assessDexObfuscation(descriptors, packageName) {
|
|
48
|
+
const prefix = `L${packageName.replace(/\./g, "/")}/`;
|
|
49
|
+
const app = descriptors
|
|
50
|
+
.filter((d) => d.startsWith(prefix) && d.endsWith(";"))
|
|
51
|
+
.map((d) => d.slice(prefix.length, -1))
|
|
52
|
+
.filter((rel) => !GENERATED.test(rel.split("/").pop() ?? ""));
|
|
53
|
+
const simple = (rel) => (rel.split("/").pop() ?? "").split("$")[0];
|
|
54
|
+
const shortNamed = app.filter((rel) => simple(rel).length <= 2).length;
|
|
55
|
+
const descriptive = app.filter((rel) => simple(rel).length > 2);
|
|
56
|
+
return {
|
|
57
|
+
appClasses: app.length,
|
|
58
|
+
shortNamed,
|
|
59
|
+
obfuscated: app.length < 25 || shortNamed / app.length >= 0.2,
|
|
60
|
+
sample: descriptive.slice(0, 3).map((rel) => `${packageName}.${rel.replace(/\//g, ".")}`),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=dex.js.map
|
package/dist/dex.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dex.js","sourceRoot":"","sources":["../src/dex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Finding } from "./finding.js";
|
|
2
|
+
/** Marker @electron/fuses writes before the fuse wire: version byte, length byte, then one byte per fuse. */
|
|
3
|
+
export declare const FUSE_SENTINEL: Buffer<ArrayBuffer>;
|
|
4
|
+
export interface FuseWire {
|
|
5
|
+
version: number;
|
|
6
|
+
/** One char per fuse: "1" enabled, "0" disabled, "r" removed. */
|
|
7
|
+
states: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseFuseWire(buf: Buffer, sentinelOffset: number): FuseWire | null;
|
|
10
|
+
export declare function readFuseWire(binaryPath: string): FuseWire | null;
|
|
11
|
+
export declare function describeFuses(wire: FuseWire): string;
|
|
12
|
+
export declare function fuseFindings(wire: FuseWire, file: string): Finding[];
|
|
13
|
+
export interface ElectronLayout {
|
|
14
|
+
root: string;
|
|
15
|
+
/** Binary that carries the fuse wire (Electron Framework on macOS, the app executable elsewhere). */
|
|
16
|
+
fuseBinary: string | null;
|
|
17
|
+
resources: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function detectElectron(dir: string): ElectronLayout | null;
|
|
20
|
+
export interface ElectronResult {
|
|
21
|
+
findings: Finding[];
|
|
22
|
+
notes: string[];
|
|
23
|
+
scannedFiles: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function analyzeElectron(layout: ElectronLayout, maxFiles: number): ElectronResult;
|
|
26
|
+
//# sourceMappingURL=electron.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electron.d.ts","sourceRoot":"","sources":["../src/electron.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAK5C,6GAA6G;AAC7G,eAAO,MAAM,aAAa,qBAAkD,CAAC;AAc7E,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAOlF;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAShE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAIpD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAcpE;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,qGAAqG;IACrG,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAyBjE;AAUD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CA4CxF"}
|
package/dist/electron.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { closeSync, existsSync, openSync, readFileSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import { basename, extname, join, relative, sep } from "path";
|
|
3
|
+
import { readAsar } from "./asar.js";
|
|
4
|
+
import { finding } from "./finding.js";
|
|
5
|
+
import { findInFile, readAt, walkFiles } from "./fsutil.js";
|
|
6
|
+
import { analyzeWebFiles, isWebAsset } from "./web.js";
|
|
7
|
+
/** Marker @electron/fuses writes before the fuse wire: version byte, length byte, then one byte per fuse. */
|
|
8
|
+
export const FUSE_SENTINEL = Buffer.from("dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX");
|
|
9
|
+
// FuseV1Options order in @electron/fuses
|
|
10
|
+
const FUSES = [
|
|
11
|
+
"RunAsNode",
|
|
12
|
+
"EnableCookieEncryption",
|
|
13
|
+
"EnableNodeOptionsEnvironmentVariable",
|
|
14
|
+
"EnableNodeCliInspectArguments",
|
|
15
|
+
"EnableEmbeddedAsarIntegrityValidation",
|
|
16
|
+
"OnlyLoadAppFromAsar",
|
|
17
|
+
"LoadBrowserProcessSpecificV8Snapshot",
|
|
18
|
+
"GrantFileProtocolExtraPrivileges",
|
|
19
|
+
];
|
|
20
|
+
export function parseFuseWire(buf, sentinelOffset) {
|
|
21
|
+
const p = sentinelOffset + FUSE_SENTINEL.length;
|
|
22
|
+
if (p + 2 > buf.length)
|
|
23
|
+
return null;
|
|
24
|
+
const version = buf[p];
|
|
25
|
+
const length = buf[p + 1];
|
|
26
|
+
if (length === 0 || p + 2 + length > buf.length)
|
|
27
|
+
return null;
|
|
28
|
+
return { version, states: buf.toString("latin1", p + 2, p + 2 + length) };
|
|
29
|
+
}
|
|
30
|
+
export function readFuseWire(binaryPath) {
|
|
31
|
+
const [hit] = findInFile(binaryPath, FUSE_SENTINEL, 1);
|
|
32
|
+
if (hit === undefined)
|
|
33
|
+
return null;
|
|
34
|
+
const fd = openSync(binaryPath, "r");
|
|
35
|
+
try {
|
|
36
|
+
return parseFuseWire(readAt(fd, hit, FUSE_SENTINEL.length + 2 + 64), 0);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
closeSync(fd);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function describeFuses(wire) {
|
|
43
|
+
return FUSES.slice(0, wire.states.length)
|
|
44
|
+
.map((name, i) => `${name}=${wire.states[i] === "1" ? "on" : wire.states[i] === "0" ? "off" : "removed"}`)
|
|
45
|
+
.join(", ");
|
|
46
|
+
}
|
|
47
|
+
export function fuseFindings(wire, file) {
|
|
48
|
+
const s = wire.states;
|
|
49
|
+
const findings = [];
|
|
50
|
+
const on = (i) => s[i] === "1";
|
|
51
|
+
const off = (i) => s[i] === "0";
|
|
52
|
+
const add = (id, fuseIndex) => findings.push(finding(id, file, { match: `${FUSES[fuseIndex]}=${on(fuseIndex) ? "on" : "off"}` }));
|
|
53
|
+
if (on(0))
|
|
54
|
+
add("electron_fuse_run_as_node", 0);
|
|
55
|
+
if (on(3))
|
|
56
|
+
add("electron_fuse_inspect_args", 3);
|
|
57
|
+
if (on(2))
|
|
58
|
+
add("electron_fuse_node_options", 2);
|
|
59
|
+
if (off(4))
|
|
60
|
+
add("electron_fuse_asar_integrity_off", 4);
|
|
61
|
+
if (off(5))
|
|
62
|
+
add("electron_fuse_load_outside_asar", 5);
|
|
63
|
+
return findings;
|
|
64
|
+
}
|
|
65
|
+
const MIN_ELECTRON_BINARY_BYTES = 20 * 1024 * 1024;
|
|
66
|
+
export function detectElectron(dir) {
|
|
67
|
+
const macFramework = join(dir, "Contents", "Frameworks", "Electron Framework.framework");
|
|
68
|
+
if (existsSync(macFramework)) {
|
|
69
|
+
const bin = join(macFramework, "Electron Framework");
|
|
70
|
+
return { root: dir, fuseBinary: existsSync(bin) ? bin : null, resources: join(dir, "Contents", "Resources") };
|
|
71
|
+
}
|
|
72
|
+
const resources = join(dir, "resources");
|
|
73
|
+
if (!existsSync(join(resources, "app.asar")) && !existsSync(join(resources, "app", "package.json")))
|
|
74
|
+
return null;
|
|
75
|
+
// Windows/Linux: the fuse wire is in the main executable next to resources/.
|
|
76
|
+
const candidates = [];
|
|
77
|
+
for (const name of safeReaddir(dir)) {
|
|
78
|
+
const full = join(dir, name);
|
|
79
|
+
const ext = extname(name).toLowerCase();
|
|
80
|
+
if (ext !== "" && ext !== ".exe")
|
|
81
|
+
continue;
|
|
82
|
+
try {
|
|
83
|
+
const st = statSync(full);
|
|
84
|
+
if (st.isFile() && st.size >= MIN_ELECTRON_BINARY_BYTES)
|
|
85
|
+
candidates.push(full);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// unreadable entry
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const fuseBinary = candidates.find((c) => findInFile(c, FUSE_SENTINEL, 1).length > 0) ?? null;
|
|
92
|
+
return { root: dir, fuseBinary, resources };
|
|
93
|
+
}
|
|
94
|
+
function safeReaddir(dir) {
|
|
95
|
+
try {
|
|
96
|
+
return readdirSync(dir);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function analyzeElectron(layout, maxFiles) {
|
|
103
|
+
const findings = [];
|
|
104
|
+
const notes = [];
|
|
105
|
+
let scannedFiles = 0;
|
|
106
|
+
if (layout.fuseBinary) {
|
|
107
|
+
const wire = readFuseWire(layout.fuseBinary);
|
|
108
|
+
if (wire) {
|
|
109
|
+
notes.push(`Electron fuses (${basename(layout.fuseBinary)}): ${describeFuses(wire)}`);
|
|
110
|
+
findings.push(...fuseFindings(wire, layout.fuseBinary));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
notes.push(`No Electron fuse wire found in ${layout.fuseBinary} (Electron older than 12, or a custom build).`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const appDir = join(layout.resources, "app");
|
|
117
|
+
if (existsSync(join(appDir, "package.json"))) {
|
|
118
|
+
findings.push(finding("electron_app_unpacked", appDir, {
|
|
119
|
+
match: existsSync(join(layout.resources, "app.asar")) ? "resources/app is loaded ahead of app.asar" : "no app.asar",
|
|
120
|
+
}));
|
|
121
|
+
const files = [];
|
|
122
|
+
walkFiles(appDir, { maxFiles, skipDirs: new Set(["node_modules", ".git"]) }, (full) => {
|
|
123
|
+
const key = relative(appDir, full).split(sep).join("/");
|
|
124
|
+
if (!isWebAsset(key))
|
|
125
|
+
return;
|
|
126
|
+
files.push({ key, display: full, size: statSync(full).size, read: () => readFileSync(full) });
|
|
127
|
+
});
|
|
128
|
+
scannedFiles += files.length;
|
|
129
|
+
findings.push(...analyzeWebFiles(files));
|
|
130
|
+
}
|
|
131
|
+
const asarPath = join(layout.resources, "app.asar");
|
|
132
|
+
if (existsSync(asarPath)) {
|
|
133
|
+
const entries = readAsar(asarPath);
|
|
134
|
+
if (entries) {
|
|
135
|
+
const web = entries.filter((e) => isWebAsset(e.key)).slice(0, maxFiles);
|
|
136
|
+
notes.push(`app.asar: ${entries.length} file(s), ${web.length} shipped JavaScript/source map file(s) checked`);
|
|
137
|
+
scannedFiles += web.length;
|
|
138
|
+
findings.push(...analyzeWebFiles(web));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
notes.push(`app.asar could not be parsed: ${asarPath}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { findings, notes, scannedFiles };
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=electron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electron.js","sourceRoot":"","sources":["../src/electron.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGvD,6GAA6G;AAC7G,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;AAE7E,yCAAyC;AACzC,MAAM,KAAK,GAAG;IACZ,WAAW;IACX,wBAAwB;IACxB,sCAAsC;IACtC,+BAA+B;IAC/B,uCAAuC;IACvC,qBAAqB;IACrB,sCAAsC;IACtC,kCAAkC;CAC1B,CAAC;AAQX,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,cAAsB;IAC/D,MAAM,CAAC,GAAG,cAAc,GAAG,aAAa,CAAC,MAAM,CAAC;IAChD,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,IAAI,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,UAAkB;IAC7C,MAAM,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IACvD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,EAAE,GAAG,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,OAAO,aAAa,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,aAAa,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;SACtC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;SACzG,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAc,EAAE,IAAY;IACvD,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IACtB,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IACvC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;IACxC,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,SAAiB,EAAE,EAAE,CAC5C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAErG,IAAI,EAAE,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,2BAA2B,EAAE,CAAC,CAAC,CAAC;IAC/C,IAAI,EAAE,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC;IAChD,IAAI,EAAE,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,4BAA4B,EAAE,CAAC,CAAC,CAAC;IAChD,IAAI,GAAG,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,kCAAkC,EAAE,CAAC,CAAC,CAAC;IACvD,IAAI,GAAG,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,iCAAiC,EAAE,CAAC,CAAC,CAAC;IACtD,OAAO,QAAQ,CAAC;AAClB,CAAC;AASD,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEnD,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,YAAY,EAAE,8BAA8B,CAAC,CAAC;IACzF,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;QACrD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;IAChH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEjH,6EAA6E;IAC7E,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,MAAM;YAAE,SAAS;QAC3C,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,IAAI,IAAI,yBAAyB;gBAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;IACH,CAAC;IACD,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IAC9F,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAQD,MAAM,UAAU,eAAe,CAAC,MAAsB,EAAE,QAAgB;IACtE,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,IAAI,EAAE,CAAC;YACT,KAAK,CAAC,IAAI,CAAC,mBAAmB,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACtF,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1D,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,kCAAkC,MAAM,CAAC,UAAU,+CAA+C,CAAC,CAAC;QACjH,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QAC7C,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,uBAAuB,EAAE,MAAM,EAAE;YACrD,KAAK,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,2CAA2C,CAAC,CAAC,CAAC,aAAa;SACpH,CAAC,CAAC,CAAC;QACJ,MAAM,KAAK,GAAmB,EAAE,CAAC;QACjC,SAAS,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;YACpF,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO;YAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChG,CAAC,CAAC,CAAC;QACH,YAAY,IAAI,KAAK,CAAC,MAAM,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YACxE,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,CAAC,MAAM,aAAa,GAAG,CAAC,MAAM,gDAAgD,CAAC,CAAC;YAC/G,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RuleCategory, Severity, TargetKind } from "./rules.js";
|
|
2
|
+
export interface Finding {
|
|
3
|
+
patternId: string;
|
|
4
|
+
patternName: string;
|
|
5
|
+
target: TargetKind;
|
|
6
|
+
category: RuleCategory;
|
|
7
|
+
severity: Severity;
|
|
8
|
+
recommendation: string;
|
|
9
|
+
/** Path of the artifact, with `!/inner/path` for files inside an archive (APK, ASAR). */
|
|
10
|
+
file?: string;
|
|
11
|
+
/** Artifacts are mostly binary — line/column are 1 unless a text match has a real position. */
|
|
12
|
+
line: number;
|
|
13
|
+
column: number;
|
|
14
|
+
match: string;
|
|
15
|
+
context: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function finding(id: string, file: string | undefined, detail?: {
|
|
18
|
+
match?: string;
|
|
19
|
+
context?: string;
|
|
20
|
+
severity?: Severity;
|
|
21
|
+
line?: number;
|
|
22
|
+
column?: number;
|
|
23
|
+
}): Finding;
|
|
24
|
+
export declare function bySeverity(a: Finding, b: Finding): number;
|
|
25
|
+
/**
|
|
26
|
+
* A–F reverse-engineering resistance grade: how much an analyst gets for free.
|
|
27
|
+
* Driven by the worst finding, then nudged down by volume at that level.
|
|
28
|
+
*/
|
|
29
|
+
export declare function grade(findings: Finding[]): "A" | "B" | "C" | "D" | "F";
|
|
30
|
+
//# sourceMappingURL=finding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding.d.ts","sourceRoot":"","sources":["../src/finding.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,yFAAyF;IACzF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,OAAO,CACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,MAAM,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACrG,OAAO,CAeT;AAID,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAOtE"}
|
package/dist/finding.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getRule } from "./rules.js";
|
|
2
|
+
export function finding(id, file, detail = {}) {
|
|
3
|
+
const rule = getRule(id);
|
|
4
|
+
return {
|
|
5
|
+
patternId: rule.id,
|
|
6
|
+
patternName: rule.name,
|
|
7
|
+
target: rule.target,
|
|
8
|
+
category: rule.category,
|
|
9
|
+
severity: detail.severity ?? rule.severity,
|
|
10
|
+
recommendation: rule.recommendation,
|
|
11
|
+
file,
|
|
12
|
+
line: detail.line ?? 1,
|
|
13
|
+
column: detail.column ?? 1,
|
|
14
|
+
match: detail.match ?? "",
|
|
15
|
+
context: detail.context ?? rule.exposes,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const RANK = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
19
|
+
export function bySeverity(a, b) {
|
|
20
|
+
return RANK[a.severity] - RANK[b.severity];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A–F reverse-engineering resistance grade: how much an analyst gets for free.
|
|
24
|
+
* Driven by the worst finding, then nudged down by volume at that level.
|
|
25
|
+
*/
|
|
26
|
+
export function grade(findings) {
|
|
27
|
+
if (findings.length === 0)
|
|
28
|
+
return "A";
|
|
29
|
+
const worst = Math.min(...findings.map((f) => RANK[f.severity]));
|
|
30
|
+
if (worst === RANK.critical)
|
|
31
|
+
return "F";
|
|
32
|
+
if (worst === RANK.high)
|
|
33
|
+
return findings.filter((f) => f.severity === "high").length >= 3 ? "F" : "D";
|
|
34
|
+
if (worst === RANK.medium)
|
|
35
|
+
return "C";
|
|
36
|
+
return "B";
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=finding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finding.js","sourceRoot":"","sources":["../src/finding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAmBrC,MAAM,UAAU,OAAO,CACrB,EAAU,EACV,IAAwB,EACxB,SAAoG,EAAE;IAEtG,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACzB,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,EAAE;QAClB,WAAW,EAAE,IAAI,CAAC,IAAI;QACtB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ;QAC1C,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,IAAI;QACJ,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;QAC1B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,IAAI,GAA6B,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAEnF,MAAM,UAAU,UAAU,CAAC,CAAU,EAAE,CAAU;IAC/C,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,QAAmB;IACvC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjE,IAAI,KAAK,KAAK,IAAI,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACtG,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,GAAG,CAAC;IACtC,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/fsutil.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function readAt(fd: number, offset: number, length: number): Buffer;
|
|
2
|
+
export declare function readPrefix(filePath: string, length: number): Buffer;
|
|
3
|
+
/**
|
|
4
|
+
* Finds every offset of `needle` in a file without loading it whole — the
|
|
5
|
+
* Electron framework binary that carries the fuse wire is 150–250 MB.
|
|
6
|
+
*/
|
|
7
|
+
export declare function findInFile(filePath: string, needle: Buffer, maxHits?: number): number[];
|
|
8
|
+
export interface WalkOptions {
|
|
9
|
+
maxFiles: number;
|
|
10
|
+
include?: string[];
|
|
11
|
+
exclude?: string[];
|
|
12
|
+
/** Directory names never descended into. */
|
|
13
|
+
skipDirs: Set<string>;
|
|
14
|
+
/** Called for directories; returning true stops the walk from descending (the caller handles it as a unit). */
|
|
15
|
+
claimDir?: (path: string) => boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function walkFiles(root: string, options: WalkOptions, onFile: (path: string) => void): {
|
|
18
|
+
truncated: boolean;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=fsutil.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsutil.d.ts","sourceRoot":"","sources":["../src/fsutil.ts"],"names":[],"mappings":"AAGA,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKzE;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,EAAE,CAgBlF;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,4CAA4C;IAC5C,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,+GAA+G;IAC/G,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CAiCpH"}
|
package/dist/fsutil.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { closeSync, openSync, readSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
export function readAt(fd, offset, length) {
|
|
4
|
+
if (length <= 0)
|
|
5
|
+
return Buffer.alloc(0);
|
|
6
|
+
const buf = Buffer.alloc(length);
|
|
7
|
+
const bytesRead = readSync(fd, buf, 0, length, offset);
|
|
8
|
+
return bytesRead === length ? buf : buf.subarray(0, bytesRead);
|
|
9
|
+
}
|
|
10
|
+
export function readPrefix(filePath, length) {
|
|
11
|
+
const fd = openSync(filePath, "r");
|
|
12
|
+
try {
|
|
13
|
+
return readAt(fd, 0, length);
|
|
14
|
+
}
|
|
15
|
+
finally {
|
|
16
|
+
closeSync(fd);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Finds every offset of `needle` in a file without loading it whole — the
|
|
21
|
+
* Electron framework binary that carries the fuse wire is 150–250 MB.
|
|
22
|
+
*/
|
|
23
|
+
export function findInFile(filePath, needle, maxHits = 8) {
|
|
24
|
+
const CHUNK = 16 * 1024 * 1024;
|
|
25
|
+
const size = statSync(filePath).size;
|
|
26
|
+
const hits = [];
|
|
27
|
+
const fd = openSync(filePath, "r");
|
|
28
|
+
try {
|
|
29
|
+
for (let pos = 0; pos < size && hits.length < maxHits; pos += CHUNK) {
|
|
30
|
+
const chunk = readAt(fd, pos, Math.min(CHUNK + needle.length - 1, size - pos));
|
|
31
|
+
for (let i = chunk.indexOf(needle); i !== -1 && hits.length < maxHits; i = chunk.indexOf(needle, i + 1)) {
|
|
32
|
+
if (i < CHUNK)
|
|
33
|
+
hits.push(pos + i);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
closeSync(fd);
|
|
39
|
+
}
|
|
40
|
+
return hits;
|
|
41
|
+
}
|
|
42
|
+
export function walkFiles(root, options, onFile) {
|
|
43
|
+
let count = 0;
|
|
44
|
+
let truncated = false;
|
|
45
|
+
const visit = (dir) => {
|
|
46
|
+
let entries;
|
|
47
|
+
try {
|
|
48
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (count >= options.maxFiles) {
|
|
56
|
+
truncated = true;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const full = join(dir, entry.name);
|
|
60
|
+
if (options.exclude?.some((e) => full.includes(e)))
|
|
61
|
+
continue;
|
|
62
|
+
if (entry.isDirectory()) {
|
|
63
|
+
if (options.skipDirs.has(entry.name))
|
|
64
|
+
continue;
|
|
65
|
+
if (options.claimDir?.(full))
|
|
66
|
+
continue;
|
|
67
|
+
visit(full);
|
|
68
|
+
}
|
|
69
|
+
else if (entry.isFile()) {
|
|
70
|
+
if (options.include && options.include.length > 0 && !options.include.some((i) => full.includes(i)))
|
|
71
|
+
continue;
|
|
72
|
+
count++;
|
|
73
|
+
onFile(full);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
visit(root);
|
|
78
|
+
return { truncated };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=fsutil.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsutil.js","sourceRoot":"","sources":["../src/fsutil.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { scanPath } from "./scanner.js";
|
|
2
|
+
export type { ScanOptions, ScanResult } from "./scanner.js";
|
|
3
|
+
export { scanUrl } from "./live.js";
|
|
4
|
+
export type { UrlScanOptions } from "./live.js";
|
|
5
|
+
export { RULES, getRule } from "./rules.js";
|
|
6
|
+
export type { Rule, RuleCategory, Severity, TargetKind } from "./rules.js";
|
|
7
|
+
export { grade } from "./finding.js";
|
|
8
|
+
export type { Finding } from "./finding.js";
|
|
9
|
+
export { analyzeJavaScript, analyzeWebFiles, parseSourceMap } from "./web.js";
|
|
10
|
+
export { analyzeApk } from "./apk.js";
|
|
11
|
+
export { parseAxml } from "./axml.js";
|
|
12
|
+
export { readAsar } from "./asar.js";
|
|
13
|
+
export { analyzeElectron, detectElectron, parseFuseWire, readFuseWire, FUSE_SENTINEL } from "./electron.js";
|
|
14
|
+
export { analyzeNative, detectNativeFormat } from "./native.js";
|
|
15
|
+
export { registerTools } from "./server.js";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { scanPath } from "./scanner.js";
|
|
2
|
+
export { scanUrl } from "./live.js";
|
|
3
|
+
export { RULES, getRule } from "./rules.js";
|
|
4
|
+
export { grade } from "./finding.js";
|
|
5
|
+
export { analyzeJavaScript, analyzeWebFiles, parseSourceMap } from "./web.js";
|
|
6
|
+
export { analyzeApk } from "./apk.js";
|
|
7
|
+
export { parseAxml } from "./axml.js";
|
|
8
|
+
export { readAsar } from "./asar.js";
|
|
9
|
+
export { analyzeElectron, detectElectron, parseFuseWire, readFuseWire, FUSE_SENTINEL } from "./electron.js";
|
|
10
|
+
export { analyzeNative, detectNativeFormat } from "./native.js";
|
|
11
|
+
export { registerTools } from "./server.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC5G,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/live.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ScanResult } from "./scanner.js";
|
|
2
|
+
export interface UrlScanOptions {
|
|
3
|
+
maxScripts?: number;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
/** Injected in tests. */
|
|
6
|
+
fetchImpl?: typeof fetch;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Loads a live page, then checks the same-site scripts it pulls in the way
|
|
10
|
+
* an analyst would start: read the bundles, follow their source map comments,
|
|
11
|
+
* and try `<bundle>.map` even when the comment was stripped.
|
|
12
|
+
*/
|
|
13
|
+
export declare function scanUrl(pageUrl: string, options?: UrlScanOptions): Promise<ScanResult>;
|
|
14
|
+
//# sourceMappingURL=live.d.ts.map
|