
Resumo: Esta PoC demonstra uma cascata de Tratamento de Exceção Estruturada (SEH) de 3 estágios causada por execução desalinhada deliberada em blocos de bytes brutos cuja primeira instrução válida é um
div regcom divisor zero.
Cada estágio de exceção instala o próximo manipulador SEH, dispara uma nova divisão por zero desalinhada e executa uma carga benigna observável antes de restaurar a cadeia SEH original e terminar de forma limpa.
MOEW (Cachoeira de Exceção por Opcode Desalinhado) é uma amostra de pesquisa defensiva que demonstra execução de múltiplos estágios controlada por exceções no Windows x86/Wow64. Ela demonstra:
fs:[0]blob1, blob2, blob3)KiUserExceptionDispatcherRtlDispatchExceptionTodas as cargas são benignas:
%TEMP%A PoC é intencionalmente inofensiva. Nenhum dado é criptografado, modificado ou destruído.
div desalinhado em offsets controlados (ECX/EDX/EBX = 0)ORIGINAL_SEH)A PoC usa recursos exclusivos do nightly:
#![feature(asm_experimental_arch)]
#![feature(naked_functions)]
Instale os componentes necessários:
rustup toolchain install nightly
rustup target add i686-pc-windows-msvc --toolchain nightly
Como a PoC instala manipuladores SEH personalizados que não estão presentes na tabela SAFESEH, o vinculador deve ser instruído a desabilitar a validação SAFESEH.
Crie .cargo/config.toml:
[target.i686-pc-windows-msvc]
rustflags = [
"-C", "link-arg=/SAFESEH:NO",
]
Compile o binário:
cargo +nightly build --target i686-pc-windows-msvc --release
A saída está localizada em:
target\i686-pc-windows-msvc\release\seh_waterfall.exe
Execute:
seh_waterfall.exe
Fluxo de controle esperado:
Estágio 0 → blob1 desalinhado → Manipulador Estágio 1
Estágio 1 → blob2 desalinhado → Manipulador Estágio 2
Estágio 2 → blob3 desalinhado → Manipulador Final
Final → restaurar SEH → sair
Artefatos visíveis:
%TEMP%\moew_stage2.txt é criado (Estágio 2)No Windows 32 bits, os registros SEH formam uma lista encadeada armazenada em fs:[0]:
#[repr(C)]
struct SehRec {
next: *mut SehRec,
handler: usize,
}
Cada manipulador usa a assinatura padrão SEH:
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();
Usado para:
fs:[0] como ORIGINAL_SEH.fs:[0] com este novo registro.blob1 + 5, que decodifica como div ecx (após definir ECX = 0).notepad.exe.blob2 + 3 → div edx (com EDX = 0).%TEMP%\moew_stage2.txt.blob3 + 3 → div ebx (com EBX = 0).calc.exe.ORIGINAL_SEH em fs:[0].process::exit(0).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 (com 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 (com 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 (com EBX = 0 → #DE)Cada estágio com falha reentra no pipeline de exceção do modo usuário do Windows:
KiUserExceptionDispatcher
→ RtlDispatchException
→ Caminhada da cadeia SEH (fs:[0])
→ Manipulador MOEW
Visão típica no depurador:
seh_waterfall!blobX+offset
ntdll!KiUserExceptionDispatcher
ntdll!RtlDispatchException
seh_waterfall!stageN_handler
A cachoeira é inteiramente conduzida por falhas de hardware genuínas e despacho SEH; nenhuma exceção sintética ou falsa é usada.
O arquivo escrito no Estágio 2 se parece com:
MOEW Stage 2 Marker
-------------------
Este arquivo foi escrito pelo manipulador SEH do Estágio 2
como uma carga de demonstração benigna.
Sua presença em %TEMP% serve como uma prova simples e observável de que o Estágio 2 foi executado através da cadeia SEH.
Extensões potenciais incluem: