第 49 课:检测工程:从源码提取行为特征
# 第 49 课:检测工程:从源码提取行为特征
免责声明:本专栏仅用于安全工程学习研究,禁止使用本专栏介绍的技术做其他用途,否则后果自负,与本号无关。
前面专栏已经讲了许多模块:心跳、注册表写入、插件加载、屏幕采集、音频采集、注入、驱动加载、凭据读取。本课讲如何把这些源码知识转换成企业可用的检测特征。重点不是写某一种平台的固定语法,而是建立“源码行-> 系统 API -> 数据-> 关联规则 -> 告警输出”的思路。

# 1. 新手先理解:检测不是搜索函数名
只看 RegSetValueEx、BitBlt、CreateThread 并不能直接判定风险。检测工程要做的是把多个信号组合起来,例如:
| 单点信号 | 组合后更可信 |
|---|---|
RegSetValueEx | Run + 可执行路径在用户目录 + 随后外联 |
BitBlt | 高频截图 + 压缩 + 网络发 |
VirtualAllocEx | RWX + WriteProcessMemory + 远程线程 |
CryptUnprotectData | 读取 Local State + 复制 Login Data + 外发 |
CreateService | 驱动服务 + 未知签名 + 设备 IOCTL |
# 2. 行为特征映射

| 行为类别 | 源码特征 | 数据 |
|---|---|---|
| 网络心跳 | TOKEN_HEARTBEAT 周期发 | 网络日志、EDR 网络事件 |
| 注册表写 | RegSetValueEx、RegCreateKey | Sysmon、EDR、Windows 事件 |
| 插件加载 | COMMAND_SENDLL、注册表缓存 | EDR、注册表监控、文件哈 |
| 内存执行 | PAGE_EXECUTE_READWRITE | EDR、内存遥 |
| 远程命令 | 远程终端、文件管理、系统管token | 主机进程、命令行、网络会 |
| 屏幕采集 | BitBlt、GetDIBits | API 遥测、进程行为 |
| 音频采集 | WASAPI loopback、waveInOpen | 设备访问、隐私权限事 |
| 驱动加载 | CreateService(SERVICE_KERNEL_DRIVER) | 服务日志、驱动加载日 |
| 敏感数据访问 | 浏览器数据库、DPAPI | 文件访问、API 调用、网络外 |
依赖说明: 本课把前面专栏中的库和系统接口转换成检测特征:HPSocket 对应网络心跳和包头,GDI/JPEG/zlib 对应屏幕流,WASAPI/waveIn 对应音频访问,MemoryModule/yapi 对应内存加载和跨位数调用,SQLite/OpenSSL/cJSON/base64 对应凭据读取链。规则设计时不要把库名当成唯一条件,要结合进程、数据源和时间窗口。
# 3. 心跳和协议特。
// 源码位置:主插件\HPSocket\TcpSocket.cpp,约179-195 BYTE Token = TOKEN_HEARTBEAT;
while (pThis->m_bIsRunning)
{
for (int i = 0; i < 1000; i++)
{
if (pThis->m_bIsRunning)
Sleep(10);
else
return 0;
}
pThis->Send(&Token, 1);
if (timeGetTime() - pThis->activetime > 60000)
{
if (pThis->m_bIsRunning)
pThis->Disconnect();
}
// 防御分析:约 10 秒级心跳0 秒活跃窗口、长连接特征
// 可以成为网络侧行为画像的一部分}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
检测思路
| 字段 | 说明 |
|---|---|
| 源主 | 哪台主机保持长连 |
| 目的地址 | 是否为未知公网或异常内网地址 |
| 周期 | 心跳是否稳定 |
| 包长 | 是否出现固定小包 |
| 后续行为 | 心跳后是否触发插件、注入或数据外发 |
# 4. 注册表写入特。
// 源码位置:主插件\启动管理\启动管理\StartupManager.cpp,约228-256 LONG result = RegOpenKeyEx(
HKEY_CURRENT_USER,
_T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"),
0,
KEY_WRITE,
&hKey);
result = RegSetValueEx(
hKey,
Tc_RegName,
0,
REG_SZ,
(const BYTE*)szPath,
(lstrlen(szPath) + 1) * sizeof(TCHAR));
// 防御分析:Run 项写入应与父进程、写入路径、文件签名// 后续外联做时间窗口关联?
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
规则字段建议
| 字段 | 示例含义 |
|---|---|
| RegistryKey | Run 项、服务项、策略项 |
| ValueName | 新增值名 |
| ValueData | 可执行文件路径 |
| ProcessName | 谁写 |
| User | 哪个用户上下 |
| FirstSeen | 首次出现时间 |
# 5. 插件加载特征
// 源码位置:主插件\登录模块\登录模块\LoginManager.cpp,约314-366 case COMMAND_SENDLL:
{
DllSendData* temp = new DllSendData;
::memcpy(temp, lpBuffer + 1, sizeof(DllSendData));
BYTE* pPluginDllShellcodeData = new BYTE[temp->dllDataSize];
::memcpy(
pPluginDllShellcodeData,
lpBuffer + 1 + sizeof(DllSendData),
temp->dllDataSize);
::RegSetValueEx(
hKey,
DllName,
0,
REG_BINARY,
(unsigned char*)writeregeditbuffer,
writeregeditsize);
// 防御分析:插件数据经网络进入后被缓存到注册表 // 检测应关注大块 REG_BINARY、插件名、哈希和后续线程创建}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 6. 注入和内存执行特。
// 源码位置:主插件\注入管理\注入管理\InjectManager.cpp,约970-979 LPVOID RemotlpAddress = VirtualAllocEx(
hProc,
NULL,
dwSize,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProc, RemotlpAddress, lpAddress, dwSize, NULL);
CreateRemoteThread(
hProc,
NULL,
0,
(LPTHREAD_START_ROUTINE)RemotlpAddress,
NULL,
0,
NULL);
// 防御分析:RWX 私有页、远程写入、远程线程是强组合信号// 本课只用于检测建模,不提供执行方式?
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 7. 屏幕和音频采集特。
// 源码位置:主插件\高速屏幕\高速屏幕\ScreenSpy.cpp,约100-116 BYTE algorithm = (BYTE)m_bAlgorithm;
WriteChangedBuffer((LPBYTE)&algorithm, sizeof(algorithm));
::BitBlt(
m_hLastMemDC,
0,
0,
m_nFullWidth,
m_nFullHeight,
m_hDeskTopDC,
iScreenX,
iScreenY,
m_dwBitBltRop);
// 防御分析:截API 与压缩、差异块、网络发送组合后// 可形成屏幕采集类规则?
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 源码位置:主插件\播放监听\播放监听\AudioCapture.cpp,约54-69 hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_LOOPBACK,
0,
0,
pwfx,
0);
hr = pAudioClient->Start();
// 防御分析:loopback 表示采集系统播放音频// 应结合用户授权、进程身份和网络发送判断风险?
2
3
4
5
6
7
8
9
10
11
12
# 8. 驱动加载和敏感数据访。
// 源码位置:主插件\驱动插件\驱动插件\KernrlManager.cpp,约188-215 SC_HANDLE hSCMgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
SC_HANDLE hService = CreateService(
hSCMgr,
TEXT("kernelquick"),
TEXT("kernelquick"),
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
szPath,
NULL,
NULL,
NULL,
NULL,
NULL);
StartService(hService, 0, NULL);
// 防御分析:驱动服务创建、驱动文件写出、签名异常和设备访问
// 应作为同一类高危事件处理?
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 源码位置:主插件\解密数据\解密数据\GetBrowserInfo.cpp,约441-465 DATA_BLOB dataIn = { (DWORD)encryptedKeyLength - 5, (BYTE*)(encryptedKey + 5) };
if (!CryptUnprotectData(&dataIn, NULL, NULL, NULL, NULL, 0, pDatab))
{
return false;
}
// 防御分析:非浏览器进程读Local State 后调用 DPAPI// 并访Login Data/Cookies,是凭据读取类强组合?
2
3
4
5
6
7
8
9
# 9. 数据源分。

