176 lines
5.8 KiB
C#
176 lines
5.8 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using MemScanEDR.Models;
|
|||
|
|
|
|||
|
|
namespace MemScanEDR.Services;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 无监督基线检测引擎 —— 第一层过滤
|
|||
|
|
/// 使用统计异常检测方法(Z-score + 重构误差),无需恶意样本训练
|
|||
|
|
/// 核心逻辑:正常程序内存结构高度规整,恶意程序偏离基线
|
|||
|
|
/// </summary>
|
|||
|
|
public class BaselineEngine
|
|||
|
|
{
|
|||
|
|
private readonly BaselineLibrary _baselineLibrary;
|
|||
|
|
private readonly double _globalAnomalyThreshold;
|
|||
|
|
|
|||
|
|
public BaselineEngine(BaselineLibrary? library = null, double threshold = 0.50)
|
|||
|
|
{
|
|||
|
|
_baselineLibrary = library ?? BaselineLibrary.CreateDefault();
|
|||
|
|
_globalAnomalyThreshold = threshold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 分析进程特征,返回异常分数和判定结果
|
|||
|
|
/// </summary>
|
|||
|
|
public BaselineResult Analyze(MemoryFeatures features)
|
|||
|
|
{
|
|||
|
|
var result = new BaselineResult();
|
|||
|
|
|
|||
|
|
// 1. 找到最匹配的基线
|
|||
|
|
var baseline = _baselineLibrary.FindBestMatch(features.ProcessName, features.ExePath);
|
|||
|
|
if (baseline == null)
|
|||
|
|
{
|
|||
|
|
result.IsAnomalous = false;
|
|||
|
|
result.AnomalyScore = 0;
|
|||
|
|
result.Details = "无匹配基线,跳过异常检测";
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result.BaselineName = baseline.Name;
|
|||
|
|
|
|||
|
|
// 2. 转换特征为向量
|
|||
|
|
var featureVector = features.ToFeatureVector();
|
|||
|
|
|
|||
|
|
// 3. 计算 Z-score 异常分数 (Mahalanobis-like)
|
|||
|
|
var (anomalyScore, deviantFeatures) = baseline.CalculateAnomalyScore(featureVector);
|
|||
|
|
|
|||
|
|
// 4. 计算重构误差
|
|||
|
|
var reconstructionError = baseline.CalculateReconstructionError(featureVector);
|
|||
|
|
|
|||
|
|
// 5. 综合分数:Z-score 异常 + 重构误差加权
|
|||
|
|
var combinedScore = anomalyScore * 0.6 + reconstructionError * 0.4;
|
|||
|
|
combinedScore = Math.Min(combinedScore, 1.0);
|
|||
|
|
|
|||
|
|
result.AnomalyScore = combinedScore;
|
|||
|
|
result.DeviantFeatureCount = deviantFeatures.Count;
|
|||
|
|
result.DeviantFeatureIndices = deviantFeatures;
|
|||
|
|
result.ReconstructionError = reconstructionError;
|
|||
|
|
result.IsAnomalous = combinedScore > _globalAnomalyThreshold;
|
|||
|
|
|
|||
|
|
// 6. 生成可解释性说明
|
|||
|
|
result.Details = GenerateExplanation(features, baseline, deviantFeatures, combinedScore);
|
|||
|
|
|
|||
|
|
// 7. 判定分类
|
|||
|
|
result.Classification = combinedScore switch
|
|||
|
|
{
|
|||
|
|
< 0.25 => BaselineClassification.Normal,
|
|||
|
|
< 0.50 => BaselineClassification.BenignVariance,
|
|||
|
|
< 0.75 => BaselineClassification.Anomalous,
|
|||
|
|
_ => BaselineClassification.HighlyAnomalous
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 快速预判 —— 仅基于元数据,不读内存
|
|||
|
|
/// </summary>
|
|||
|
|
public BaselineResult QuickPreAnalyze(ProcessInfo proc, List<MemoryRegion> regions)
|
|||
|
|
{
|
|||
|
|
var extractor = new FeatureExtractor();
|
|||
|
|
var features = extractor.QuickExtract(proc, regions);
|
|||
|
|
return Analyze(features);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private static string GenerateExplanation(MemoryFeatures f, BaselineProfile baseline,
|
|||
|
|
List<int> deviantFeatures, double score)
|
|||
|
|
{
|
|||
|
|
var parts = new List<string>();
|
|||
|
|
|
|||
|
|
if (score < 0.25)
|
|||
|
|
{
|
|||
|
|
parts.Add("进程内存结构符合正常程序基线");
|
|||
|
|
return string.Join("; ", parts);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 命名特征索引对应的含义
|
|||
|
|
var featureNames = new Dictionary<int, string>
|
|||
|
|
{
|
|||
|
|
{0, "未签名"}, {1, "非系统路径"}, {2, "临时路径"},
|
|||
|
|
{5, "系统进程名"}, {6, "父进程异常"},
|
|||
|
|
{12, "RWX页比例高"}, {13, "匿名可执行页"}, {14, "RWX私有页"},
|
|||
|
|
{18, "内存PE头"}, {19, "PE与磁盘不一致"},
|
|||
|
|
{20, "可疑API"}, {21, "敏感字符串"}, {22, "签名匹配"}, {23, "高危签名"},
|
|||
|
|
{24, "高熵代码段"}, {25, "最大熵值"}, {26, "高熵区域数"},
|
|||
|
|
{29, "非标准端口连接"}, {30, "可疑端口"}, {31, "境外连接"},
|
|||
|
|
{35, "无磁盘映射模块"}, {36, "临时目录模块"}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
foreach (var idx in deviantFeatures.Take(5))
|
|||
|
|
{
|
|||
|
|
if (featureNames.TryGetValue(idx, out var name))
|
|||
|
|
parts.Add(name);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
parts.Add($"异常分数={score:F2}");
|
|||
|
|
|
|||
|
|
if (f.RwxPrivatePages > 0 && f.IsSystemProcessName)
|
|||
|
|
parts.Insert(0, "严重警告: 系统进程存在RWX私有内存");
|
|||
|
|
|
|||
|
|
if (f.PeMismatchDisk)
|
|||
|
|
parts.Insert(0, "严重警告: Process Hollowing 检测");
|
|||
|
|
|
|||
|
|
return string.Join("; ", parts);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 基线检测结果
|
|||
|
|
/// </summary>
|
|||
|
|
public class BaselineResult
|
|||
|
|
{
|
|||
|
|
/// <summary>使用的基线名称</summary>
|
|||
|
|
public string BaselineName { get; set; } = "";
|
|||
|
|
|
|||
|
|
/// <summary>综合异常分数 [0-1]</summary>
|
|||
|
|
public double AnomalyScore { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>是否判定为异常</summary>
|
|||
|
|
public bool IsAnomalous { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>偏离特征数量</summary>
|
|||
|
|
public int DeviantFeatureCount { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>偏离特征索引列表</summary>
|
|||
|
|
public List<int> DeviantFeatureIndices { get; set; } = new();
|
|||
|
|
|
|||
|
|
/// <summary>重构误差</summary>
|
|||
|
|
public double ReconstructionError { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>分类结果</summary>
|
|||
|
|
public BaselineClassification Classification { get; set; }
|
|||
|
|
|
|||
|
|
/// <summary>可解释性详情</summary>
|
|||
|
|
public string Details { get; set; } = "";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 基线分类结果
|
|||
|
|
/// </summary>
|
|||
|
|
public enum BaselineClassification
|
|||
|
|
{
|
|||
|
|
/// <summary>完全正常</summary>
|
|||
|
|
Normal,
|
|||
|
|
|
|||
|
|
/// <summary>良性偏差(如开发工具、安全软件的正常表现)</summary>
|
|||
|
|
BenignVariance,
|
|||
|
|
|
|||
|
|
/// <summary>异常偏离基线</summary>
|
|||
|
|
Anomalous,
|
|||
|
|
|
|||
|
|
/// <summary>高度异常</summary>
|
|||
|
|
HighlyAnomalous
|
|||
|
|
}
|