libmwemu 0.24.5

x86 32/64bits and system internals emulator, for securely emulating malware and other stuff.
Documentation
use crate::emu;
use crate::windows::constants;
use crate::winapi::helper;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;

pub(super) fn dispatch(emu: &mut emu::Emu) -> bool {
    match emu.regs().rax {
        constants::NR64_READ => handle_syscall64_read(emu),
        constants::NR64_WRITE => handle_syscall64_write(emu),
        constants::NR64_OPEN => handle_syscall64_open(emu),
        constants::NR64_OPENAT => handle_syscall64_openat(emu),
        constants::NR64_CLOSE => handle_syscall64_close(emu),
        constants::NR64_EXECVE => handle_syscall64_execve(emu),
        constants::NR64_CHDIR => handle_syscall64_chdir(emu),
        constants::NR64_CHMOD => handle_syscall64_chmod(emu),
        constants::NR64_LSEEK => handle_syscall64_lseek(emu),
        _ => return false,
    }

    true
}

pub(super) fn handle_syscall64_read(emu: &mut emu::Emu) {
    let fd = emu.regs().rdi;
    let buff = emu.regs().rsi;
    let sz = emu.regs().rdx;

    if helper::handler_exist(fd) {
        let filepath = helper::handler_get_uri(fd);
        if filepath.contains(".so") {
            let mut lib_buff: Vec<u8> = Vec::new();

            match File::open(&filepath) {
                Ok(f) => {
                    let mut reader = BufReader::new(&f);
                    reader
                        .read_to_end(&mut lib_buff)
                        .expect("kernel64 cannot load dynamic library");
                    f.sync_all();

                    let map = emu
                        .maps
                        .get_mem_by_addr_mut(buff)
                        .expect("buffer send to read syscall point to no map");

                    let mem_end = map.get_base() + map.size() as u64 - 1;
                    let buff_end = buff + lib_buff.len() as u64 - 1;
                    if buff_end > mem_end {
                        let overflow = buff_end - mem_end;
                        lib_buff = lib_buff[0..lib_buff.len() - overflow as usize].to_vec();
                    }

                    emu.maps.write_bytes(buff, &lib_buff);
                    emu.regs_mut().rax = sz;
                }
                Err(_) => {
                    log::trace!("file not found");
                    emu.regs_mut().rax = 0;
                }
            };
        }
    } else {
        emu.regs_mut().rax = sz;
    }

    log::trace!(
        "{}** {} syscall read(fd:{} buf:0x{:x} sz:{}) ={} {}",
        emu.colors.light_red,
        emu.pos,
        fd,
        buff,
        sz,
        emu.regs().rax,
        emu.colors.nc
    );
}

pub(super) fn handle_syscall64_write(emu: &mut emu::Emu) {
    let fd = emu.regs().rdi;
    let buff = emu.regs().rsi;
    let sz = emu.regs().rdx;
    emu.regs_mut().rax = sz;
    log::trace!(
        "{}** {} syscall write() fd: {} buf: 0x{:x} sz: {} {}",
        emu.colors.light_red,
        emu.pos,
        fd,
        buff,
        sz,
        emu.colors.nc
    );
    if fd == 1 {
        let s = emu.maps.read_string(buff);
        log::trace!("stdout: `{}`", s)
    }
    if fd == 2 {
        let s = emu.maps.read_string(buff);
        log::trace!("stderr: `{}`", s)
    }
}

pub(super) fn handle_syscall64_open(emu: &mut emu::Emu) {
    let file_path = emu.maps.read_string(emu.regs().rdi);
    let fd = helper::handler_create(&file_path);

    emu.regs_mut().rax = fd;
    log::trace!(
        "{}** {} syscall open({}) ={} {}",
        emu.colors.light_red,
        emu.pos,
        file_path,
        fd,
        emu.colors.nc
    );
}

pub(super) fn handle_syscall64_openat(emu: &mut emu::Emu) {
    let dirfd = emu.regs().rdi;
    let file_path = emu.maps.read_string(emu.regs().rsi);
    let mut fd: u64 = 0xffffffff_ffffffff;

    let path = Path::new(&file_path);
    if path.exists() {
        fd = helper::handler_create(&file_path);
    }

    log::trace!(
        "{}** {} syscall openat({} '{}') ={} {}",
        emu.colors.light_red,
        emu.pos,
        dirfd,
        file_path,
        fd as i64,
        emu.colors.nc
    );

    emu.regs_mut().rax = fd;
}

pub(super) fn handle_syscall64_close(emu: &mut emu::Emu) {
    let fd = emu.regs().rdi;

    if helper::handler_exist(fd) {
        helper::handler_close(fd);
        emu.regs_mut().rax = 0;
    } else {
        helper::socket_close(fd);
        emu.regs_mut().rax = 0xffffffff_ffffffff;
    }

    log::trace!(
        "{}** {} syscall close(fd:{}) ={} {}",
        emu.colors.light_red,
        emu.pos,
        fd,
        emu.regs().rax,
        emu.colors.nc
    );
}

pub(super) fn handle_syscall64_execve(emu: &mut emu::Emu) {
    let cmd = emu.maps.read_string(emu.regs().rdi);
    log::trace!(
        "{}** {} syscall execve()  cmd: {} {}",
        emu.colors.light_red,
        emu.pos,
        cmd,
        emu.colors.nc
    );
    emu.regs_mut().rax = 0;
}

pub(super) fn handle_syscall64_chdir(emu: &mut emu::Emu) {
    let path = emu.maps.read_string(emu.regs().rdi);
    log::trace!(
        "{}** {} syscall chdir() path: {} {}",
        emu.colors.light_red,
        emu.pos,
        path,
        emu.colors.nc
    );
}

pub(super) fn handle_syscall64_chmod(emu: &mut emu::Emu) {
    let file_path = emu.maps.read_string(emu.regs().rdi);
    let perm = emu.regs().rsi;
    log::trace!(
        "{}** {} syscall chmod() file: {} perm: {} {}",
        emu.colors.light_red,
        emu.pos,
        file_path,
        perm,
        emu.colors.nc
    );
}

pub(super) fn handle_syscall64_lseek(emu: &mut emu::Emu) {
    let fd = emu.regs().rdi;
    log::trace!(
        "{}** {} syscall lseek()  fd: {} {}",
        emu.colors.light_red,
        emu.pos,
        fd,
        emu.colors.nc
    );
}