0xsp-SRD/aether
GitHub: 0xsp-SRD/aether
Aether是一款用于Windows内存取证和威胁狩猎的工具,可检测恶意行为和注入技术。
Stars: 28 | Forks: 1

# 以太
版本:0.8(公开测试版)
**Aether** 是一款Windows内存取证和威胁狩猎工具,它扫描实时进程内存以查找恶意模式、检测注入技术、植入签名、反射加载.NET程序集。它使用多层置信度模型,显著降低误报率并寻找恶意行为。Aether在检测Hollowing、APC、线程劫持技术方面具有良好能力。安全分析师可以使用它扫描、狩猎并快照可疑区域以进行离线分析。
## 核心功能
以下是Aether核心功能的简要说明,您可以阅读完整的技术博客文章以获取更多信息:
### 签名扫描
- 在进程内存中进行**字节模式匹配**,使用**首字节索引**,比简单的扫描快50-100倍
- **ASCII + UTF-16LE双编码** — 捕获.NET CLR存储的字符串(例如,“msxsl:script”变为`6D 00 73 00 78 00 ...`)
- 从JSON文件中**动态加载规则** — 将新签名放入`rules/`而无需重新编译
- 在`MEM_PRIVATE`区域中进行`PE头检测` — 标记反射加载.NET程序集(`MZ` + `PE` + `BSJB`元数据)
### 结构化内存IOCs
Aether在原始工作集信号上**叠加五层过滤器**,因此一个发现需要多个一致指标才能报告,并带有FP过滤:
| 层 | 过滤器 | 目的 |
|-------|--------|---------|
| **L1** | 结构化 | 仅考虑**可执行**IMAGE子区域(消除`.data` / `.rdata` COW噪声) |
| **L2** | 定量 | 通过`private_pages`计数和`private_ratio`(低/中/高)进行评分 |
| **L3** | 协同 | 只有当**独立**信号在相同的分配基上达成一致时才提升 — 签名命中、`missing_peb_entry`、`private_rwx`、钩子前缀、或磁盘差异 |
| **L4** | CLR感知 | 对ngen / R2R / tiered-JIT目标(`*.ni.dll`、`mscor*`、`clr*`、`coreclr`、`system.private.corelib*`)进行模块级抑制,而不是在CLR加载时跳过所有内容 |
| **L5** | 磁盘差异 | 使用`CreateFileMappingW(SEC_IMAGE_NO_EXECUTE)`映射模块文件;将每个私有可执行页的前16字节与磁盘上的相同RVA进行比较。任何差异都是真实的修改IOCs |
其他结构化检查:
- **PEB模块交叉引用**:不在PEB模块列表中的`MEM_IMAGE`分配(DLL空心化/模块踩踏)
- **工作集扫描**:通过`K32QueryWorkingSetEx`检测修改后的代码页,**批量**处理每个区域的单个系统调用,而不是每个4 KB页(比简单的循环快50-100倍)
- **私有RWX检测**:标记`MEM_PRIVATE + PAGE_EXECUTE_*`(它会产生误报)分配(shellcode、JIT喷洒、动态代码占位符分配)
- **钩子前缀探测** — 读取每个私有代码页的前16字节并匹配经典的x86/x64跳板:
- `E9 ?? ?? ?? ??` — `JMP rel32`
- `FF 25 ?? ?? ?? ??` — `JMP [rip+disp32]`
- `68 ?? ?? ?? ?? C3` — `PUSH imm32 ; RET`
- `48 B8 ?? ?? ?? ?? ?? ?? ?? ?? FF E0` — `MOV RAX, imm64 ; JMP RAX`
- `49 BB ?? ?? ?? ?? ?? ?? ?? ?? 41 FF E3` — Detours风格的`MOV R11, imm64 ; JMP R11`
- **CLR检测** — 对`Cor_Private_IPCBlock_v4_
`部分进行节对象探测*和* v2 `Cor_Private_IPCBlock_`(旧.NET 2/3 / mscorwks),因此运行旧运行时的嘈杂应用程序池不会被错误分类
### 线程启动地址验证(TSAV / L8)
Aether对线程进行更严格的分类,并与L1–L5发现进行交叉相关。对于目标进程创建的每个线程,Aether通过`NtQueryInformationThread`读取其`Win32StartAddress`,当访问允许时,也通过`GetThreadContext` / `Wow64GetThreadContext`读取其实时`Rip` / `Eip`。
每个地址都按以下表格进行评分,更多详情请阅读博客文章:
| 判决 | 严重性 | 条件 |
|---------|----------|-----------|
| `TSAV_SHELLCODE_PRIVATE` | CRITICAL | 地址位于`MEM_PRIVATE + PAGE_EXECUTE_*`区域 — 经典的`CreateRemoteThread`shellcode |
| `TSAV_SUSPENDED_RIP` | CRITICAL | 暂停线程的`Rip` / `Eip`与`Win32StartAddress`不一致,并解析为可疑区域 — 捕获`Win32StartAddress`欺骗(EarlyBird / APC技巧)和`SetThreadContext`劫持 |
| `TSAV_HOLLOWED_HOST` | HIGH | 地址位于不在PEB模块列表中的`MEM_IMAGE`分配(DLL空心化/模块踩踏) |
| `TSAV_MODIFIED_HOST` | HIGH | 地址位于L1–L5管道已标记为`MODIFIED_CODE_*`、`MISSING_PEB`、`PRIVATE_RWX`、`DISK_MEM_DIFF`或`HOOK_PROLOGUE`的分配 |
| `TSAV_STAGED_PRIVATE_RW` | HIGH | `MEM_PRIVATE + PAGE_READWRITE` — `VirtualProtect`之前的shellcode阶段 |
| `TSAV_MAPPED_NONPE` | MEDIUM | `MEM_MAPPED`(页面文件支持的节)没有PE头 — sRDI / 页面文件反射加载器 |
| `TSAV_SPOOF_TRAMPOLINE` | MEDIUM | 线程`Win32StartAddress`等于拒绝列表中的跳板(`LoadLibraryA/W/ExA/W`、`WinExec`、`CreateProcessA/W`、`VirtualAlloc[Ex]`、`RtlExitUserThread`、`RtlExitUserProcess`、`NtTerminateProcess`、`ShellExecuteA/W`) |
与基本检查“启动地址是否在任何模块中”相比,使其更强大的原因:
- **`VirtualQueryEx`交叉检查** — 每个地址都通过单个O(1)调用查询`Type` / `Protect` / `AllocationBase`,而不是在模块列表中进行线性扫描
- **与L1–L5的交叉相关** — 启动地址落在已标记分配中的线程从“OK”升级到`TSAV_MODIFIED_HOST`
- **PEB一致性** — 即使启动地址在技术上落在“真实”范围内,也能检测到空心化模块
- **暂停-Rip探测** — `Win32StartAddress`可以通过`NtSetInformationThread`写入进程,并且是可欺骗的字段;暂停线程的实时`Rip`是加载器难以重写的。我们比较这两个,并标记任何解析为可疑区域的任何不一致
- **WoW64感知** — 自动切换到`Wow64GetThreadContext`并读取64位进程中的32位线程的`Eip`
- **访问权限级** — 每个线程回退到`QUERY_INFORMATION | GET_CONTEXT` → `QUERY_INFORMATION` → `QUERY_LIMITED_INFORMATION`,因此部分访问场景仍然产生有用的分类
### 混沌分析与Shellcode启发式方法
Aether目前支持在占位符级别进行XOR检测模式,并采用Shannon熵算法检查内存区域中字节的随机性,它标记所有高于阈值的项。为了解决高误报率,Aether使用多个指标。
### C2信标检测
- **TCP连接监控** — 轮询`GetExtendedTcpTable`以获取目标PID
- **信标模式检测** — 识别周期性短暂连接(经典的C2回调行为)
- **连接表输出** — 格式化的控制台表,包含状态、端点、命中和协议
### 输出模式
- **基于严重性的彩色控制台报告**,使用ANSI高亮显示
- **可由机器解析的JSON**,用于SIEM / d-tect.py管道集成
- **分级怀疑输出** — 每个`MODIFIED_CODE_*`发现都携带`private_pages`和`region_pages`,以便分类具有实际数字
- **使用Unicode框绘制字符的表格格式输出**,用于连接监控
## 怀疑类型
### 修改代码管道(L1–L5)
| 标签 | 严重性 | 含义 |
|-------|----------|---------|
| `MODIFIED_CODE_HIGH` | HIGH | 具有钩子前缀、磁盘差异或≥ 25 %私有页比的可执行IMAGE页面 |
| `MODIFIED_CODE_MED` | MEDIUM | 由另一个信号证实,或≥ 5 %比率,或≥ 8个私有页 |
| `HOOK_PROLOGUE` | MEDIUM | 在私有代码页的起始位置找到跳板字节模式 |
| `DISK_MEM_DIFF` | HIGH | 可执行私有页的前16字节与磁盘上的映像不同 |
| `MISSING_PEB` | HIGH | `MEM_IMAGE`分配不在PEB模块列表中(DLL空心化) |
| `PRIVATE_RWX` | HIGH | 具有可执行保护的私有内存 |
| `CLR_INIT` | INFO | 目标进程托管.NET CLR(过滤提示,不是发现) |
### 线程启动地址验证(L8)
| 标签 | 严重性 | 含义 |
|-------|----------|---------|
| `TSAV_SHELLCODE_PRIVATE` | CRITICAL | 线程在`MEM_PRIVATE + PAGE_EXECUTE_*`(经典shellcode线程)启动 |
| `TSAV_SUSPENDED_RIP` | CRITICAL | 暂停线程的`Rip` / `Eip`解析为与`Win32StartAddress`不一致的可疑区域 |
| `TSAV_HOLLOWED_HOST` | HIGH | 线程在PEB中缺失的`MEM_IMAGE`分配中启动 |
| `TSAV_MODIFIED_HOST` | HIGH | 线程在L1–L5已标记的分配中启动 |
| `TSAV_STAGED_PRIVATE_RW` | HIGH | 线程在`MEM_PRIVATE + PAGE_READWRITE`(`VirtualProtect`之前的阶段)启动 |
| `TSAV_MAPPED_NONPE` | MEDIUM | 线程在`MEM_MAPPED`非PE节中启动 |
| `TSAV_SPOOF_TRAMPOLINE` | MEDIUM | 线程`Win32StartAddress`等于拒绝列表中的跳板(`LoadLibraryW`、`RtlExitUserThread`等) |
| `THREAD_START_ANOMALY` | HIGH | 每个扫描的每个可疑线程的聚合计数 |
### 加密有效负载检测
| 标签 | 严重性 | 含义 |
|-------|----------|---------|
| `XOR_PE_HEADER` | CRITICAL | 在单字节或多字节XOR下找到PE头;DOS占位符锚点+ `MZ` / `e_lfanew` / `PE\0\0`一致性检查全部通过(Donut、CS `sleep_mask`、Sliver、sRDI) |
## 规则包
签名组织到JSON规则包中。将这些中的任何一个放入`rules/`目录:
| 文件 | 覆盖范围 |
|------|----------|
| `cobalt_strike.json` | Cobalt Strike信标工件 |
| `meterpreter.json` | Metasploit Meterpreter植入 |
| `sliver.json` | Sliver C2植入(BishopFox) |
| `brute_ratel.json` | Brute Ratel C4獾 |
| `havoc.json` | Havoc C2恶魔 |
| `sharp_tools.json` | .NET攻击工具(Rubeus、Seatbelt、SharpHound) |
| `mimikatz.json` | Mimikatz凭证盗窃 |
| `powershell_cradles.json` | PowerShell攻击支架 & AMSI绕过 |
| `dotnet_loaders.json` | 通用.NET加载器和注入器 |
| `mythic_poshc2.json` | Mythic / PoshC2 / Nighthawk植入 |
| `phantom_str.json` | Phantom ASP .NET加载器 |
每个规则文件都是一个签名对象的JSON数组:
```
[
{
"pattern": "msxsl:script",
"weight": 5,
"category": "engine_xslt",
"description": "XSLT script block declaration"
}
]
```
`category`映射到以下之一:`engine_xslt`、`engine_codedom`、`engine_managed`、`c2_tcp`、`c2_http`、`c2_sql`、`c2_smtp`、`c2_file`、`c2_dns`、`evasion`、`reflective_load`、`webshell_generic`。
## 使用方法
```
Aether.exe --scan --pid [OPTIONS]
Aether.exe --scan --lookup "ProcessName.exe"
Aether.exe --hunt SLEEP_MS PERIOD
Aether.exe --scan-all [OPTIONS]
```
### 选项
| 标志 | 描述 |
|------|-------------|
| `--pid`,`-p ` | 要扫描的目标进程ID |
| `--lookup`,`-l ` | 查找匹配进程名的所有PID |
| `--json`,`-j` | 将结果输出为JSON(用于SIEM集成) |
| `--verbose`,`-v` | 显示每个区域的扫描细节 |
| `--scan-all`,`-a` | 扫描所有进程 |
| `--hunt`,`-b [ms] [hits]` | 监控连接 — 每ms`轮询一次(默认2000),标记出现≥ `hits`次出现的端点 |
| `--networking` | 网络监控模式 |
| `--rules`,`-r ` | 规则目录(默认:`rules/`) |
| `--config`,`-c ` | 单个规则文件(旧格式) |
| `--help`,`-h` | 显示帮助 |
## 示例输出
### 控制台报告
```
Scan Results for PID 4820
==================================================
Regions: 847 total, 312 scanned, 287 system-skipped
Bytes scanned: 214.35 MB
Read errors: 3
Scan time: 1247 ms
[HIGH] ENGINE_XSLT | score=18 hits=4 [T1220]
+5 "msxsl:script" @ 0x7FFE2A3B1000 (ascii)
+6 "urn:payload" @ 0x7FFE2A3B1200 (ascii)
+4 "enableScript" @ 0x7FFE2A3B1400 (utf16le)
+3 "XsltSettings" @ 0x7FFE2A3B1600 (ascii)
[CRITICAL] REFLECTIVE_LOAD | 2 PE headers in MEM_PRIVATE
(1 with .NET BSJB metadata) [T1620]
---- Structural IOCs (8) ----
[HIGH] MISSING_PEB @ 0x000001D6E0000000 (1048576 bytes)
[HIGH] DISK_MEM_DIFF @ 0x000001D6E0001000 (4 private / 240 pages)
[HIGH] MODIFIED_CODE_HIGH @ 0x000001D6E0001000 (4 private / 240 pages)
[HIGH] PRIVATE_RWX @ 0x000001D6EDDD0000 (12288 bytes)
[CRITICAL] XOR_PE_HEADER @ 0x000001D6EDDD0000 (4 bytes)
[CRITICAL] TSAV_SHELLCODE_PRIVATE @ 0x000001D6EDDD0000 (8472 bytes)
[HIGH] TSAV_MODIFIED_HOST @ 0x000001D6E0001000 (8476 bytes)
[HIGH] THREAD_START_ANOMALY @ 0x0 (2 bytes)
```
使用`--verbose`还可以看到每个线程的详细信息和恢复的XOR密钥:
```
[!] XOR_PE_HEADER @ 0x1D6EDDD0000 key_len=4 key=AABBCCDD
[!] TID:8472 SHELLCODE_PRIVATE start=0x1D6EDDD0150
[!] TID:8476 MODIFIED_HOST start=0x1D6E0001A80 host=msi.dll
```
恢复的密钥字节可以传递给一个单行命令(`python -c 'import sys; k=bytes.fromhex("AABBCCDD"); d=sys.stdin.buffer.read(); sys.stdout.buffer.write(bytes(b^k[i%len(k)] for i,b in enumerate(d)))'`)以转储解密后的PE进行分析。
## 如何编译
### 预先条件
- **Zig 0.16** — [在此下载](https://ziglang.org/download/)
- 从任何宿主操作系统(Linux、macOS、Windows)进行交叉编译
### 构建
```
git clone https://github.com/0xsp-SRD/aether
cd aether
# 调试构建(启用安全检查)
zig build
# 发布构建(更小,更快二进制)
zig build -Doptimize=ReleaseSafe
# 或者
zig build -Doptimize=ReleaseFast
```
构建的可执行文件位于`zig-out/bin/Aether.exe`。
### 部署
如果您想执行额外的签名扫描,请将`zig-out/bin/Aether.exe`和`rules/`目录复制到目标Windows机器。如果目标进程需要管理员权限,则需要以管理员权限运行Aether.exe。
## 局限性
- **仅用户模式** — 没有内核驱动程序;无法检测rootkits或内核级操作
- **仅IPv4** — TCP连接监控目前不支持IPv6端点。
- **L5磁盘差异需要文件访问** — 如果原始模块文件已被删除或被锁定,则磁盘差异将静默跳过该模块(其他层仍然运行)
- **TSAV欺骗跳板列表在扫描器自己的进程中解析** — 捕获系统DLL共享ASLR基会话范围的常见情况,但可能错过具有独特进程基的靶标(Win10+上很少见)
- **TSAV Rip探测仅捕获暂停线程** — 在探测时已运行的线程上的`Win32StartAddress`重写只能检测到线程恰好在一个等待时被挂起(与Moneta相同的约束)
- **XOR-PE检测在此版本中是基本的**
## 许可证标签:APC 技术, Hollowing 技术, JARM, .NET 集成, PE 头检测, RFI远程文件包含, SecList, Windows 安全, 低误报率, 内存分析, 内存取证, 动态规则加载, 多人体追踪, 多层级置信模型, 安全分析工具, 安全响应, 注入技术, 端点可见性, 签名扫描, 线程劫持, 结构化内存 IOCs