Go 主机安全面试:Windows DLL 侧载与搜索顺序劫持检测
Windows 主机被入侵后,攻击者常把恶意 DLL 放到可信程序的同目录,借助 DLL 搜索顺序加载,或者替换程序会先找的依赖文件,让合法进程帮自己执行代码。面试官通常会追问:这类行为为什么难靠文件名发现?Go Agent 应该采哪些事件?怎样减少把正常安装程序、驱动更新和第三方软件误报成攻击?
岗位场景
text
Windows 主机
-> 采集进程创建、模块加载、文件创建、签名信息和哈希
-> 识别可信进程加载异常路径 DLL、同名依赖覆盖、临时目录落地和后续外联
-> 关联父子进程、安装包、解压目录、启动目录和告警抑制规则
-> 输出可解释证据,支持客户排障、误报治理和攻击链还原这类题考的是 Windows 加载器原理、进程/模块证据、规则设计、白名单边界和 Go 侧的事件标准化能力。
高频面试题
1. 什么是 DLL 侧载,为什么它常见?
简洁答案:DLL 侧载就是让一个可信程序加载到攻击者控制的 DLL,程序本身可能是正常的,但它被放在了会优先搜索的目录里,于是恶意代码借壳执行。
关键知识点:
- Windows 加载 DLL 时会按搜索顺序找目标模块。
- 同目录、当前工作目录、系统目录和 PATH 都可能参与解析。
- 攻击者喜欢利用“程序合法、路径异常”这个落差。
Go 落地思路:
- 事件里同时保留
image、loaded_module、module_path、signature、hash。 - 规则不要只看
dll文件名,要看加载它的进程和所在目录。 - 告警解释里说明“哪个可信程序从哪里加载了什么 DLL”,比只报一个文件名更有用。
2. 只看 DLL 文件名为什么不够?
简洁答案:同名 DLL 可能是正常组件,也可能是攻击者伪造的;真正关键的是加载路径、父进程、签名和文件来源。
关键知识点:
- 很多软件会带自己的私有 DLL,文件名可能很普通。
- 同名文件放在不同目录,安全含义完全不同。
- 侧载攻击常见于安装包目录、解压目录、用户写入目录和应用目录。
Go 落地思路:
- 把“名称 + 路径 + 签名”作为最小判断单元。
- 对可信软件维护路径基线,而不是维护一个巨大的文件名黑名单。
- 规则优先匹配“可信进程 + 非预期目录 + 弱签名或无签名”。
3. Windows 上哪些证据最适合发现侧载?
简洁答案:进程创建、模块加载、文件创建、签名校验和网络连接放在一起,才容易把侧载和正常依赖加载区分开。
常见证据:
| 证据来源 | 关注字段 | 检测价值 |
|---|---|---|
| 进程创建 | image、cmdline、parent_image、user | 找到可信宿主和启动来源 |
| 模块加载 | module_path、signed、publisher | 找到异常 DLL 路径 |
| 文件事件 | path、create_time、hash | 发现 DLL 落地和覆盖 |
| 网络事件 | dest_ip、dest_domain、proc | 发现侧载后的外联 |
| 签名信息 | signature_status、subject | 辅助区分官方组件和伪装文件 |
Go 落地思路:
- 采集层统一输出结构化字段,别把 ETW、Sysmon 或其他来源的细节直接暴露给规则层。
- 文件事件和模块事件要按同一
host + pid + time window关联。 - 对高频系统组件做基线缓存,减少重复计算。
4. 搜索顺序劫持和普通 DLL 依赖加载有什么区别?
简洁答案:普通依赖加载是程序设计的一部分,搜索顺序劫持则是攻击者利用加载器会先找某些目录的行为,把恶意 DLL 放进优先目录。
关键知识点:
- 依赖加载通常是显式依赖,路径和签名更稳定。
- 搜索顺序劫持更依赖目录位置,例如当前目录、可写目录或解压目录。
- 攻击者经常把文件放进和程序同目录的位置。
Go 落地思路:
- 规则判断时分开“显式私有依赖”和“通过搜索顺序找到的模块”。
- 对安装目录、临时目录、下载目录、用户可写目录做风险分层。
- 报警输出要注明“这是路径风险,不是单纯的文件名风险”。
5. 如何减少正常安装器、解压器和自动更新的误报?
简洁答案:看进程角色和上下文。安装器、更新器和解压器确实会写入 DLL,但它们通常有固定签名、固定父进程和固定工作目录。
关键知识点:
- 正常安装通常伴随可信签名、固定产品名和已知安装路径。
- 攻击链常见父进程是浏览器、Office、脚本宿主、Web 服务或用户临时会话。
- 单次命中不够,要看连续行为是否形成落地、执行和外联链路。
Go 落地思路:
- 白名单优先按
publisher + path + hash + expiry设计,不要只按文件名。 - 对压缩包解压、软件升级和补丁安装做时间窗口压制。
- 保留被压制事件的样本,方便后续回溯误报原因。
go
type ModuleEvent struct {
HostID string
PID int
ProcessImage string
ModulePath string
Signed bool
Publisher string
SHA256 string
}6. Go Agent 怎么做 DLL 侧载检测才不重?
简洁答案:先做轻量标准化和风险分层,再在规则层做少量高价值判断,不要在采集层写一堆硬编码黑名单。
关键知识点:
- 采集层只负责把模块加载、文件落地、签名和路径统一起来。
- 规则层负责判断路径是否异常、签名是否可信、是否命中已知宿主基线。
- 告警层再做去重、聚合和攻击链合并。
Go 落地思路:
- 用稳定键聚合:
host + pid + module_path + minute_bucket。 - 先过滤系统正常噪声,再对可疑路径做深一点的规则判断。
- 避免每个事件都重复做昂贵的签名查询和哈希计算。
7. 如果攻击者把恶意 DLL 伪装成系统文件名怎么办?
简洁答案:不能只看名字,要看路径、签名、哈希、父进程和加载时间。系统文件名放到用户可写目录里,通常比名字本身更值得怀疑。
关键知识点:
- 伪装名只是表象,路径才是关键。
- 可信系统文件一般在固定系统目录并有稳定签名。
- 同名不同签名、同名不同路径、同名不同发布时间都值得比较。
Go 落地思路:
- 先建立“可信目录 + 可信签名”的双条件。
- 对系统目录外出现的高仿文件名提高权重,但不要直接一票否决。
- 记录 hash 变化和首次出现时间,便于排查持久化侧载。
学习要点
- Windows DLL 搜索顺序和加载器行为。
- 进程创建、模块加载、文件创建、签名和网络事件的关联方式。
- 白名单、路径基线和时间窗口在降噪里的作用。
- Go Agent 的事件标准化、聚合、缓存和规则解释设计。
小练习
- 观察一台 Windows 机器上某个常用软件启动时加载了哪些 DLL,区分系统目录和应用目录。
- 设计一个最小规则:只在
trusted_process + user_writable_path + unsigned_module时报警。 - 想一想:如果安装器和攻击样本都写入同名 DLL,你还会用什么字段区分它们?
复盘题
- 为什么 DLL 侧载比“查一个黑名单文件名”更适合做成行为检测?
- 你会把哪些字段放进 Go 的模块事件结构体,为什么?
- 如果客户现场把某个告警判成误报,你会先看哪三个证据?
