MemScan-EDR/src-csharp/MemScanEDR/Services/DetectionPipeline.cs

280 lines
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using MemScanEDR.Models;
namespace MemScanEDR.Services;
/// <summary>
/// 三级联动检测管线 —— 2.0 核心编排引擎
///
/// 流程:
/// [快速预过滤] → [第一层: 基线异常检测] → [第二层: 监督分类] → [第三层: MITRE规则复核] → 输出
///
/// 速度优化:
/// - 预过滤阶段不读内存,仅元数据判断,跳过 >80% 的进程
/// - 只在可疑进程上执行完整特征提取
/// - 基线匹配失败时提前退出,节省计算
/// </summary>
public class DetectionPipeline
{
private readonly BaselineEngine _baselineEngine;
private readonly ClassificationEngine _classificationEngine;
private readonly RuleEngine _ruleEngine;
private readonly FeatureExtractor _featureExtractor;
private readonly MemoryScanner _memoryScanner;
private readonly BaselineLibrary _baselineLibrary;
// 扫描模式
private readonly ScanMode _mode;
public DetectionPipeline(ScanMode mode = ScanMode.Balanced)
{
_mode = mode;
_baselineLibrary = BaselineLibrary.CreateDefault();
_baselineEngine = new BaselineEngine(_baselineLibrary);
_classificationEngine = new ClassificationEngine();
_ruleEngine = new RuleEngine();
_featureExtractor = new FeatureExtractor();
_memoryScanner = new MemoryScanner();
}
/// <summary>
/// 完整三级检测流程
/// </summary>
public Task<ScanResult> AnalyzeAsync(ProcessInfo proc, List<Signature> signatures)
{
return Task.FromResult(Analyze(proc, signatures));
}
/// <summary>
/// 完整三级检测流程(同步核心)
/// </summary>
private ScanResult Analyze(ProcessInfo proc, List<Signature> signatures)
{
var sw = Stopwatch.StartNew();
// ─── 阶段0: 快速预过滤(不读内存)───
var memoryRegions = _memoryScanner.GetMemoryRegions(proc.Pid);
proc.MemoryRegions = memoryRegions;
var signatureMatches = new List<SignatureMatch>();
var preFilterResult = QuickPreFilter(proc, memoryRegions);
if (preFilterResult.canSkip)
{
return new ScanResult
{
Pid = proc.Pid,
ProcessName = proc.Name,
RiskLevel = RiskLevel.Safe,
RiskScore = preFilterResult.score,
Indicators = new List<string>(),
Reasoning = preFilterResult.reason,
AIProvider = "pipeline-v2/fast-filter",
DetectionLayer = "PreFilter",
ScanTime = DateTime.Now
};
}
// ─── 阶段1: 内存区域扫描(轻量)───
if (_mode != ScanMode.Fast)
{
var suspiciousRegions = _memoryScanner.GetSuspiciousRegions(proc.Pid);
if (suspiciousRegions.Count > 0 || proc.IsTempPath || !proc.IsSigned)
{
signatureMatches = _memoryScanner.ScanProcess(proc.Pid, signatures);
}
}
// ─── 阶段2: 特征提取 ───
MemoryFeatures features;
if (_mode == ScanMode.Fast)
{
features = _featureExtractor.QuickExtract(proc, memoryRegions);
}
else
{
features = _featureExtractor.Extract(proc, memoryRegions, signatureMatches, signatures);
}
// ─── 第一层: 无监督基线检测 ───
var baselineResult = _baselineEngine.Analyze(features);
// 完全匹配基线 → 直接判定为正常
if (baselineResult.Classification == BaselineClassification.Normal &&
baselineResult.AnomalyScore < 0.20)
{
return BuildSafeResult(proc, features, baselineResult, signatureMatches,
$"第一层 | 进程内存结构完全匹配正常基线 [{baselineResult.BaselineName}] | 异常分数={baselineResult.AnomalyScore:F3}");
}
// ─── 第二层: 监督分类 ───
var classificationResult = _classificationEngine.Classify(features);
// 分类为良性 + 基线无异常 → 安全
if (classificationResult.Classification == MalwareClass.Benign &&
baselineResult.AnomalyScore < 0.40)
{
return BuildSafeResult(proc, features, baselineResult, signatureMatches,
$"第二层 | 分类器判定良性 | {classificationResult.SuspectedFamily}");
}
// ─── 第三层: MITRE ATT&CK规则复核 ───
var ruleResult = _ruleEngine.Validate(features, classificationResult, baselineResult);
// ─── 构建最终结果 ───
var indicators = BuildIndicators(features, baselineResult, classificationResult, ruleResult);
var layer = DetermineDetectionLayer(baselineResult, classificationResult, ruleResult);
return new ScanResult
{
Pid = proc.Pid,
ProcessName = proc.Name,
RiskLevel = ruleResult.FinalRiskLevel,
RiskScore = ruleResult.CombinedScore,
Indicators = indicators,
Reasoning = ruleResult.Reasoning,
Matches = signatureMatches,
AIProvider = $"pipeline-v2/{_mode.ToString().ToLower()}",
DetectionLayer = layer,
ScanTime = DateTime.Now
};
}
// ─── 快速预过滤 ───
private static (bool canSkip, double score, string reason) QuickPreFilter(
ProcessInfo proc, List<MemoryRegion> regions)
{
double score = 0;
var reasons = new List<string>();
// 已签名 + 系统路径 + 无网络 → 几乎肯定安全
if (proc.IsSigned && proc.IsSystemPath && proc.Connections.Count == 0)
{
// 再检查是否有可疑内存区域
var hasRwx = regions.Any(r =>
r.Protect.Contains("EXECUTE_READWRITE") && r.Type == "PRIVATE");
if (!hasRwx && !proc.IsTempPath)
{
return (true, 0, $"预过滤 | 已签名系统程序 | PID={proc.Pid} {proc.Name}");
}
// 脚本引擎/Shell 有合法RWX(JIT)即使有RWX也是正常的
if (hasRwx && FeatureExtractor.IsScriptingEngine(proc))
{
return (true, 0.05, $"预过滤 | 已签名脚本引擎(RWX为JIT正常行为) | PID={proc.Pid} {proc.Name}");
}
}
// 未签名 + 临时路径 → 需要进一步分析
if (!proc.IsSigned && proc.IsTempPath)
score += 0.30;
// 系统进程名 + 非系统路径 → 可疑
if (FeatureExtractor.IsSystemProcessName(proc.Name) && !proc.IsSystemPath)
score += 0.35;
// 网络连接到可疑端口
if (proc.Connections.Any(c => IsSuspiciousPort(c.RemotePort)))
score += 0.25;
// RWX 私有页
if (regions.Any(r => r.Protect.Contains("EXECUTE_READWRITE") && r.Type == "PRIVATE"))
score += 0.20;
if (score < 0.05)
return (true, 0, $"预过滤 | 无可疑特征 | PID={proc.Pid} {proc.Name}");
if (score < 0.15 && proc.IsSigned)
return (true, score * 0.5, $"预过滤 | 已签名低风险 | PID={proc.Pid} {proc.Name} | score={score:F2}");
return (false, score, $"预过滤 | 进入AI分析 | PID={proc.Pid} {proc.Name} | score={score:F2}");
}
private static bool IsSuspiciousPort(int port) => port switch
{
4444 or 5555 or 6666 or 7777 or 1337 or 31337 or 9999 or 12345 or 27015 => true,
_ => false
};
private static ScanResult BuildSafeResult(ProcessInfo proc, MemoryFeatures features,
BaselineResult baseline, List<SignatureMatch> matches, string reasoning)
{
return new ScanResult
{
Pid = proc.Pid,
ProcessName = proc.Name,
RiskLevel = RiskLevel.Safe,
RiskScore = Math.Min(baseline.AnomalyScore, 0.15),
Indicators = new List<string>(),
Reasoning = reasoning,
Matches = matches,
AIProvider = "pipeline-v2/baseline",
DetectionLayer = "Layer1_Baseline",
ScanTime = DateTime.Now
};
}
private static List<string> BuildIndicators(MemoryFeatures f, BaselineResult baseline,
ClassificationResult classification, RuleValidationResult rule)
{
var indicators = new List<string>();
if (baseline.IsAnomalous)
{
indicators.Add($"基线异常(分数={baseline.AnomalyScore:F2})");
foreach (var idx in baseline.DeviantFeatureIndices.Take(3))
indicators.Add($"偏离特征#{idx}");
}
if (classification.Classification == MalwareClass.Malicious)
indicators.Add($"AI分类:恶意({classification.SuspectedFamily})");
else if (classification.Classification == MalwareClass.Suspicious)
indicators.Add("AI分类:可疑");
if (rule.MatchedRuleCount > 0)
{
foreach (var tech in rule.MatchedTechniques.Take(5))
indicators.Add(tech);
}
if (f.RwxPrivatePages > 0)
indicators.Add($"RWX私有页={f.RwxPrivatePages}");
if (f.PeMismatchDisk)
indicators.Add("ProcessHollowing");
if (f.SuspiciousStringHits > 0)
indicators.Add($"敏感字符串={f.SuspiciousStringHits}");
return indicators;
}
private static string DetermineDetectionLayer(BaselineResult baseline,
ClassificationResult classification, RuleValidationResult rule)
{
if (rule.MatchedRuleCount >= 2) return "L3_Rules+L2_AI+L1_Baseline";
if (classification.Classification == MalwareClass.Malicious) return "L2_AI+L1_Baseline";
if (baseline.IsAnomalous) return "L1_Baseline";
return "PreFilter";
}
}
/// <summary>
/// 扫描模式
/// </summary>
public enum ScanMode
{
/// <summary>快速模式:仅元数据,不读取内存</summary>
Fast,
/// <summary>平衡模式:采样熵值 + 特征提取</summary>
Balanced,
/// <summary>深度模式:全量内存扫描 + 完整特征提取</summary>
Deep
}