edgecasehuman/procdrift
GitHub: edgecasehuman/procdrift
一款单文件、零依赖的 Windows 进程漂移检测器,通过路径级快照对比来回答「这台机器上现在多跑了哪些程序」。
Stars: 1 | Forks: 0
# ProcDrift
[](https://github.com/edgecasehuman/procdrift/actions/workflows/ci.yml)
[](https://github.com/edgecasehuman/procdrift/actions/workflows/audit.yml)
[](LICENSE)
一个单一可执行文件的 Windows 进程监视器,旨在回答一个问题:**现在运行着哪些在这台机器处于已知良好状态时并未运行的程序?**
Task Manager 告诉你正在运行什么。Autoruns 告诉你配置了哪些开机启动项。两者都没告诉你*变化*了什么。ProcDrift 会记录其能检测到的每个可执行文件路径的参考快照,然后将后续的每次扫描显示为与该快照的差异。
一个单一可执行文件,体积不到半兆:只有一个桌面窗口,没有控制台,无需安装。没有服务,没有驱动,没有遥测,没有网络访问,没有后台进程。关闭它之后,不会留下任何运行中的痕迹。
## 它展示的内容
信任度和发现结果是分开的,因为它们回答的是不同的问题。
**Trust (信任度)** 是指该可执行文件相对于你的快照所处的状态:
| Trust | 含义 |
|---|---|
| Protected | Windows 关键进程。ProcDrift 拒绝对其执行任何操作,因为结束它会导致机器停机。 |
| Allowed | 其确切路径存在于你的参考快照中 |
| Known | Windows 自带的程序,ProcDrift 可以描述它,但它不在你的快照中 |
| Unclassified | 除了本次扫描观察到的情况外,对此一无所知 |
`Protected` 声明的是 ProcDrift 会采取什么操作,而不是判断该进程是否为良性。
**Findings (发现)** 是指当前关于该进程的真实情况:
| Finding | 含义 |
|---|---|
| New | 不存在于参考快照中 |
| Different path | 该名称曾在不同的路径下被观察到 |
| Starts automatically | 存在与该可执行文件完全对应的开机启动项 |
| Parent ended | 启动它的父进程已不再运行 |
| Restarting | 在两分钟内至少启动了三次 |
| Peer outlier | 比同类的其他实例消耗更多资源 |
| Many instances | 正在运行多个同类的实例 |
| Known parent | 由快照中匹配的进程启动 |
| Heavy CPU / memory / disk | 目前位列前五的资源消耗大户 |
值得采取行动的组合是 **New + Starts automatically**:某些不在你的基线中、但在重启后依然会存在的东西。ProcDrift 会将其排在最前面。
Findings 被表述为观察结果,而不是定性判断。这里没有任何内容会说“恶意”或“威胁”,因为进程监视器无法知晓这一点,而硬要这么说,正是这些工具让人们逐渐无视它们的原因。
## Authenticode
选中一个进程会离线验证其签名:首先检查安全目录(这是大多数 Windows 系统二进制文件的签名方式 —— 仅检查内嵌签名会将一台干净的机器大部分报告为“未签名”),然后是内嵌签名。其结果会区分 **Unsigned**(完全没有签名)和 **Invalid**(存在签名但未通过验证),因为将这两者混为一谈会丢失唯一真正值得关注的案例。默认关闭了吊销检查,并且 URL 检索仅限于缓存,因此选中某一行永远不会因网络原因而阻塞。
## 安装
从 [Releases] 下载 `ProcDrift.exe` 并运行。这就是安装的全部过程。
状态数据会被写入 `%LOCALAPPDATA%\ProcDrift\state.json`,并且仅在你回应首次运行提示、捕获快照或更改允许项之后才会写入。写入是原子操作。不会基于定时器进行任何写入。
### 关于 SmartScreen
发布的二进制文件是未签名的。在特定构建版本积累足够信誉之前,Windows SmartScreen 会在首次运行时发出警告。如果你需要确定性,请根据发布说明验证其 SHA-256,或者直接从本仓库自行构建。
ProcDrift 绝不会要求你添加 Defender 排除项。如果一个工具提出此要求,它实际上是在要求你仅凭它的一面之词降低你自身的安全防护。
## 使用说明
1. 在你认为干净的机器上运行它,然后选择 **Record all**。
2. 过段时间再回来查看。**Review** 过滤器会显示不匹配的项目。
3. **Allow** 会将特定的可执行文件路径标记为预期项。允许项是基于路径的,而不是基于名称,因此具有熟悉名称的不同二进制文件不会被盲目信任。
键盘快捷键:`F5` 刷新,`Ctrl+F` 或 `Ctrl+K` 搜索,`Ctrl+C` 复制选中行,`Enter` 查看详情,`Space` 切换挂起状态,`F2` 允许选中的路径,`Delete` 结束进程,`Escape` 清除搜索。点击列标题进行排序。
进程控制(挂起、恢复、结束、结束捕获的进程树)仅对选定的进程执行,并会重新检查进程身份,因此不会错误地操作被复用的 PID。
## 设计约束
这些是有意为之的设计,而非缺失的功能:
- 一个进程,一个窗口,每次可见刷新只进行一次进程枚举。
- 最小化时定时器会停止。
- 如果内核查询失败,屏幕上会保留最后的有效表格,而不是清空内容。
- 启动项索引只构建一次,而不是每次刷新都构建,因为它需要读取数百个注册表项。
- 签名验证在工作线程中运行,绝不在 UI 线程中运行。
没有历史数据库,没有图形化,没有在线查询,没有套接字普查,也没有定期的文件写入操作。
## 构建
需要 rustup 和 Visual Studio Build Tools。编译器版本固定在 `rust-toolchain.toml` 中,并在首次执行 `cargo` 命令时自行安装。该 crate 也可以在 Rust 1.88 及更高版本上构建,这已由 CI 单独验证。
```
cargo build --locked --release
```
生成的二进制文件是 `target/release/ProcDrift.exe`,这就是完整的应用程序。
```
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked
```
某些测试会特意测试真实的运行环境:目录验证会针对真实的 `kernel32.dll` 进行检查,并且断言启动项索引不为空。这两者一旦失败都会产生明显的报错,而不是静默地返回无结果。
## 安全性
该工具会结束和挂起进程,并报告 Authenticode 结果,因此其信任边界已在 [SECURITY.md](SECURITY.md) 中明确记录 —— 包括 `Trusted` 判定*不代表*什么,以及出于设计考虑默认关闭了吊销检查。请通过仓库的 Security 标签页私下报告漏洞,切勿作为公开 issue 提交。
## 贡献
[CONTRIBUTING.md](CONTRIBUTING.md) 涵盖了构建过程、CI 强制执行的四道关卡,以及本项目刻意不做的事情列表。参与本项目受 [行为准则](CODE_OF_CONDUCT.md) 约束。
## 许可证
MIT。详见 [LICENSE](LICENSE)。
标签:Rust, 可视化界面, 桌面应用, 端点可见性, 系统工具, 网络流量审计, 通知系统, 配置漂移