@mlvscan/wasm-core 1.1.7 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,19 +1,190 @@
1
1
  # @mlvscan/wasm-core
2
2
 
3
- WebAssembly core for MLVScan – scanning Unity mods in the browser.
3
+ [![npm](https://img.shields.io/npm/v/@mlvscan/wasm-core.svg?color=red)](https://www.npmjs.com/package/@mlvscan/wasm-core)
4
4
 
5
- ## Local development (before publishing)
5
+ WebAssembly scanning engine for [MLVScan](https://github.com/ifBars/MLVScan). Runs the full [MLVScan.Core](https://github.com/ifBars/MLVScan.Core) malware detection engine entirely in the browser — no server, no uploads, no tracking.
6
6
 
7
- 1. Build the .NET WASM app from the `MLVScan.WASM` project folder:
8
- ```bash
9
- dotnet publish -c Release
10
- ```
11
- 2. Copy the built `_framework` into this package’s `dist` so the package is self-contained:
12
- ```bash
13
- npm run copy:framework
14
- ```
15
- 3. Consuming projects (e.g. MLVScan.Web.v2) can depend on this package via `"file:../MLVScan.Core/MLVScan.WASM/npm"` and run `npm install`. The web app will serve and copy `_framework` from `node_modules/@mlvscan/wasm-core/dist/_framework`.
7
+ ## Installation
16
8
 
17
- ## Publish
9
+ ```bash
10
+ npm install @mlvscan/wasm-core
11
+ ```
18
12
 
19
- Run `tsc` and `copy:framework` (after building the .NET project), then `npm pack` or publish to a registry.
13
+ ## Serving the Framework Files
14
+
15
+ The package ships with a `dist/_framework` directory containing the .NET WASM runtime. **Your build tool must serve these files at runtime.** With Vite, use `vite-plugin-static-copy`:
16
+
17
+ ```ts
18
+ // vite.config.ts
19
+ import { viteStaticCopy } from 'vite-plugin-static-copy'
20
+
21
+ export default {
22
+ plugins: [
23
+ viteStaticCopy({
24
+ targets: [{
25
+ src: 'node_modules/@mlvscan/wasm-core/dist/_framework',
26
+ dest: '.'
27
+ }]
28
+ })
29
+ ]
30
+ }
31
+ ```
32
+
33
+ Then initialize with `baseUrl: '/'` (the default).
34
+
35
+ ## Quick Start
36
+
37
+ ```ts
38
+ import { initScanner, scanAssembly } from '@mlvscan/wasm-core'
39
+
40
+ // Initialize once at app startup
41
+ await initScanner({ baseUrl: '/' })
42
+
43
+ // Scan a DLL from a file input
44
+ const file = event.target.files[0]
45
+ const bytes = new Uint8Array(await file.arrayBuffer())
46
+ const result = await scanAssembly(bytes, file.name)
47
+
48
+ console.log(`Found ${result.summary.totalFindings} issue(s)`)
49
+ for (const finding of result.findings) {
50
+ console.log(`[${finding.severity}] ${finding.description} @ ${finding.location}`)
51
+ }
52
+ ```
53
+
54
+ ## API Reference
55
+
56
+ ### `initScanner(options?)`
57
+
58
+ Loads the .NET WASM runtime. Call once at app startup before scanning. Safe to call multiple times — subsequent calls are no-ops if already initialized.
59
+
60
+ ```ts
61
+ await initScanner({
62
+ baseUrl: '/', // Where _framework is served. Defaults to '/'.
63
+ useMock: false, // Force mock mode (useful for testing). Defaults to false.
64
+ throwOnInitFailure: false // Throw instead of falling back to mock on load failure.
65
+ })
66
+ ```
67
+
68
+ If `throwOnInitFailure` is not set and WASM fails to load, the scanner silently falls back to mock mode (returning zero findings). Use `getScannerStatus()` to detect this.
69
+
70
+ ---
71
+
72
+ ### `scanAssembly(fileBytes, fileName)`
73
+
74
+ Scans a .NET assembly and returns a [`ScanResult`](#scanresult). Auto-initializes if `initScanner` was not called first.
75
+
76
+ ```ts
77
+ const result = await scanAssembly(bytes, 'MyMod.dll')
78
+ ```
79
+
80
+ ---
81
+
82
+ ### `scanAssemblyWithConfig(fileBytes, fileName, config)`
83
+
84
+ Scans with explicit options for deeper analysis (call chains, data flows, developer guidance).
85
+
86
+ ```ts
87
+ const result = await scanAssemblyWithConfig(bytes, 'MyMod.dll', {
88
+ developerMode: true,
89
+ enableCrossMethodAnalysis: true,
90
+ deepAnalysis: {
91
+ enableDeepAnalysis: true,
92
+ enableNetworkToExecutionCorrelation: true,
93
+ }
94
+ })
95
+ ```
96
+
97
+ ---
98
+
99
+ ### Status & Utility
100
+
101
+ | Function | Returns | Description |
102
+ |---|---|---|
103
+ | `isScannerReady()` | `boolean` | True when init has completed (real or mock). Use to gate the scan button. |
104
+ | `isMockScanner()` | `boolean` | True when running in mock mode. |
105
+ | `getScannerStatus()` | `ScannerStatus` | Full status snapshot — ready, mock, explicit mock, and init error. |
106
+ | `getScannerVersion()` | `Promise<string>` | Scanner engine version (e.g. `"1.1.7"`). Returns `"1.0.0-mock"` in mock mode. |
107
+ | `getSchemaVersion()` | `Promise<string>` | Result schema version (e.g. `"1.0.0"`). |
108
+ | `getInitError()` | `Error \| null` | The error that caused WASM fallback, or null if healthy. |
109
+
110
+ ## Scan Modes
111
+
112
+ The `scanMode` in [`ScanConfigInput`](#scanassemblywithconfig) controls the depth of analysis and what is included in the result:
113
+
114
+ | Mode | Description |
115
+ |---|---|
116
+ | `summary` (default) | Fast scan. Returns findings with severity and location. |
117
+ | `detailed` | Includes `callChains` — the execution path from entry point to suspicious code. |
118
+ | `developer` | Includes `dataFlows` and `developerGuidance` with remediation suggestions. |
119
+
120
+ ## Handling WASM Load Failures
121
+
122
+ If the WASM runtime fails to load (e.g. COOP/COEP headers not set, browser incompatibility), the scanner falls back to mock mode automatically. Check the status after init to show an appropriate message:
123
+
124
+ ```ts
125
+ await initScanner({ baseUrl: '/' })
126
+
127
+ const status = getScannerStatus()
128
+ if (status.initError) {
129
+ console.warn('Scanner unavailable, results will be empty:', status.initError.message)
130
+ }
131
+ ```
132
+
133
+ To throw instead of falling back silently:
134
+
135
+ ```ts
136
+ await initScanner({ baseUrl: '/', throwOnInitFailure: true })
137
+ ```
138
+
139
+ ## Type Reference
140
+
141
+ ### `ScanResult`
142
+
143
+ The root object returned by all scan functions.
144
+
145
+ ```ts
146
+ interface ScanResult {
147
+ schemaVersion: string
148
+ metadata: ScanMetadata // Scanner version, timestamp, scan mode, platform
149
+ input: ScanInput // File name, size, optional SHA-256
150
+ summary: ScanSummary // Total findings and counts by severity
151
+ findings: Finding[] // Individual security findings
152
+ callChains?: CallChain[] // Detailed mode: execution paths
153
+ dataFlows?: DataFlowChain[] // Developer mode: source-to-sink data flows
154
+ developerGuidance?: DeveloperGuidance[] // Developer mode: remediation suggestions
155
+ }
156
+ ```
157
+
158
+ ### `Finding`
159
+
160
+ ```ts
161
+ interface Finding {
162
+ ruleId?: string
163
+ description: string
164
+ severity: 'Low' | 'Medium' | 'High' | 'Critical'
165
+ location: string // Type/method name or file:line
166
+ codeSnippet?: string
167
+ }
168
+ ```
169
+
170
+ ### `ScannerStatus`
171
+
172
+ ```ts
173
+ interface ScannerStatus {
174
+ ready: boolean
175
+ isMock: boolean
176
+ mockRequestedExplicitly: boolean
177
+ initError: Error | null
178
+ }
179
+ ```
180
+
181
+ For the full type definitions, see [`types.ts`](https://github.com/ifBars/MLVScan.Core/blob/main/MLVScan.WASM/npm/src/types.ts).
182
+
183
+ ## Related
184
+
185
+ * [MLVScan.Core](https://github.com/ifBars/MLVScan.Core) — The detection engine (NuGet package, CLI, WASM source)
186
+ * [MLVScan.Web](https://github.com/ifBars/MLVScan.Web) — React web app built on this package
187
+ * [MLVScan](https://github.com/ifBars/MLVScan) — MelonLoader/BepInEx plugin
188
+
189
+ ---
190
+ *Licensed under GPL-3.0*
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mainAssemblyName": "MLVScan.WASM.dll",
3
3
  "resources": {
4
- "hash": "sha256-jTAixhhqHmH6Js7hnz8TbIU8LPF6Av7QIkhdNfm8da8=",
4
+ "hash": "sha256-kQ8yXgo/2m62IeBvqmE2y/Rv5qnIhJ76+Mb2sd2UHtk=",
5
5
  "jsModuleNative": {
6
6
  "dotnet.native.js": "sha256-clxzGaAFwcQ6QWhwQ7dzpD9ktR/87yTache3B45gqoQ="
7
7
  },
@@ -9,7 +9,7 @@
9
9
  "dotnet.runtime.js": "sha256-TGUqQm2/C+r+yZ5BCjd72qyLw9wv0KPFKzKXk/giiyY="
10
10
  },
11
11
  "wasmNative": {
12
- "dotnet.native.wasm": "sha256-fin1Zl1yIo6hXwrmCD6i3R0OLwYlXlPPBuP9GwGRhfQ="
12
+ "dotnet.native.wasm": "sha256-7LljILBN1AFf6EU6LHPYFSM546zEqe1EGl7AAP3pb1Q="
13
13
  },
14
14
  "wasmSymbols": {
15
15
  "dotnet.native.js.symbols": "sha256-mcn0xQOEP6bIrzi/nvTIsKV7ryyqIdVUtbOIC/EOcqI="
@@ -20,20 +20,20 @@
20
20
  "icudt_no_CJK.dat": "sha256-L7sV7NEYP37/Qr2FPCePo5cJqRgTXRwGHuwF5Q+0Nfs="
21
21
  },
22
22
  "assembly": {
23
- "MLVScan.Core.wasm": "sha256-I6pReZ5whl4GsSwBOycEb5zMmcsiocjRQSFEUKSY+64=",
24
- "MLVScan.WASM.wasm": "sha256-E3uY+sg1PROG3DaOEhgnwb3Qrwiol/wRsrpVKKnqMKs=",
25
- "Mono.Cecil.wasm": "sha256-9nKX3pNgOOICbt5NYrpLzfr68C2NenjxIZRWMSm3+9s=",
26
- "System.Collections.Concurrent.wasm": "sha256-63SVm6IOpVPPAswPtjPxNn+UVLmQVcVw/TsZkAERzZ0=",
27
- "System.Collections.wasm": "sha256-suGbEYUofGw2k7rtWARZyGc4mKVUtVEV3TwUd3fZmmo=",
23
+ "MLVScan.Core.wasm": "sha256-n14Dpe9qxFK9DoeqYdYn3XdOfGlQ8tUR1214rLiCwgc=",
24
+ "MLVScan.WASM.wasm": "sha256-RPRKDzyd235JwUgdRljPx8P2308Dy8hid3msbRu1Azc=",
25
+ "Mono.Cecil.wasm": "sha256-+26bn77S22+aVO+7xKl2WP74xQjSYR0S8GP6mRWf9C8=",
26
+ "System.Collections.Concurrent.wasm": "sha256-pFhCmskR6dmKt18zv1jrGGR184LyXdz408BBMX4BBhg=",
27
+ "System.Collections.wasm": "sha256-TRwwb/PWxTAKfplBNqMkn14z5rNLvuy459MunrnseDo=",
28
28
  "System.IO.Compression.wasm": "sha256-zPnVmOjOHN/V1tNLjZurM9T/xj1LXcVlKv+emtlb3gA=",
29
- "System.Linq.wasm": "sha256-9tHJX23oXTc36XpgjNVp5rHnx9pG+W2584qC0yZIJII=",
30
- "System.Memory.wasm": "sha256-kNlcsfG/cVsoTKFZc2vbR+COjs4GUSwhQHlLCNkCqEg=",
31
- "System.Private.CoreLib.wasm": "sha256-k4QAIYYtp+zKYAMwo5l55YeGDF4iEi70Q5M7PSB/uBc=",
29
+ "System.Linq.wasm": "sha256-1wPZ41jMHt8ciwhU3I4TFTqP5hLFGPgwv9ELOm1r4sc=",
30
+ "System.Memory.wasm": "sha256-csnkwt/JrsppyyW/C58TooGjK2jHvla7al1hV1pbTm4=",
31
+ "System.Private.CoreLib.wasm": "sha256-Zvoxo5D29MB/hBBw4MTVcRXUU77qT05R4VgGobV5ycw=",
32
32
  "System.Runtime.InteropServices.JavaScript.wasm": "sha256-knh9wD83/GTpX28IRzoUJy42zEAtXZdBUcckFTm6bzw=",
33
33
  "System.Security.Cryptography.wasm": "sha256-1yetTxYoa9Mv2JdPd07A9bKVQKSs1o/cCS66raJYlMQ=",
34
- "System.Text.Encodings.Web.wasm": "sha256-0Yj+mrS4Z2sHQGjRimW4tqk281Rv2anm+6r0rfM+7x8=",
35
- "System.Text.Json.wasm": "sha256-2eNYX3n7GnAmU/ijgyEEbIqVdeKYh9kjIVv4cA1Q3lc=",
36
- "System.Text.RegularExpressions.wasm": "sha256-OhRvJc9wBjXcObymgRgCyOalu/X7h8WyZAGrSpsMgYg="
34
+ "System.Text.Encodings.Web.wasm": "sha256-nPDcUnKJT3K4bYAjeaZI+9dn3OmAWOVz87kkXfy7znA=",
35
+ "System.Text.Json.wasm": "sha256-AeaONG3Ex8c3fn8CGqF/3LBoWcM5ZFPr+ulSTe/PVRQ=",
36
+ "System.Text.RegularExpressions.wasm": "sha256-6xU3ws3QrP3va4o+lU66Gz4HOOB8fkyaR4hm51P5cJQ="
37
37
  },
38
38
  "vfs": {
39
39
  "runtimeconfig.bin": {
Binary file
package/dist/index.d.ts CHANGED
@@ -18,7 +18,7 @@
18
18
  * const result = await scanAssembly(dllBytes, 'MyMod.dll')
19
19
  * ```
20
20
  */
21
- import type { ScanResult } from './types';
21
+ import type { ScanConfigInput, ScanResult } from './types';
22
22
  /**
23
23
  * Options for initializing the WASM scanner.
24
24
  *
@@ -81,6 +81,11 @@ export declare function initScanner(options?: ScannerInitOptions): Promise<void>
81
81
  * @throws When the scanner is not in mock mode but the WASM scan call fails.
82
82
  */
83
83
  export declare function scanAssembly(fileBytes: Uint8Array, fileName: string): Promise<ScanResult>;
84
+ /**
85
+ * Scans an assembly with an explicit scan configuration (including deep analysis options).
86
+ * Use this for opt-in deep scans while keeping quick scan defaults for normal usage.
87
+ */
88
+ export declare function scanAssemblyWithConfig(fileBytes: Uint8Array, fileName: string, config: ScanConfigInput): Promise<ScanResult>;
84
89
  /**
85
90
  * Returns whether the scanner is ready to use (initialization finished, either
86
91
  * with real WASM or mock). Use this to gate UI (e.g. enable "Scan" only when
package/dist/index.js CHANGED
@@ -161,6 +161,35 @@ export async function scanAssembly(fileBytes, fileName) {
161
161
  throw new Error(`Scan failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
162
162
  }
163
163
  }
164
+ /**
165
+ * Scans an assembly with an explicit scan configuration (including deep analysis options).
166
+ * Use this for opt-in deep scans while keeping quick scan defaults for normal usage.
167
+ */
168
+ export async function scanAssemblyWithConfig(fileBytes, fileName, config) {
169
+ if (!scannerLoaded) {
170
+ await initScanner();
171
+ }
172
+ if (useMockScanner || !scannerExports) {
173
+ return {
174
+ ...mockScanResult,
175
+ input: {
176
+ fileName,
177
+ sizeBytes: fileBytes.length,
178
+ },
179
+ };
180
+ }
181
+ if (!scannerExports.MLVScan?.WASM?.ScannerExports) {
182
+ throw new Error('Scanner not properly initialized: MLVScan.WASM.ScannerExports not found');
183
+ }
184
+ try {
185
+ const configJson = JSON.stringify(config ?? {});
186
+ const resultJson = scannerExports.MLVScan.WASM.ScannerExports.ScanAssemblyWithConfig(fileBytes, fileName, configJson);
187
+ return JSON.parse(resultJson);
188
+ }
189
+ catch (error) {
190
+ throw new Error(`Scan with config failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
191
+ }
192
+ }
164
193
  /**
165
194
  * Returns whether the scanner is ready to use (initialization finished, either
166
195
  * with real WASM or mock). Use this to gate UI (e.g. enable "Scan" only when
package/dist/types.d.ts CHANGED
@@ -119,3 +119,35 @@ export interface DeveloperGuidance {
119
119
  alternativeApis?: string[];
120
120
  isRemediable: boolean;
121
121
  }
122
+ export interface DeepBehaviorAnalysisConfig {
123
+ enableDeepAnalysis?: boolean;
124
+ emitDiagnosticFindings?: boolean;
125
+ requireCorrelatedBaseFinding?: boolean;
126
+ deepScanOnlyFlaggedMethods?: boolean;
127
+ enableStringDecodeFlow?: boolean;
128
+ enableExecutionChainAnalysis?: boolean;
129
+ enableResourcePayloadAnalysis?: boolean;
130
+ enableDynamicLoadCorrelation?: boolean;
131
+ enableNativeInteropCorrelation?: boolean;
132
+ enableScriptHostLaunchAnalysis?: boolean;
133
+ enableEnvironmentPivotCorrelation?: boolean;
134
+ enableNetworkToExecutionCorrelation?: boolean;
135
+ maxInstructionsPerMethod?: number;
136
+ maxAnalysisTimeMsPerMethod?: number;
137
+ maxDeepMethodsPerAssembly?: number;
138
+ maxTrackedDataFlowEdgesPerMethod?: number;
139
+ }
140
+ export interface ScanConfigInput {
141
+ developerMode?: boolean;
142
+ enableCrossMethodAnalysis?: boolean;
143
+ maxCallChainDepth?: number;
144
+ enableReturnValueTracking?: boolean;
145
+ detectAssemblyMetadata?: boolean;
146
+ enableMultiSignalDetection?: boolean;
147
+ analyzeExceptionHandlers?: boolean;
148
+ analyzeLocalVariables?: boolean;
149
+ analyzePropertyAccessors?: boolean;
150
+ enableRecursiveResourceScanning?: boolean;
151
+ maxRecursiveResourceSizeMB?: number;
152
+ deepAnalysis?: DeepBehaviorAnalysisConfig;
153
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mlvscan/wasm-core",
3
- "version": "1.1.7",
3
+ "version": "1.1.9",
4
4
  "description": "WebAssembly core for MLVScan - scanning Unity mods in the browser",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",