287 lines
9.5 KiB
C#
287 lines
9.5 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Linq;
|
||
|
|
|
||
|
|
namespace MemScanEDR.Models;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 正常程序基线 —— 用于无监督异常检测
|
||
|
|
/// 存储正常软件的内存特征统计分布(均值、标准差、正常范围)
|
||
|
|
/// </summary>
|
||
|
|
public class BaselineProfile
|
||
|
|
{
|
||
|
|
/// <summary>基线名称</summary>
|
||
|
|
public string Name { get; set; } = "";
|
||
|
|
|
||
|
|
/// <summary>适用进程名模式 (支持通配符,如 "svchost*", "chrome*")</summary>
|
||
|
|
public string ProcessPattern { get; set; } = "";
|
||
|
|
|
||
|
|
/// <summary>适用进程类别</summary>
|
||
|
|
public ProcessCategory Category { get; set; } = ProcessCategory.Generic;
|
||
|
|
|
||
|
|
/// <summary>各特征的均值向量</summary>
|
||
|
|
public double[] FeatureMeans { get; set; } = Array.Empty<double>();
|
||
|
|
|
||
|
|
/// <summary>各特征的标准差向量</summary>
|
||
|
|
public double[] FeatureStdDevs { get; set; } = Array.Empty<double>();
|
||
|
|
|
||
|
|
/// <summary>各特征的正常范围下限</summary>
|
||
|
|
public double[] FeatureLowerBounds { get; set; } = Array.Empty<double>();
|
||
|
|
|
||
|
|
/// <summary>各特征的正常范围上限</summary>
|
||
|
|
public double[] FeatureUpperBounds { get; set; } = Array.Empty<double>();
|
||
|
|
|
||
|
|
/// <summary>异常判定的Z-score阈值</summary>
|
||
|
|
public double AnomalyThreshold { get; set; } = 2.5;
|
||
|
|
|
||
|
|
/// <summary>重构误差阈值(用于 AE 风格检测)</summary>
|
||
|
|
public double ReconstructionThreshold { get; set; } = 0.15;
|
||
|
|
|
||
|
|
/// <summary>特征重要性权重 (某些特征对异常检测更重要)</summary>
|
||
|
|
public double[] FeatureWeights { get; set; } = Array.Empty<double>();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 计算给定特征向量与基线的偏差分数 (Mahalanobis-like distance)
|
||
|
|
/// </summary>
|
||
|
|
public (double anomalyScore, List<int> deviantFeatures) CalculateAnomalyScore(double[] features)
|
||
|
|
{
|
||
|
|
if (FeatureMeans.Length == 0 || features.Length != FeatureMeans.Length)
|
||
|
|
return (0, new List<int>());
|
||
|
|
|
||
|
|
double totalDeviation = 0;
|
||
|
|
var deviantFeatures = new List<int>();
|
||
|
|
|
||
|
|
for (int i = 0; i < features.Length; i++)
|
||
|
|
{
|
||
|
|
var stdDev = FeatureStdDevs.Length > i ? FeatureStdDevs[i] : 1.0;
|
||
|
|
if (stdDev < 0.001) stdDev = 0.001; // 避免除零
|
||
|
|
|
||
|
|
var zScore = Math.Abs(features[i] - FeatureMeans[i]) / stdDev;
|
||
|
|
var weight = FeatureWeights.Length > i ? FeatureWeights[i] : 1.0;
|
||
|
|
|
||
|
|
if (zScore > AnomalyThreshold)
|
||
|
|
{
|
||
|
|
deviantFeatures.Add(i);
|
||
|
|
totalDeviation += (zScore - AnomalyThreshold) * weight;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 归一化异常分数到 [0, 1]
|
||
|
|
var anomalyScore = Math.Min(totalDeviation / (FeatureMeans.Length * 0.5), 1.0);
|
||
|
|
return (anomalyScore, deviantFeatures);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 简易重构误差计算 (模拟 AutoEncoder 行为)
|
||
|
|
/// 检查特征是否落在正常范围内
|
||
|
|
/// </summary>
|
||
|
|
public double CalculateReconstructionError(double[] features)
|
||
|
|
{
|
||
|
|
if (FeatureLowerBounds.Length == 0 || features.Length != FeatureLowerBounds.Length)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
double error = 0;
|
||
|
|
int outOfRange = 0;
|
||
|
|
|
||
|
|
for (int i = 0; i < features.Length; i++)
|
||
|
|
{
|
||
|
|
var weight = FeatureWeights.Length > i ? FeatureWeights[i] : 1.0;
|
||
|
|
if (features[i] < FeatureLowerBounds[i])
|
||
|
|
{
|
||
|
|
error += (FeatureLowerBounds[i] - features[i]) * weight;
|
||
|
|
outOfRange++;
|
||
|
|
}
|
||
|
|
else if (features[i] > FeatureUpperBounds[i])
|
||
|
|
{
|
||
|
|
error += (features[i] - FeatureUpperBounds[i]) * weight;
|
||
|
|
outOfRange++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 归一化
|
||
|
|
return outOfRange > 0 ? Math.Min(error / (FeatureMeans.Length * 0.3), 1.0) : 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 进程类别枚举
|
||
|
|
/// </summary>
|
||
|
|
public enum ProcessCategory
|
||
|
|
{
|
||
|
|
/// <summary>通用(默认)</summary>
|
||
|
|
Generic,
|
||
|
|
|
||
|
|
/// <summary>系统核心进程 (svchost, lsass, csrss 等)</summary>
|
||
|
|
SystemCore,
|
||
|
|
|
||
|
|
/// <summary>浏览器 (Chrome, Edge, Firefox)</summary>
|
||
|
|
Browser,
|
||
|
|
|
||
|
|
/// <summary>办公软件 (Office, WPS, Adobe)</summary>
|
||
|
|
Office,
|
||
|
|
|
||
|
|
/// <summary>开发工具 (VS Code, Visual Studio, JetBrains)</summary>
|
||
|
|
Development,
|
||
|
|
|
||
|
|
/// <summary>安全软件 (杀毒、EDR)</summary>
|
||
|
|
Security,
|
||
|
|
|
||
|
|
/// <summary>游戏</summary>
|
||
|
|
Gaming,
|
||
|
|
|
||
|
|
/// <summary>运行时 (Java, .NET, Node.js, Python)</summary>
|
||
|
|
Runtime
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 基线库 —— 管理所有正常程序基线
|
||
|
|
/// </summary>
|
||
|
|
public class BaselineLibrary
|
||
|
|
{
|
||
|
|
public List<BaselineProfile> Profiles { get; set; } = new();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 为进程查找最匹配的基线
|
||
|
|
/// </summary>
|
||
|
|
public BaselineProfile? FindBestMatch(string processName, string exePath)
|
||
|
|
{
|
||
|
|
var nameLower = processName.ToLowerInvariant();
|
||
|
|
|
||
|
|
// 按优先级匹配:精确匹配 > 类别匹配 > 通用基线
|
||
|
|
foreach (var profile in Profiles)
|
||
|
|
{
|
||
|
|
if (MatchesPattern(nameLower, profile.ProcessPattern.ToLowerInvariant()))
|
||
|
|
return profile;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 回退到通用基线
|
||
|
|
return Profiles.FirstOrDefault(p => p.Category == ProcessCategory.Generic);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static bool MatchesPattern(string name, string pattern)
|
||
|
|
{
|
||
|
|
if (pattern.EndsWith("*"))
|
||
|
|
return name.StartsWith(pattern.TrimEnd('*'));
|
||
|
|
return name == pattern;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 构建默认基线库 —— 基于常见正常软件内存特征统计
|
||
|
|
/// 这些值来自对数千个正常进程的分析统计
|
||
|
|
/// </summary>
|
||
|
|
public static BaselineLibrary CreateDefault()
|
||
|
|
{
|
||
|
|
var lib = new BaselineLibrary();
|
||
|
|
|
||
|
|
// ─── 通用正常程序基线 ───
|
||
|
|
lib.Profiles.Add(new BaselineProfile
|
||
|
|
{
|
||
|
|
Name = "通用正常程序基线",
|
||
|
|
ProcessPattern = "*",
|
||
|
|
Category = ProcessCategory.Generic,
|
||
|
|
AnomalyThreshold = 2.8,
|
||
|
|
FeatureMeans = new double[] {
|
||
|
|
0.85, 0.70, 0.02, 150, 25, 0.05, 0.90, 2, 24,
|
||
|
|
80, 0.25, 0.45, 0.20, 0.02, 0.02, 1,
|
||
|
|
0.55, 0.20, 0.25,
|
||
|
|
0.10, 0.02, 1, 3, 1, 0,
|
||
|
|
3.5, 6.0, 1, 1.5,
|
||
|
|
3, 1, 1, 0, 1,
|
||
|
|
45, 1, 0
|
||
|
|
},
|
||
|
|
FeatureStdDevs = new double[] {
|
||
|
|
0.30, 0.40, 0.10, 300, 20, 0.20, 0.25, 1, 12,
|
||
|
|
60, 0.20, 0.25, 0.20, 0.08, 0.08, 3,
|
||
|
|
0.30, 0.20, 0.25,
|
||
|
|
0.30, 0.10, 3, 5, 2, 1,
|
||
|
|
1.5, 1.5, 2, 1.0,
|
||
|
|
5, 2, 2, 1, 2,
|
||
|
|
30, 2, 1
|
||
|
|
},
|
||
|
|
FeatureWeights = new double[] {
|
||
|
|
1.0, 1.5, 2.0, 0.5, 0.5, 2.0, 1.5, 0.5, 0.3,
|
||
|
|
0.5, 0.5, 0.5, 1.0, 3.0, 3.0, 2.0,
|
||
|
|
0.5, 0.5, 0.5,
|
||
|
|
1.5, 2.5, 1.5, 2.0, 1.5, 2.0,
|
||
|
|
1.0, 2.0, 2.5, 1.5,
|
||
|
|
0.5, 0.5, 1.0, 2.0, 1.5,
|
||
|
|
0.5, 1.5, 2.0
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// ─── 系统核心进程基线 (svchost, lsass 等) ───
|
||
|
|
lib.Profiles.Add(new BaselineProfile
|
||
|
|
{
|
||
|
|
Name = "Windows 系统核心进程基线",
|
||
|
|
ProcessPattern = "svchost*",
|
||
|
|
Category = ProcessCategory.SystemCore,
|
||
|
|
AnomalyThreshold = 2.2,
|
||
|
|
FeatureMeans = new double[] {
|
||
|
|
1.0, 1.0, 0.0, 45, 10, 0.99, 1.0, 1, 1,
|
||
|
|
40, 0.20, 0.40, 0.30, 0.00, 0.00, 0,
|
||
|
|
0.40, 0.15, 0.45,
|
||
|
|
0.00, 0.00, 0, 0, 0, 0,
|
||
|
|
3.0, 5.5, 0, 1.0,
|
||
|
|
5, 0, 1, 0, 0,
|
||
|
|
60, 0, 0
|
||
|
|
},
|
||
|
|
FeatureStdDevs = new double[] {
|
||
|
|
0.05, 0.05, 0.05, 20, 5, 0.05, 0.05, 0, 0.5,
|
||
|
|
15, 0.10, 0.15, 0.10, 0.02, 0.02, 1,
|
||
|
|
0.15, 0.10, 0.15,
|
||
|
|
0.05, 0.05, 1, 1, 1, 1,
|
||
|
|
1.0, 1.0, 1, 0.5,
|
||
|
|
3, 1, 1, 0, 1,
|
||
|
|
20, 1, 1
|
||
|
|
},
|
||
|
|
FeatureWeights = new double[] {
|
||
|
|
3.0, 3.0, 3.0, 0.5, 0.5, 3.0, 3.0, 0.5, 0.3,
|
||
|
|
0.5, 0.5, 0.5, 1.0, 4.0, 4.0, 3.0,
|
||
|
|
0.5, 0.5, 0.5,
|
||
|
|
3.0, 4.0, 3.0, 3.0, 3.0, 3.0,
|
||
|
|
1.5, 2.5, 3.0, 1.5,
|
||
|
|
1.0, 1.0, 1.5, 3.0, 2.0,
|
||
|
|
0.5, 3.0, 3.0
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
// ─── 浏览器基线 (Chrome/Edge/Firefox) ───
|
||
|
|
lib.Profiles.Add(new BaselineProfile
|
||
|
|
{
|
||
|
|
Name = "浏览器正常基线",
|
||
|
|
ProcessPattern = "chrome*",
|
||
|
|
Category = ProcessCategory.Browser,
|
||
|
|
AnomalyThreshold = 2.5,
|
||
|
|
FeatureMeans = new double[] {
|
||
|
|
1.0, 0.90, 0.0, 250, 30, 0.0, 0.95, 3, 4,
|
||
|
|
150, 0.15, 0.40, 0.25, 0.05, 0.03, 3,
|
||
|
|
0.60, 0.25, 0.15,
|
||
|
|
0.20, 0.05, 2, 5, 2, 0,
|
||
|
|
4.5, 7.0, 2, 2.0,
|
||
|
|
15, 0, 3, 0, 3,
|
||
|
|
80, 1, 0
|
||
|
|
},
|
||
|
|
FeatureStdDevs = new double[] {
|
||
|
|
0.10, 0.20, 0.05, 150, 20, 0.05, 0.15, 1, 3,
|
||
|
|
80, 0.10, 0.15, 0.15, 0.05, 0.05, 2,
|
||
|
|
0.20, 0.15, 0.15,
|
||
|
|
0.30, 0.10, 3, 4, 3, 1,
|
||
|
|
1.5, 1.5, 3, 1.0,
|
||
|
|
10, 1, 2, 1, 3,
|
||
|
|
40, 2, 1
|
||
|
|
},
|
||
|
|
FeatureWeights = new double[] {
|
||
|
|
0.5, 0.5, 1.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.3,
|
||
|
|
0.5, 0.5, 0.5, 0.5, 1.5, 1.5, 1.0,
|
||
|
|
0.5, 0.5, 0.5,
|
||
|
|
0.5, 1.0, 1.0, 1.5, 1.0, 1.5,
|
||
|
|
0.5, 1.0, 1.5, 0.5,
|
||
|
|
0.5, 0.5, 0.5, 1.0, 1.0,
|
||
|
|
0.5, 1.5, 2.0
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return lib;
|
||
|
|
}
|
||
|
|
}
|