-
Notifications
You must be signed in to change notification settings - Fork 0
API Reference
Reference for the MLVScan.Core NuGet package.
The main entry point for scanning operations.
public class AssemblyScanner
{
// Constructor
public AssemblyScanner(IEnumerable<IScanRule> rules, ScanConfig config = null);
// Methods
public IEnumerable<ScanFinding> Scan(string filePath);
public IEnumerable<ScanFinding> Scan(Stream assemblyStream, string fileName);
}Helper for creating rule sets.
public static class RuleFactory
{
public static List<IScanRule> CreateDefaultRules();
}Represents a single detection.
public class ScanFinding
{
public string Description { get; set; }
public Severity Severity { get; set; } // Low, Medium, High, Critical
public string Location { get; set; } // e.g., "MyClass::MyMethod"
public string CodeSnippet { get; set; } // The actual IL instructions
public string RuleId { get; set; }
public IDeveloperGuidance? DeveloperGuidance { get; set; }
public bool HasCallChain { get; }
public CallChain? CallChain { get; set; }
}Tracks call relationships between methods and builds consolidated call chains for suspicious patterns. This allows consolidating multiple related findings (e.g., P/Invoke declaration + call site) into a single finding with full attack path visibility.
public class CallGraphBuilder
{
// Constructor
public CallGraphBuilder(IEnumerable<IScanRule> rules, CodeSnippetBuilder snippetBuilder);
// Register a suspicious P/Invoke or method declaration
public void RegisterSuspiciousDeclaration(
MethodDefinition method,
IScanRule triggeringRule,
string codeSnippet,
string description);
// Register a call site where a method calls another method
public void RegisterCallSite(
MethodDefinition callerMethod,
MethodReference calledMethod,
int instructionOffset,
string codeSnippet);
// Build consolidated call chain findings from all tracked data
public IEnumerable<ScanFinding> BuildCallChainFindings();
// Check if a method is registered as suspicious
public bool IsSuspiciousMethod(MethodReference method);
// Clear all tracked data (call before scanning a new assembly)
public void Clear();
// Properties
public int SuspiciousDeclarationCount { get; }
public int CallSiteCount { get; }
}Represents a complete call chain from an entry point to a suspicious declaration. Used to consolidate multiple findings that are part of the same attack pattern.
public class CallChain
{
public string ChainId { get; set; }
public string RuleId { get; set; }
public List<CallChainNode> Nodes { get; set; }
public Severity Severity { get; set; }
public string Summary { get; set; }
// Add nodes to the chain
public void PrependNode(CallChainNode node);
public void AppendNode(CallChainNode node);
// Get formatted output
public string ToDetailedDescription();
public string? ToCombinedCodeSnippet();
}Represents a single node in a call chain (one method call or declaration site).
public class CallChainNode
{
public string Location { get; set; }
public string? CodeSnippet { get; set; }
public string Description { get; set; }
public CallChainNodeType NodeType { get; set; }
}
public enum CallChainNodeType
{
EntryPoint, // Entry point (e.g., OnMelonInitialize)
IntermediateCall, // Intermediate method call
SuspiciousDeclaration // The suspicious declaration itself
}Analyzes data flow through IL instructions to track how data moves between suspicious operations. Supports both single-method and cross-method data flow analysis.
public class DataFlowAnalyzer
{
// Constructor
public DataFlowAnalyzer(
IEnumerable<IScanRule> rules,
CodeSnippetBuilder snippetBuilder,
DataFlowAnalyzerConfig config = null);
// Methods
public void Clear();
public List<DataFlowChain> AnalyzeMethod(MethodDefinition method);
public void AnalyzeCrossMethodFlows();
public IEnumerable<ScanFinding> BuildDataFlowFindings();
// Properties
public int DataFlowChainCount { get; }
public int SuspiciousChainCount { get; }
public int CrossMethodChainCount { get; }
public int SuspiciousCrossMethodChainCount { get; }
}See Data Flow Analysis for complete documentation.
Configuration for cross-method data flow analysis.
public class DataFlowAnalyzerConfig
{
// Enable cross-method data flow analysis
public bool EnableCrossMethodAnalysis { get; set; } = true;
// Maximum depth for call chain analysis (higher = more thorough but slower)
public int MaxCallChainDepth { get; set; } = 5;
// Enable return value tracking
public bool EnableReturnValueTracking { get; set; } = true;
}Represents a complete data flow from source to sink(s). Used to track how suspicious data moves through operations.
public class DataFlowChain
{
public string ChainId { get; set; }
public string? SourceVariable { get; set; }
public List<DataFlowNode> Nodes { get; set; }
public DataFlowPattern Pattern { get; set; }
public Severity Severity { get; set; }
public double Confidence { get; set; }
public string Summary { get; set; }
public string MethodLocation { get; set; }
public bool IsSuspicious { get; }
public bool IsCrossMethod { get; set; }
public List<string> InvolvedMethods { get; set; }
public int CallDepth { get; }
// Methods
public void AppendNode(DataFlowNode node);
public void PrependNode(DataFlowNode node);
public string ToDetailedDescription();
public string? ToCombinedCodeSnippet();
public DataFlowNode? GetSource();
public IEnumerable<DataFlowNode> GetSinks();
public IEnumerable<DataFlowNode> GetTransforms();
}Represents a single node in a data flow chain showing how data moves through operations.
public class DataFlowNode
{
public string Location { get; set; } // "MyClass.MyMethod:42"
public string Operation { get; set; } // "WebClient.DownloadData"
public DataFlowNodeType NodeType { get; set; } // Source/Transform/Sink/Intermediate
public string DataDescription { get; set; } // "byte[] (network data)"
public int InstructionOffset { get; set; } // IL offset
public string? CodeSnippet { get; set; } // IL code snippet
public string? MethodKey { get; set; } // For cross-method tracking
public bool IsMethodBoundary { get; set; } // Is this a method call?
public string? TargetMethodKey { get; set; } // Target method if boundary
}Known data flow patterns that indicate specific attack types.
public enum DataFlowPattern
{
Legitimate, // Normal, legitimate behavior
DownloadAndExecute, // Network → decode → execute (Critical)
DataExfiltration, // File/registry read → network send (Critical)
DynamicCodeLoading, // Network/file → Assembly.Load (Critical)
CredentialTheft, // Browser/password file → network (Critical)
RemoteConfigLoad, // Network → configuration (Medium)
ObfuscatedPersistence, // Encode → registry/startup (High)
Unknown // Suspicious but unrecognized
}Type of node in a data flow chain.
public enum DataFlowNodeType
{
Source, // Data originates here (network, file, registry)
Transform, // Data is transformed (decode, decrypt, decompress)
Sink, // Data is consumed (file write, process start, network send)
Intermediate // Data passes through (variable assignment, parameter passing)
}When MLVScan detects a P/Invoke declaration and its usage, it consolidates them into a single finding with a call chain:
[ENTRY] NoMoreTrash.Main.OnInitializeMelon: Entry point calls MaliciousHelper
[CALL] NoMoreTrash.MaliciousHelper.Execute:42: Calls ShellExecuteA
[DECL] NoMoreTrash.Southwards.ShellExecuteA: P/Invoke declaration for shell32.dll
This shows the complete attack path from the mod's entry point to the dangerous system call.
Implement this to create custom detection logic.
public interface IScanRule
{
string Description { get; }
Severity Severity { get; }
string RuleId { get; }
bool RequiresCompanionFinding { get; }
IDeveloperGuidance? DeveloperGuidance { get; }
// Return true if the method contains the pattern
bool IsSuspicious(MethodReference method);
// Analyze contextual patterns (optional, for advanced rules)
IEnumerable<ScanFinding> AnalyzeContextualPattern(
MethodReference method,
Collection<Instruction> instructions,
int instructionIndex,
MethodSignals methodSignals);
}Provides actionable guidance to mod developers for fixing flagged patterns.
public interface IDeveloperGuidance
{
string Remediation { get; }
string? DocumentationUrl { get; }
string[]? AlternativeApis { get; }
bool IsRemediable { get; }
}See Contributing for a guide on implementing these interfaces.