harryeetsource/MOEW
GitHub: harryeetsource/MOEW
这是一个基于Rust的概念验证项目,演示了如何通过未对齐操作码异常瀑布流在Windows x86上实现多阶段执行,旨在分析异常驱动控制流对安全遥测的干扰。
Stars: 14 | Forks: 2
# 不可见的威胁,可见的解决方案。
# 未对齐操作码异常瀑布流 (MOEW)
### 3 阶段 SEH 瀑布流 PoC(良性,x86/Wow64)
## 1. 概述
MOEW (Misaligned Opcode Exception Waterfall) 是一个**防御性研究**示例,展示了在 **x86/Wow64 Windows** 上受控的、由异常驱动的多阶段执行。它演示了:
- 通过 `fs:[0]` 手动操作 SEH 链
- 故意未对齐进入手工构造的字节序列 (`blob1`, `blob2`, `blob3`)
- 阶段链接的 SEH 处理程序
- 通过以下方式进行多故障递归:
- `KiUserExceptionDispatcher`
- `RtlDispatchException`
- 自定义用户模式处理程序
- 恢复原始 SEH 链的清理终止路径
**所有载荷均为良性**:
- **阶段 1:** 启动记事本
- **阶段 2:** 将标记文件写入 `%TEMP%`
- **最终阶段:** 启动计算器
该 PoC 经过故意去武装化。没有任何数据被加密、修改或销毁。
## 2. 功能特性
- 通过 3 个分阶段处理程序实现完全确定性的 SEH 递归
- 具有多条有效解码路径的裸机 x86 字节块
- 在受控偏移量处未对齐的 `div`(`ECX`/`EDX`/`EBX` = 0)
- 用于日志记录和追踪的每阶段全局计数器
- 完全恢复原始 SEH 头 (`ORIGINAL_SEH`)
- Rust nightly + 内联汇编 + 裸函数
- 用于遥测和调试器测试的良性但可见的“载荷”
## 3. 环境要求
### 3.1 架构
- **仅限 x86 (32 位)**
- 使用 MSVC 工具链编译
- 也可在 WoW64 下的 64 位 Windows 上运行
### 3.2 Rust Nightly
该 PoC 使用仅限 nightly 版本的功能:
```
#![feature(asm_experimental_arch)]
#![feature(naked_functions)]
```
安装必要的组件:
```
rustup toolchain install nightly
rustup target add i686-pc-windows-msvc --toolchain nightly
```
### 3.3 禁用 SAFESEH
由于该 PoC 安装的自定义 SEH 处理程序未出现在 SAFESEH 表中,必须指示链接器禁用 SAFESEH 验证。
创建 `.cargo/config.toml`:
```
[target.i686-pc-windows-msvc]
rustflags = [
"-C", "link-arg=/SAFESEH:NO",
]
```
## 4. 构建说明
构建二进制文件:
```
cargo +nightly build --target i686-pc-windows-msvc --release
```
输出位于:
```
target\i686-pc-windows-msvc\release\seh_waterfall.exe
```
## 5. 运行 PoC
执行:
```
seh_waterfall.exe
```
预期的控制流:
```
Stage 0 → misaligned blob1 → Stage 1 handler
Stage 1 → misaligned blob2 → Stage 2 handler
Stage 2 → misaligned blob3 → Final handler
Final → restore SEH → exit
```
可见的产物:
- **notepad.exe** 启动(阶段 1)
- `%TEMP%\moew_stage2.txt` 被创建(阶段 2)
- **calc.exe** 启动(最终处理程序)
## 6. 技术剖析
### 6.1 SEH 记录布局
在 32 位 Windows 上,SEH 记录形成一个存储在 `fs:[0]` 的链表:
```
#[repr(C)]
struct SehRec {
next: *mut SehRec,
handler: usize,
}
```
每个处理程序使用标准的 SEH 签名:
```
extern "system" fn handler(
record: *mut u8,
frame: *mut u8,
context: *mut u8,
dispatcher: *mut u8,
) -> i32
```
### 6.2 全局状态
```
static STAGE_COUNTER: AtomicU32 = AtomicU32::new(0);
static mut ORIGINAL_SEH: *mut SehRec = std::ptr::null_mut();
```
用于:
- 计算处理程序递归深度
- 在瀑布流结束时恢复原始 SEH 头
## 7. 阶段逻辑
### **阶段 0 — 初始帧设置**
1. 将 `fs:[0]` 保存为 `ORIGINAL_SEH`。
2. 构建一个指向阶段 1 处理程序的 SEH 记录。
3. 用这个新记录覆盖 `fs:[0]`。
4. 未对齐进入 `blob1 + 5`,其解码为 `div ecx`(在设置 `ECX = 0` 之后)。
### **阶段 1 — 第一个 SEH 处理程序**
1. 启动 `notepad.exe`。
2. 为阶段 2 处理程序构建一个 SEH 记录并将其链接到顶部。
3. 未对齐进入 `blob2 + 3` → `div edx`(此时 `EDX = 0`)。
### **阶段 2 — 第二个 SEH 处理程序**
1. 写入 `%TEMP%\moew_stage2.txt`。
2. 在 SEH 链上安装最终处理程序。
3. 未对齐进入 `blob3 + 3` → `div ebx`(此时 `EBX = 0`)。
### **最终处理程序 — 终止**
1. 启动 `calc.exe`。
2. 将 `ORIGINAL_SEH` 恢复到 `fs:[0]`。
3. 通过 `process::exit(0)` 干净地退出进程。
## 8. 未对齐故障块
### 8.1 `blob1`
```
#[unsafe(naked)]
pub extern "C" fn blob1() {
naked_asm! {
".byte 0xB8, 0x10, 0x00, 0x00, 0x00", // mov eax, 0x10
".byte 0xF7, 0xF1", // div ecx
".byte 0xC3", // ret
".byte 0x90, 0x90, 0x90", // nop padding
}
}
```
- 对齐解码:`mov eax, 0x10; div ecx; ret`
- 在 `+5` 处未对齐:`div ecx`(此时 `ECX = 0` → `#DE`)
### 8.2 `blob2`
```
#[unsafe(naked)]
pub extern "C" fn blob2() {
naked_asm! {
".byte 0x55", // push ebp
".byte 0x8B, 0xEC", // mov ebp, esp
".byte 0xF7, 0xF2", // div edx
".byte 0xC3", // ret
".byte 0x90, 0x90, 0x90", // nop padding
}
}
```
- 对齐解码:`push ebp; mov ebp, esp; div edx; ret`
- 在 `+3` 处未对齐:`div edx`(此时 `EDX = 0` → `#DE`)
### 8.3 `blob3`
```
#[unsafe(naked)]
pub extern "C" fn blob3() {
naked_asm! {
".byte 0x53", // push ebx
".byte 0x8B, 0xD8", // mov ebx, eax
".byte 0xF7, 0xF3", // div ebx
".byte 0xC3", // ret
".byte 0x90, 0x90, 0x90", // nop padding
}
}
```
- 对齐解码:`push ebx; mov ebx, eax; div ebx; ret`
- 在 `+3` 处未对齐:`div ebx`(此时 `EBX = 0` → `#DE`)
## 9. 异常管道
每个故障阶段都会重新进入 Windows 用户模式异常管道:
```
KiUserExceptionDispatcher
→ RtlDispatchException
→ SEH chain walk (fs:[0])
→ MOEW handler
```
典型的调试器视图:
```
seh_waterfall!blobX+offset
ntdll!KiUserExceptionDispatcher
ntdll!RtlDispatchException
seh_waterfall!stageN_handler
```
瀑布流完全由真正的硬件故障和 SEH 分发驱动;没有使用合成或伪造的异常。
## 10. 标记文件输出
在阶段 2 写入的文件如下所示:
```
MOEW Stage 2 Marker
-------------------
This file was written by the Stage 2 SEH handler
as a benign demonstration payload.
```
它存在于 `%TEMP%` 中作为简单、可观察的证明,证明阶段 2 已通过 SEH 链执行。
## 11. 安全注意事项
- PoC 是良性的,仅用于防御性研究。
- 无持久性、注册表修改或加密行为。
- 所有异常均被捕获并处理。
- 原始 SEH 链在终止前已恢复。
## 12. 未来增强
潜在的扩展包括:
- 针对 SEH 瀑布流和递归异常模式的 YARA 和行为规则。
- 针对分段硬件故障的 ETW / EDR 信号映射。
- SEH 链随时间演变的图形化图表。
- 与真实恶意软件异常链的并排比较。
## 13. 完整源代码
完整的 PoC 实现可在此存储库中找到(参见 `src/main.rs`)。
## 14. 许可证
本项目旨在用于防御性研究和教育。
Copyright <2025>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## 15. 真实样本与 PoC:SEH 损坏、瀑布流行为及遥测影响
### 15.1 真实样本的行为:故意的 SEH 损坏
启发本 PoC 的真实世界 MOEW 样本在执行结束时**并未**恢复 `fs:[0]`。
相反,其最终阶段:
1. 用 `NULL` 或指向无效内存的指针**覆盖 SEH 头 (`fs:[0]`)**。
2. **触发最后一次未对齐异常**,确保发生硬件故障。
3. 强制 Windows 遍历**无效或截断的 SEH 链**。
4. 导致 `RtlDispatchException` 遇到无效的处理程序指针。
5. 导致崩溃,其中:
- EIP/RIP 指向**非映像内存**(堆、栈或匿名区域)。
- **故障模块**无法解析并显示为 `unknown`。
- **故障路径**也显示为 `unknown`。
6. 产生的 Windows 错误报告 (WER) 签名**不可归因**于任何已加载的模块。
7. 记录事件查看器 `Application Error` 事件,其中包含无意义的故障偏移量。
8. 产生主要由以下内容主导的 EDR 遥测数据:
- 重复的 `KiUserExceptionDispatcher` 调用,
- 递归 SEH 转换,
- 最终缺乏模块归因的异常崩溃。
这种破坏性的 SEH 损坏步骤服务于样本的主要反取证目的:
**擦除因果链并产生不可归因的终端崩溃。**
### 15.2 PoC 的行为:SEH 的干净恢复且无终端崩溃
与真实样本不同,此 PoC:
- 在阶段 0 期间**捕获**原始 SEH 头:
asm!("mov {old}, fs:[0]", old = out(reg) old_head);
ORIGINAL_SEH = old_head;
- 在最终处理程序中**恢复**原始 SEH 头:
asm!("mov fs:[0], {p}", p = in(reg) ORIGINAL_SEH);
- 通过 `process::exit(0)` **干净地终止**,而不是触发未处理的故障。
因此,PoC:
- **不**留下损坏的 SEH 链。
- **不**产生最终的未处理异常。
- **不**生成:
- WER 崩溃报告,
- 事件查看器 `Application Error 1000` 条目,
- “faulting module: unknown”(故障模块:未知)签名,
- 无效的异常处置,
- 或悬空的 SEH 记录。
然而——关键在于——PoC *没有*消除 MOEW 的**异常驱动的遥测降级**行为。
### 15.3 真实样本和 PoC 共有的遥测降级
PoC 绝对**会**以相同的基本方式降级遥测:
- 它故意触发**多次未对齐的硬件故障**。
- 它快速连续产生**多次第一次机会异常** (first‑chance exceptions)。
- 它强制 Windows 重复执行:
KiUserExceptionDispatcher
RtlDispatchException
→ 自定义处理程序
→ 未对齐块
→ 硬件故障
- 它生成**非线性的、以异常为主的调用栈**。
- 它通过以下方式在调试器和 EDR 中扭曲控制流重建:
- 递归 SEH 处理程序,
- 未对齐解码路径,
- 非函数对齐地址,
- 部分指令边界。
因此,PoC 忠实地再现了:
- **递归瀑布流模式**,
- **异常驱动的状态机**,
- **未对齐操作码进入行为**,
- 以及**控制流混淆**,
……同时避免了破坏性的最终崩溃。
这使得 PoC 非常适合进行仪器测量和研究,而无需触发完整的反取证载荷。
### 15.4 为什么 PoC 适用于防御性研究
由于 PoC 保留了 MOEW 的整体行为,*减去* SEH 损坏崩溃,因此它是:
- 在实验室环境中可以安全地重复运行。
- 确定性且稳定。
- 适用于:
- EDR 管道分析,
- 遥测研究,
- 事件响应培训,
- 调试器行为测试,
- 与真实恶意样本的并排比较。
PoC 对**异常瀑布流**(MOEW 的本质)进行建模,同时移除了最终的破坏性签名。
它证明了遥测降级的产生**不仅**来自于 SEH 损坏,还来自于异常驱动的控制流模型本身。
### 15.5 总结
| 行为 | 真实 MOEW 样本 | PoC 实现 |
|-------------------------------------------|------------------|--------------------|
| 未对齐操作码瀑布流 | ✔ | ✔ |
| 递归 SEH 驱动的状态机 | ✔ | ✔ |
| 占主导地位的异常分发调用栈 | ✔ | ✔ |
| 遥测 / 堆栈跟踪降级 | ✔ | ✔ |
| 故意的 SEH 损坏 | ✔ | ❌ |
| 悬空或无效的 SEH 指针 | ✔ | ❌ |
| 最终未异常 | ✔ | ❌ |
| WER “未知模块” 崩溃 | ✔ | ❌ |
| 干净地恢复 `fs:[0]` | ❌ | ✔ |
| 干净的终止 | ❌ | ✔ |
本部分明确了行为差异,同时保持 PoC 的目的清晰:
**以安全、对研究友好的形式展示 MOEW 瀑布流,且不包含反取证的最终崩溃。**
标签:32位, Conpot, DOM解析, FS:[0], KiUserExceptionDispatcher, POC, RtlDispatchException, Rust, Rust夜间版, SAFESEH绕过, SEH, SEH覆写, SEH链, Windows安全, Wow64, WoW64, x86, 内联汇编, 利用技术, 反调试, 多阶段执行, 安全意识培训, 异常分发, 指令对齐, 控制流劫持, 搜索语句(dork), 操作码, 无害载荷, 概念验证, 漏洞分析, 端点可见性, 结构化异常处理, 网络流量审计, 裸函数, 调试测试, 路径探测, 通知系统, 防御性样本, 除零异常