enkomio/argus
GitHub: enkomio/argus
Argus 是一款面向恶意软件分析的 Windows 网络流量拦截工具,通过伪造 HTTP/HTTPS、DNS、SMTP、POP3 响应来诱骗恶意软件暴露其行为。
Stars: 5 | Forks: 0
# Argus
///` 目录下
- **可自定义的虚假响应** — 将文件放入 `default_files/` 目录即可根据路径提供自定义内容;如果目录或文件缺失,则使用内置回退
## 用法
Argus 需要提权终端或 UAC 提示(内嵌的清单会自动请求 `requireAdministrator`)。
```
# 使用默认 config 运行
argus.exe
# 自定义 config 文件
argus.exe -c configs\default.ini
# 详细 / debug 日志记录
argus.exe -v
# 将 listener 绑定到特定地址
argus.exe -b 0.0.0.0
# 将日志输出写入文件
argus.exe -l argus.log
# 覆盖 capture 目录 (默认: capture\)
argus.exe --log-dir D:\analysis\run1
# 列出可用的 listener 类型
argus.exe --list-listeners
```
## 配置
编辑 `configs\default.ini` 以启用/禁用监听器并自定义响应。
### 全局选项
```
[Argus]
DivertTraffic: Yes # Enable WinDivert automatic traffic redirection
```
### 监听器配置参考
每个监听器部分(除 `[Argus]` 外)都接受以下键:
| 键 | 必需 | 适用于 | 描述 | 示例值 |
|-----|----------|------------|-------------|----------------|
| `Listener` | ✅ | 所有 | 要使用的监听器类型 | `HTTPListener`, `DNSListener`, `SMTPListener`, `POPListener`, `RawListener` |
| `Enabled` | ✅ | 所有 | 是否启动此监听器 | `True`, `False` |
| `ServicePort` | ✅ | 所有 | WinDivert 拦截的端口(发往此端口的流量将被捕获) | `80`, `443`, `53`, `25` |
| `ListenerPort` | ✖️ | 所有 | Argus 实际在本地绑定的端口。省略时默认为 `ServicePort` | `18080`, `18443`, `10053` |
| `Protocol` | ✖️ | 所有 | 传输协议。默认:`TCP` | `TCP`, `UDP` |
| `UseSSL` | ✖️ | HTTP | 启用 TLS 终止 (HTTPS MITM)。默认:`No` | `Yes`, `No` |
| `Timeout` | ✖️ | 所有 | 空闲连接超时时间(秒)。默认:`10` | `5`, `10`, `30` |
| `Banner` | ✖️ | SMTP, POP3 | 连接时发送给客户端的问候语 | `220 mail.example.com ESMTP`, `+OK POP3 ready` |
| `ResponseA` | ✖️ | DNS | 针对 **A** 查询返回的 IP 地址 | `127.0.0.1`, `192.168.1.1` |
| `ResponseMX` | ✖️ | DNS | 针对 **MX** 查询返回的主机名 | `mail.argus.local` |
| `ResponseTXT` | ✖️ | DNS | 针对 **TXT** 查询返回的字符串 | `v=spf1 -all`, `ARGUS` |
| `Passthrough` | ✖️ | 所有 | 逗号分隔的进程 / IP / 域名列表,这些流量将透传到真实目的地而不被拦截。参见 [选择性透传](#selective-passthrough) | `curl.exe`, `93.184.216.34`, `.*\.microsoft\.com` |
| `NoLog` | ✖️ | 所有 | 逗号分隔的进程 / IP / 域名列表,其流量**不**写入捕获文件。条目格式与 `Passthrough` 相同 | `analytics\.example\.com`, `telemetry\.microsoft\.com` |
| `ForwardTo` | ✖️ | 所有 | 外部 TCP endpoint 的 `IP:PORT`,可在处理每个请求和响应之前对其进行检查和修改。参见 [ForwardTo](#forwardto--external-traffic-modifier) | `127.0.0.1:9999` |
### 选择性透传
`Passthrough` 键接受逗号分隔的条目列表。当匹配到**任意**条目时,连接将透传到真实目的地。支持的条目类型:
| 条目类型 | 示例 | 匹配目标 |
|--------------|--------------------------------------|------------------------------|
| 进程名 | `curl.exe`, `curl.*` | 发起进程名 |
| PID | `1234` | 发起进程 PID |
| IPv4 地址 | `93.184.216.34` | 原始目标 IP |
| IPv6 地址 | `2606:2800:220:1:248:1893:25c8:1946` | 原始目标 IP |
| 域名 | `example.com`, `.*\.microsoft\.com` | HTTP `Host` / DNS 查询名 |
| 域名+路径 | `example.com/api/v1` | HTTP `Host` + URI 前缀 |
| URL | `http://example.com/path` | 去除 scheme 后,按上述规则匹配 |
**进程名和域名/URL 条目被视为不区分大小写的正则表达式**,并在开头进行匹配锚定 (`^`)。像 `curl.exe` 这样的普通名称仍然有效——正则表达式中的 `.` 可以匹配任意字符,这在实际使用中是无害的。使用 `curl\.exe` 可以精确匹配字面量点号。
```
# Pass through 任何名称以 "curl" 开头的进程
Passthrough: curl.*
# Pass through 任何 Microsoft 域名的 DNS 查询
Passthrough: .*\.microsoft\.com
# 仅 Pass through 指定 path 的请求
Passthrough: updates\.vendor\.com/v2/check
# 混合多种 entry 类型
Passthrough: malware_loader.exe, 93.184.216.34, c2\.evil\.io
```
当 HTTP 连接被透传时:
- **阶段 1**(读取数据前):检查 PID、进程名和 IP 条目。如果匹配,原始 TCP 流将被透明代理 (`copy_bidirectional`)。
- **阶段 2**(读取 HTTP 标头后):根据 `Host` 标头和 URI 检查域名和 URL 条目。已读取的请求数据字节将重放给真实服务器,然后再代理其余部分。
Argus 自身的出站连接(在透传期间创建的连接)会自动排除在 WinDivert 拦截之外,以防止重定向循环。
### 选择性日志抑制
`NoLog` 键使用与 `Passthrough` 相同的条目格式。匹配的连接不会写入捕获文件(它们仍会以 `info` 级别记录到控制台/日志文件中)。
```
NoLog: analytics\.example\.com, telemetry\.microsoft\.com
```
### 监听器示例 — HTTP / HTTPS
```
[HTTPListener]
Enabled: True
Listener: HTTPListener
ServicePort: 80
ListenerPort: 18080
Protocol: TCP
UseSSL: No
Timeout: 10
[HTTPSListener]
Enabled: True
Listener: HTTPListener
ServicePort: 443
ListenerPort: 18443
Protocol: TCP
UseSSL: Yes
Timeout: 10
# 可选:将匹配的连接 Pass through 到真实目的地。
# Passthrough: curl.exe, 1234, 93.184.216.34, example\.com, http://evil\.com/payload
# 可选:禁止为匹配的连接生成 capture 文件。
# NoLog: curl.exe, 1234, 93.184.216.34, analytics\.example\.com
```
### 监听器示例 — DNS
```
[DNSListener]
Enabled: True
Listener: DNSListener
ServicePort: 53
ListenerPort: 10053
Protocol: UDP
ResponseA: 127.0.0.1 # IP returned for A queries
ResponseMX: mail.argus.local
ResponseTXT: ARGUS
# 可选:将匹配的查询转发到真实的 DNS 服务器。
# Passthrough: curl.exe, 1234, 93.184.216.34, example.com, .*\.microsoft\.com
# 可选:禁止为匹配的查询生成 capture 文件。
# NoLog: curl.exe, 1234, 93.184.216.34, analytics\.example\.com
```
支持的记录类型:`A`、`AAAA`(返回 `::1`)、`MX`、`TXT`。任何其他查询类型都会收到 `A` 记录回退响应。
### 监听器示例 — SMTP / POP3
```
[SMTPListener]
Enabled: True
Listener: SMTPListener
ServicePort: 25
ListenerPort: 10025
Protocol: TCP
Banner: 220 argus.local SMTP Service Ready
[POPListener]
Enabled: True
Listener: POPListener
ServicePort: 110
ListenerPort: 10110
Protocol: TCP
Banner: +OK Argus POP3 Server Ready
```
每个监听器都会记录凭据 (USER/PASS) 和协议命令,并回复看似合理的成功响应,以保持恶意软件继续运行。
### 监听器示例 — 原始 TCP/UDP
```
[RawTCPListener]
Enabled: True
Listener: RawListener
ServicePort: 1337
ListenerPort: 11337
Protocol: TCP
Timeout: 5
[RawUDPListener]
Enabled: True
Listener: RawListener
ServicePort: 1338
ListenerPort: 11338
Protocol: UDP
Timeout: 5
```
接受任何流量,将其回显,并记录每个数据包最多 256 字节的十六进制转储。用作没有专用监听器的端口的默认兜底方案。
## 自定义虚假 HTTP 响应
HTTP 监听器会先在 `default_files/` 目录中查找文件,如果找不到,再回退到内置响应。
每个传入请求的解析顺序:
| 优先级 | 尝试路径 | `GET /login.html` 的示例 |
|----------|-----------|-------------------------------|
| 1 | `default_files/{uri}` | `default_files/login.html` |
| 2 | `default_files/index.html` | 通用 HTML 回退 |
| 3 | 内置常量 | 始终可用 |
将任意文件放入 `default_files/` 目录中,当 URI 匹配时它将自动提供服务。URI 路径在使用前会经过清理(去除开头的 `/`,移除 `..` 组件)以防止目录遍历。
```
default_files/
├── index.html ← served for "/" and any unmatched HTML request
├── login.html ← served for "/login.html"
├── api/
│ └── status.json ← served for "/api/status.json"
└── update.exe ← served for "/update.exe"
```
## HTTPS 拦截 (MITM)
首次运行时,Argus 会在 `configs/` 目录中生成一个 CA 密钥对:
```
configs/
├── argus-ca.crt ← install this in Windows Certificate Store (Trusted Root CAs)
└── argus-ca.key ← private key — keep secret
```
对于每个 TLS 连接,Argus 都会动态生成一个由 CA 签名、针对所请求主机名的叶子证书。一旦操作系统信任了该 CA,浏览器和 HTTP 客户端就会毫无错误地接受这些叶子证书。
**在 Windows 上安装 CA:**
```
certutil -addstore -f "Root" configs\argus-ca.crt
```
**移除 CA:**
```
certmgr.msc → Trusted Root Certification Authorities → Certificates → right-click "Argus CA" → Delete
```
CA 证书将在一年后过期。如果加载的 CA 已过期,Argus 会在启动时发出警告。
## ForwardTo — 外部流量修改器
`ForwardTo` 键允许你通过外部 TCP endpoint 路由每个被拦截的请求和响应,然后再由 Argus 处理或返回。该 endpoint 可以检查并修改字节数据;无论它返回什么,都会被用来替代原始 payload。如果 endpoint 无法访问或返回错误,Argus 将回退到原始 payload —— 流量绝不会被丢弃。
### 通信协议
```
Argus → endpoint:
[4 bytes BE uint32] length of JSON metadata header
[N bytes UTF-8] JSON metadata
[4 bytes BE uint32] length of raw payload
[M bytes] raw payload
endpoint → Argus:
[4 bytes BE uint32] length of (possibly modified) payload
[K bytes] payload to use in place of the original
```
**JSON 元数据字段:**
| 字段 | 类型 | 描述 |
|--------------|--------|------------------------------------------------------|
| `request_id` | number | 请求及其关联响应共享的唯一 ID,用于关联 |
| `direction`| string | `"request"` 或 `"response"` |
| `protocol` | string | `"http"`, `"https"`, `"dns"`, `"smtp"`, `"pop3"`, `"raw"` |
| `src_ip` | string | 客户端源 IP |
| `src_port` | number | 客户端源端口 |
| `dst_ip` | string | 原始目标 IP (在 WinDivert 拦截之前) |
| `dst_port` | number | 原始目标端口 |
| `process` | string | 发起可执行文件名 (例如 `"malware.exe"`) |
| `pid` | number | 发起 PID (`0` = 未知) |
### 配置
将 `ForwardTo` 添加到 `configs\default.ini` 中的任意监听器部分:
```
[HTTPListener]
Enabled: True
Listener: HTTPListener
ServicePort: 80
ListenerPort: 18080
Protocol: TCP
ForwardTo: 127.0.0.1:9999
[DNSListener]
Enabled: True
Listener: DNSListener
ServicePort: 53
ListenerPort: 10053
Protocol: UDP
ForwardTo: 127.0.0.1:9999
```
多个监听器可以指向同一个 endpoint,或者各自指向不同的 endpoint。
### 运行示例 Python 转发器
`python/example_interceptor.py` 中提供了一个即开即用的示例。它不需要外部依赖(仅使用标准库)。
**终端 1 — 首先启动转发器:**
```
cd python
python example_interceptor.py # listens on 0.0.0.0:9999
python example_interceptor.py --port 8888 # custom port
python example_interceptor.py --debug # verbose output
```
**终端 2 — 启动 Argus(需提权):**
```
argus.exe -c configs\default.ini
```
**预期输出(拦截器终端):**
```
12:34:01 INFO Argus interceptor listening on 0.0.0.0:9999
12:34:01 INFO Handling protocols: http, https, dns, smtp, raw
12:34:01 INFO Add 'ForwardTo: 127.0.0.1:9999' to any listener in configs/default.ini
12:34:01 INFO ────────────────────────────────────────────────────────────
12:34:45 INFO [HTTP req] malware.exe → GET /c2/beacon
12:34:45 INFO [HTTP rsp] 200 OK (1024 bytes) title tag patched
12:34:46 INFO [DNS req] malware.exe → A evil-c2.example.com
12:34:46 INFO [DNS rsp] evil-c2.example.com A TTL=60 127.0.0.1
```
### Python 库 (`argus_interceptor`)
`python/argus_interceptor.py` 是一个零依赖库,用于处理所有 socket 帧。只需实现你需要的处理程序:
```
from argus_interceptor import (
create_interceptor,
http_request, http_response,
dns_message,
smtp_response, smtp_command,
)
def handle_http(meta, payload):
if meta.direction == "response":
resp = http_response(payload)
resp.body = resp.body.replace(b"foo", b"bar")
return resp.to_bytes() # Content-Length auto-updated
return payload
def handle_dns(meta, payload):
msg = dns_message(payload)
for q in msg.questions:
print(f"{q.type_name} query for {q.name}")
return payload
interceptor = create_interceptor(
http_handler=handle_http,
https_handler=handle_http,
dns_handler=handle_dns,
)
interceptor.serve()
```
**内置协议解析器:**
| 函数 | 返回值 | 关键字段 |
|---|---|---|
| `http_request(payload)` | `HttpRequest` | `.method`, `.path`, `.headers`, `.body` |
| `http_response(payload)` | `HttpResponse` | `.status_code`, `.status_text`, `.headers`, `.body` |
| `dns_message(payload)` | `DnsMessage` | `.questions`, `.answers`, `.is_query`, `.rcode` |
| `smtp_response(payload)` | `SmtpResponse` | `.code`, `.lines` |
| `smtp_command(payload)` | `SmtpCommand` | `.command`, `.args` |
`Headers` 是一个不区分大小写的字典;`HttpRequest.to_bytes()` 和 `HttpResponse.to_bytes()` 会重建原始消息并自动更新 `Content-Length`。
`DnsRecord.address` 返回 A/AAAA 录的解码 IP;`DnsRecord.text` 返回 TXT 记录的解码字符串。`DnsMessage.to_bytes()` 重新序列化 DNS 线传输格式。
拦截器也可以使用任何其他语言实现 —— 该通信协议是与语言无关的(参见上文通信格式)。ForwardTo 会针对**被拦截和**透传的连接调用,因此无论 Argus 是在返回虚假响应还是在代理到真实服务器,该 endpoint 都能看到所有流量。
## 请求/响应捕获
每个被拦截的事务都会保存到磁盘。目录结构如下:
```
capture/
└── /
└── /
└── /
├── 20260515_143201_0001_req.log
├── 20260515_143201_0001_rsp.log
├── 20260515_143205_0002_req.log
└── ...
```
- **``** — 经过清理的可执行文件名(例如 `malware.exe`)
- **``** — 数字 PID;如果进程重启,则会创建一个新的子目录
- **``** — `http`, `https`, `smtp`, `pop`, `dns`, `raw`
- **文件名** — `___.log`,其中 `NNNN` 是每个 PID 的事务计数器
默认捕获目录是相对于工作目录的 `capture\`。使用 `--log-dir` 覆盖。
## 监听器
| 监听器 | 端口 | 协议 | 描述 |
|---------------|-------|----------|-----------------------------------------------------|
| HTTPListener | 80 | TCP | HTTP — 提供虚假 HTML/文件,匹配时透传 |
| HTTPSListener | 443 | TCP | HTTPS — 基于主机的 MITM 证书,解密捕获 |
| DNSListener | 53 | UDP | DNS — 可配置的 A/AAAA/MX/TXT,透传 |
| SMTPListener | 25 | TCP | 发送电子邮件 — 记录凭据和邮件正文 |
| POPListener | 110 | TCP | POP3 接收电子邮件 — 记录凭据 |
| RawListener | any | TCP/UDP | 兜底 — 十六进制转储日志,回显响应 |
## 构建
### 前置条件
- Windows 10/11 或 Windows Server 2016+
- **管理员权限**(WinDivert 和特权端口所需)
- [WinDivert](https://reqrypt.org/windivert.html) — `WinDivert.dll` 和 `WinDivert64.sys` 必须与 `argus.exe` 位于同一文件夹中(已包含在仓库中)
### 1. 安装 Rust
```
winget install Rustlang.Rustup
# 或从 https://rustup.rs 下载 installer
```
### 2. 构建
```
cargo build --release
```
`build.rs` 脚本会自动:
- 将 `WinDivert-2.2.2-A/x64/` 添加到链接器搜索路径,以便在编译时找到 `WinDivert.lib`
- 将 `WinDivert.dll` 和 `WinDivert64.sys` 复制到 `argus.exe` 旁边
- 嵌入请求 `requireAdministrator` 的 UAC 清单
二进制文件位置:`argus.exe`
## 法律声明
此工具旨在用于合法的恶意软件分析和安全研究。请仅在隔离的实验室环境中使用。请勿在生产网络上使用。
## 许可证
[PolyForm Noncommercial 1.0.0](LICENSE) — 可免费用于个人使用、安全研究和非商业用途。禁止商业用途。
标签:DAST, IP 地址批量处理, 中间人攻击(MITM), 多人体追踪, 安全分析工具, 恶意软件分析, 流量重定向, 网络流量拦截, 通知系统