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

238 lines
8.8 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.Linq;
using MemScanEDR.Models;
namespace MemScanEDR.Services;
/// <summary>
/// 监督学习分类引擎 —— 第二层检测
/// 使用轻量级加权特征分类器,模拟训练好的监督模型的推理行为
/// 不依赖深度学习框架,纯 C# 实现,适合终端 EDR 部署
///
/// 分类逻辑基于:
/// 1. 特征加权评分(模拟训练好的线性模型权重)
/// 2. 特征组合规则(模拟决策树的关键分支)
/// 3. 已知恶意模式匹配
/// </summary>
public class ClassificationEngine
{
// ─── 特征权重(从训练数据中学习到的权重,模拟线性分类器)───
// 正权重 = 该特征越高越可疑,负权重 = 正常特征
private static readonly double[] FeatureWeights = new double[]
{
// 进程元数据
-2.0, -1.5, 3.0, 0.1, 0.1, 2.5, -2.0, 0.1, 0.0,
// 内存页权限RWX 相关权重极高)
0.1, -0.5, -0.3, -1.0, 4.0, 3.5, 2.5,
// 内存类型
-0.5, -0.3, -1.0,
// 代码特征
1.5, 4.0, 2.0, 2.5, 1.5, 2.0,
// 熵特征
1.0, 2.5, 2.0, 1.0,
// 网络特征
0.5, 0.3, 1.0, 2.5, 1.5,
// DLL加载
0.2, 2.0, 2.5
};
// 分类阈值
private const double HighRiskThreshold = 0.70;
private const double SuspiciousThreshold = 0.40;
/// <summary>
/// 对特征向量进行分类
/// </summary>
public ClassificationResult Classify(MemoryFeatures features)
{
var result = new ClassificationResult();
var vector = features.ToFeatureVector();
// ─── 1. 线性加权评分 ───
double weightedScore = 0;
double maxPossibleScore = 0;
var topContributors = new List<(int index, double contribution)>();
for (int i = 0; i < Math.Min(vector.Length, FeatureWeights.Length); i++)
{
var contribution = vector[i] * FeatureWeights[i];
weightedScore += contribution;
if (FeatureWeights[i] > 0)
maxPossibleScore += Math.Abs(FeatureWeights[i]);
if (Math.Abs(contribution) > 0.5)
topContributors.Add((i, contribution));
}
// 归一化到 [0, 1]
var normalizedScore = maxPossibleScore > 0
? Math.Max(0, weightedScore) / (maxPossibleScore * 0.5)
: 0;
normalizedScore = Math.Min(normalizedScore, 1.0);
// ─── 2. 决策树规则增强 ───
var ruleBoost = ApplyDecisionRules(features);
// 综合得分
var finalScore = normalizedScore * 0.7 + ruleBoost * 0.3;
finalScore = Math.Min(finalScore, 1.0);
result.RawScore = normalizedScore;
result.RuleBoost = ruleBoost;
result.FinalScore = finalScore;
// ─── 3. 分类判定 ───
result.Classification = finalScore switch
{
>= HighRiskThreshold => MalwareClass.Malicious,
>= SuspiciousThreshold => MalwareClass.Suspicious,
_ => MalwareClass.Benign
};
// ─── 4. 恶意家族推测 ───
result.SuspectedFamily = InferMalwareFamily(features);
// ─── 5. 关键特征贡献 ───
result.TopContributors = topContributors
.OrderByDescending(c => Math.Abs(c.contribution))
.Take(5)
.Select(c => (GetFeatureName(c.index), c.contribution))
.ToList();
return result;
}
/// <summary>
/// 决策树规则 —— 模拟关键分支逻辑
/// </summary>
private static double ApplyDecisionRules(MemoryFeatures f)
{
double boost = 0;
// 规则1: 系统进程 + RWX私有页 = 极高风险 (代码注入核心特征)
if (f.IsSystemProcessName && f.RwxPrivatePages > 0)
boost += 0.40;
// 规则2: 未签名 + 临时路径 + RWX = 高风险
if (!f.IsSigned && f.IsTempPath && f.RwxPrivatePages > 0)
boost += 0.30;
// 规则3: Process Hollowing = 立即高风险
if (f.PeMismatchDisk)
boost += 0.50;
// 规则4: 高熵 + 无磁盘映射可执行页 = 加密载荷
if (f.MaxEntropy > 7.0 && f.AnonymousExecPages > 0 && f.ImagePages == 0)
boost += 0.35;
// 规则5: 签名匹配 + 网络C2端口 = 远控木马
if (f.HighSeverityMatches > 0 && f.SuspiciousPortConnections > 0)
boost += 0.35;
// 规则6: 系统进程名 + 非系统路径 = 进程伪装
if (f.IsSystemProcessName && !f.IsSystemPath)
boost += 0.25;
// 规则7: 可疑API多 + 网络连接 = 可能C2
if (f.SuspiciousApiStrings.Count >= 3 && f.ConnectionCount > 0)
boost += 0.20;
// 规则8: 境外连接 + 非标准端口 + 高熵 = 数据外泄
if (f.ForeignConnections > 0 && f.NonStandardPortConnections > 0 && f.MaxEntropy > 7.0)
boost += 0.25;
// 规则9: 无磁盘模块 + 临时路径模块
if (f.UnmappedModules > 0 && f.TempPathModules > 0)
boost += 0.20;
return Math.Min(boost, 0.60);
}
/// <summary>
/// 推测恶意软件家族
/// </summary>
private static string InferMalwareFamily(MemoryFeatures features)
{
var indicators = new List<string>();
// CobaltStrike
if (features.SuspiciousStrings.Any(s => s.Contains("beacon", StringComparison.OrdinalIgnoreCase)))
indicators.Add("CobaltStrike Beacon");
// Meterpreter
if (features.SuspiciousStrings.Any(s => s.Contains("meterpreter", StringComparison.OrdinalIgnoreCase)))
indicators.Add("Metasploit Meterpreter");
// Mimikatz
if (features.SuspiciousStrings.Any(s => s.Contains("mimikatz", StringComparison.OrdinalIgnoreCase)) ||
features.SuspiciousApiStrings.Any(a => a.Contains("MiniDump", StringComparison.OrdinalIgnoreCase)))
indicators.Add("凭证窃取工具 (Mimikatz)");
// Process Hollowing
if (features.PeMismatchDisk)
indicators.Add("Process Hollowing");
// Ransomware
if (features.SuspiciousStrings.Any(s => s.Contains("ENCRYPTED", StringComparison.OrdinalIgnoreCase) ||
s.Contains("ransom", StringComparison.OrdinalIgnoreCase)))
indicators.Add("勒索软件");
// Crypto Miner
if (features.SuspiciousStrings.Any(s => s.Contains("stratum", StringComparison.OrdinalIgnoreCase) ||
s.Contains("cryptonight", StringComparison.OrdinalIgnoreCase) ||
s.Contains("coinmine", StringComparison.OrdinalIgnoreCase)))
indicators.Add("挖矿木马");
// RAT
if (features.SuspiciousApiStrings.Count >= 3 && features.ForeignConnections > 0 &&
features.SuspiciousPortConnections > 0)
indicators.Add("远控木马 (RAT)");
// Reflective DLL Injection
if (features.AnonymousExecPages > 0 && features.RwxPrivatePages > 0 &&
features.SuspiciousApiStrings.Any(a => a.Contains("Reflective", StringComparison.OrdinalIgnoreCase)))
indicators.Add("反射DLL注入木马");
// Bootkit/Rootkit
if (features.IsSystemProcessName && !features.IsSystemPath && features.RwxPrivatePages > 0)
indicators.Add("Rootkit/伪装系统进程");
return indicators.Count > 0 ? string.Join(" | ", indicators) : "未知恶意家族";
}
private static string GetFeatureName(int index) => index switch
{
0 => "未签名", 1 => "非系统路径", 2 => "临时路径",
3 => "内存占用", 4 => "线程数", 5 => "系统进程名", 6 => "父进程异常",
12 => "RWX页比例", 13 => "匿名可执行页", 14 => "RWX私有页",
18 => "内存PE头", 19 => "PE与磁盘不一致",
20 => "可疑API", 21 => "敏感字符串", 22 => "签名匹配", 23 => "高危签名",
24 => "高熵代码段", 25 => "最大熵值", 26 => "高熵区域数",
29 => "非标准端口", 30 => "可疑端口", 31 => "境外连接",
35 => "无磁盘模块", 36 => "临时目录模块",
_ => $"特征{index}"
};
}
/// <summary>
/// 分类引擎结果
/// </summary>
public class ClassificationResult
{
public MalwareClass Classification { get; set; } = MalwareClass.Benign;
public double RawScore { get; set; }
public double RuleBoost { get; set; }
public double FinalScore { get; set; }
public string SuspectedFamily { get; set; } = "";
public List<(string featureName, double contribution)> TopContributors { get; set; } = new();
}
public enum MalwareClass
{
Benign,
Suspicious,
Malicious
}