
Whitepaper
TL;DR: Dieser PoC demonstriert eine 3‑stufige Kaskade der strukturierten Ausnahmebehandlung (SEH), die durch absichtliche fehlausgerichtete Ausführung in rohe Byte-Blobs verursacht wird, deren erste gültige Anweisung ein auslösendes
div regmit einem Divisor von Null ist.
Jede Ausnahmestufe installiert den nächsten SEH-Handler, löst eine neue fehlausgerichtete Division‑durch‑Null aus und führt eine harmlose, beobachtbare Nutzlast aus, bevor die ursprüngliche SEH-Kette wiederhergestellt und sauber beendet wird.
MOEW (Misaligned Opcode Exception Waterfall) ist eine defensive Forschungsprobe, die kontrollierte, ausnahmegetriebene mehrstufige Ausführung auf x86/Wow64-Windows demonstriert. Sie zeigt:
fs:[0]blob1, blob2, blob3)KiUserExceptionDispatcherRtlDispatchExceptionAlle Nutzlasten sind harmlos:
%TEMP%Der PoC ist absichtlich entschärft. Es werden keine Daten verschlüsselt, verändert oder zerstört.
div an kontrollierten Offsets (ECX/EDX/EBX = 0)ORIGINAL_SEH)Der PoC verwendet nur in Nightly verfügbare Features:
#![feature(asm_experimental_arch)]
#![feature(naked_functions)]
Installieren Sie die erforderlichen Komponenten:
rustup toolchain install nightly
rustup target add i686-pc-windows-msvc --toolchain nightly
Da der PoC benutzerdefinierte SEH-Handler installiert, die nicht in der SAFESEH-Tabelle enthalten sind, muss der Linker angewiesen werden, die SAFESEH-Validierung zu deaktivieren.
Erstellen Sie .cargo/config.toml:
[target.i686-pc-windows-msvc]
rustflags = [
"-C", "link-arg=/SAFESEH:NO",
]
Binärdatei bauen:
cargo +nightly build --target i686-pc-windows-msvc --release
Die Ausgabe befindet sich unter:
target\i686-pc-windows-msvc\release\seh_waterfall.exe
Ausführen:
seh_waterfall.exe
Erwarteter Kontrollfluss:
Stage 0 → misaligned blob1 → Stage 1 handler
Stage 1 → misaligned blob2 → Stage 2 handler
Stage 2 → misaligned blob3 → Final handler
Final → restore SEH → exit
Sichtbare Artefakte:
%TEMP%\moew_stage2.txt wird erstellt (Stufe 2)Unter 32‑Bit-Windows bilden SEH-Records eine verkettete Liste, die unter fs:[0] gespeichert ist:
#[repr(C)]
struct SehRec {
next: *mut SehRec,
handler: usize,
}
Jeder Handler verwendet die Standard-SEH-Signatur:
extern "system" fn handler(
record: *mut u8,
frame: *mut u8,
context: *mut u8,
dispatcher: *mut u8,
) -> i32
static STAGE_COUNTER: AtomicU32 = AtomicU32::new(0);
static mut ORIGINAL_SEH: *mut SehRec = std::ptr::null_mut();
Wird verwendet, um:
fs:[0] als ORIGINAL_SEH speichern.fs:[0] mit diesem neuen Record überschreiben.blob1 + 5, das als div ecx dekodiert (nachdem ECX = 0 gesetzt wurde).notepad.exe starten.blob2 + 3 → div edx (mit EDX = 0).%TEMP%\moew_stage2.txt schreiben.blob3 + 3 → div ebx (mit EBX = 0).calc.exe starten.ORIGINAL_SEH in fs:[0] wiederherstellen.process::exit(0) beenden.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 (mit ECX = 0 → #DE)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 (mit EDX = 0 → #DE)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 (mit EBX = 0 → #DE)Jede ausgelöste Stufe tritt erneut in die Windows-Benutzermodus-Ausnahme-Pipeline ein:
KiUserExceptionDispatcher
→ RtlDispatchException
→ SEH chain walk (fs:[0])
→ MOEW handler
Typische Debugger-Ansicht:
seh_waterfall!blobX+offset
ntdll!KiUserExceptionDispatcher
ntdll!RtlDispatchException
seh_waterfall!stageN_handler
Der Waterfall wird vollständig durch echte Hardwarefehler und SEH-Dispatch angetrieben; es werden keine synthetischen oder gefälschten Ausnahmen verwendet.
Die in Stufe 2 geschriebene Datei sieht folgendermaßen aus:
MOEW Stage 2 Marker
-------------------
This file was written by the Stage 2 SEH handler
as a benign demonstration payload.
Ihre Präsenz in %TEMP% dient als einfacher, beobachtbarer Beweis, dass Stufe 2 über die SEH-Kette ausgeführt wurde.
Mögliche Erweiterungen umfassen: