SCEMU The crates.io lib, x86 cpu and systems emulator focused mainly for anti-malware
SCEMU the lib
This repo has been archived, now libscemu, pyscemu and scemu become 1 repo: https://github.com/sha0coder/mwemu
Usage
Download the maps32 or maps64 from: https://github.com/sha0coder/scemu
In the example it's on /tmp/ but dont use tmp.
Create an emu32 or emu64 and it's important to set the maps folder.
use libscemu::emu32;
fn main() { let mut emu = emu32(); emu.setmapsfolder("/tmp/maps32/"); emu.init(false, false);
Load your shellcode or PE binary and run the emulator. None parameter means emulate for-ever.
emu.load_code("shellcodes32/shikata.bin");
emu.set_verbose(2);
emu.run(None).unwrap();
Or if you prefer call specific function.
emu.load_code("samples/malware.exe");
let cryptokeygen = 0x40112233; let ret_addr = 0x40110000; // any place safe to return.
let param1 = 0x33; let param2outbuff = emu.alloc("buffer", 1024);
emu.maps.memset(param2outbuff, 0, 1024); // non necesary, by default alloc create zeros. emu.maps.writespacedbytes(param2outbuff, "DE CC 6C 83 CC F3 66 85 34"); // example of initialization.
// call function emu.regs.seteip(cryptokey_gen); emu.stackpush32(param2out_buff); emu.stack_push32(param1); emu.stackpush32(retaddr); emu.run(Some(retaddr)).unwrap(); // emulate until arrive to retaddr
// or simpler way: let eax = emu.call32(cryptokeygen, &[param1, param2outbuff]).unwrap();
// this would be slower but more control while emu.step() { ... }
// check result log::info!("return value: 0x{:x}", emu.regs.get_eax()); emu.maps.dump(param2outbuff);
Now it's possible to do hooks on libscemu but not on pyscemu.
use libscemu::emu32;
//need iced_x86 crate only for instruction hooks, to get the //instruction object, so add iced-x86 = "1.17.0" use iced_x86::{Instruction};
fn tracememoryread(emu:&mut libscemu::emu::Emu, ip_addr:u64, mem_addr:u64, sz:u8) { log::info!("0x{:x}: reading {} at 0x{:x}", ipaddr, sz, memaddr); if mem_addr == 0x22dff0 { emu.stop(); } }
fn tracememorywrite(emu:&mut libscemu::emu::Emu, ip_addr:u64, mem_addr:u64, sz:u8, value:u128) -> u128 { log::info!("0x{:x}: writing {} '0x{:x}' at 0x{:x}", ip_addr, sz, value, mem_addr); value // I could change the value to write }
fn traceinterrupt(emu:&mut libscemu::emu::Emu, ipaddr:u64, interrupt:u64) -> bool { log::info!("interrupt {} triggered at eip: 0x{:x}", interrupt, ip_addr); true // do handle interrupts }
fn traceexceptions(emu:&mut libscemu::emu::Emu, ipaddr:u64) -> bool { log::info!("0x{:x} triggered an exception", ip_addr); true // do handle exceptions }
fn tracepreinstruction(emu:&mut libscemu::emu::Emu, ip_addr:u64, ins:&Instruction, sz:usize) { }
fn tracepostinstruction(emu:&mut libscemu::emu::Emu, ip_addr:u64, ins:&Instruction, sz:usize, emu_ok:bool) { }
fn tracewinapicall(emu:&mut libscemu::emu::Emu, ipaddr:u64, apiaddr:u64) -> bool { return true; // handle api calls }
fn main() { let mut emu = emu32(); emu.setmapsfolder("../scemu/maps32/"); // download the maps, ideally from scemu git. emu.init();
emu.load_code("/home/sha0/src/scemu/shellcodes32/mars.exe"); emu.hook.onmemoryread(tracememoryread); emu.hook.onmemorywrite(tracememorywrite); emu.hook.oninterrupt(traceinterrupt); emu.hook.onexception(traceexceptions); emu.hook.onpreinstruction(tracepreinstruction); emu.hook.onpostinstruction(tracepostinstruction); emu.hook.onwinapicall(tracewinapicall); emu.run(None).unwrap(); log::info!("end!"); }