| 数据 | 适合发现 |
|---|---|
| Sysmon | 注册表、进程、网络、驱动加载、文件创 |
| Windows 事件 | 服务创建、计划任务、登录、驱动签名问 |
| EDR | 线程、内存、句柄、模块、API |
| NDR | 东西向流量、协议异常、扫描模 |
| 防火 | 内网连接允许/拒绝 |
| DNS | 内部主机名解析异 |
| 代理日志 | 外联、隧道、目的域 |
| SIEM | 多源关联和告警分 |
# 10. 规则关联流程

一条规则可以按以下方式设计
| 步骤 | 说明 |
|---|---|
| 采集 | 收集主机、网络、身份、资产事 |
| 标准 | 统一字段:主机、进程、用户、目标、时 |
| 关联 | 在时间窗口内连接多个信号 |
| 分级 | 按资产重要性、行为组合、用户身份打 |
| 输出 | 给出可操作的处置建议 |
示例检测模型:
| 模型 | 条件 |
|---|---|
| 注入 | 同一源进程对同一目标进程出现打开句柄、远程写入、远程线程 |
| 凭据读取 | 非浏览器进程读取 Local State,复制 Login Data,调用 DPAPI |
| 持久化链 | Run 项或服务创建后,短时间出现外联 |
| 横向连接 | 普通终端短时间访问多个内网端口并回传数据 |
| 驱动 | 新驱动服务创建、驱动加载、未知设备 IOCTL |
# 11. 具体规则样例
下面把第 39-41 课的源码知识转换成更具体的规则模型。仍然不绑定平台语法,便于迁移到 Sysmon、EDR、SIEM NDR。 规则一:插件缓存和加载
| 字段 | 条件 |
|---|---|
| 主体 | 同一进程或同一会话 |
| 时间窗口 | 5 分钟 |
| 条件 1 | 建立长连接或出现稳定心跳 |
| 条件 2 | 写入大块 REG_BINARY 或创建插件相关缓存 |
| 条件 3 | 随后创建线程、加载模块、出现新的功能 token 行为 |
| 输出 | 标记为“疑似远程插件下发和缓存 |
规则二:凭据读取
| 字段 | 条件 |
|---|---|
| 主体 | 非浏览器进程 |
| 条件 1 | 访问 Local State、Login Data 或 Cookies |
| 条件 2 | 调用 CryptUnprotectData AES-GCM 相关解密函数 |
| 条件 3 | 1 分钟内出现网络发送或结果格式化 |
| 输出 | 标记为“疑似浏览器凭据读取 |
规则三:屏幕视频流链
| 字段 | 条件 |
|---|---|
| 主体 | 非会议、非远程协助白名单进 |
| 条件 1 | 调用 BitBlt、GetDIBits、PrintWindow 之一 |
| 条件 2 | 同进程出JPEG/zlib/x264/libyuv 相关调用 |
| 条件 3 | 持续上行或固定帧率网络发 |
| 输出 | 标记为“疑似未授权屏幕采集 |
告警说明建议包含可操作字段:
触发原因:同一进程5 分钟内出现网络长连接、注册表大块二进制写入和线程创建证据字段:进程路径、签名、目的地址、注册表键、值名、数据大小、线程创建时间排除建议:核对是否为企业远程运维代理,是否有工单、签名、资产登记和用户提示处置建议:隔离主机,保全注册表值,导出进程树,检查是否存在插件加载和敏感数据访问?
2
# 12. 检测调优闭。

| 阶段 | 目标 |
|---|---|
| 提取源码特征 | 找到 API、路径、token、协议字 |
| 写初版规则 | 覆盖高风险组合 |
| 回放样本日志 | 验证规则能命 |
| 标注误报来源 | 找合法软件和正常运维场景 |
| 收紧条件 | 加入父进程、签名、资产标签、时间窗 |
| 沉淀说明 | SOC 知道为什么告警、怎么处理 |
# 13. 合法练习:
选择任意 3 个模块,分别提取 API、文件路径、注册表路径、token?
写一条凭据读取链检测模型,不写平台语法,只写字段和关联条件?
给“高频截+ 网络发送”设计误报来源列表,例如会议软件、远程协助软件、录屏软件?
设计一个规则说明模板:名称、风险、数据源、字段、触发条件、误报来源、处置建议。
安全工程知识交流加wx:easy_coder,黑灰产勿扰,企业单位合作请出示有效证件。
本留言区仅对应当前文章,欢迎补充观点、提出问题或帮助修正文中疏漏。 留言由 GitHub/Gitalk 提供,需要使用 GitHub 登录。
社区交流
讨论与留言