libmwemu 0.24.3

x86 32/64bits and system internals emulator, for securely emulating malware and other stuff.
Documentation
use crate::api::windows::common::ntdll;
use crate::emu;
use crate::maps::mem64::Permission;
use crate::winapi::helper;
use crate::windows::{constants, structures};

pub(super) fn dispatch(api: &str, emu: &mut emu::Emu) -> bool {
    match api {
        "NtAllocateVirtualMemory" => NtAllocateVirtualMemory(emu),
        "NtQueryVirtualMemory" => NtQueryVirtualMemory(emu),
        "RtlZeroMemory" => RtlZeroMemory(emu),
        "RtlMoveMemory" => RtlMoveMemory(emu),
        "NtProtectVirtualMemory" => NtProtectVirtualMemory(emu),
        "memset" => memset(emu),
        "RtlCopyMemory" => RtlCopyMemory(emu),
        "NtFlushInstructionCache" => NtFlushInstructionCache(emu),
        "RtlAddFunctionTable" => RtlAddFunctionTable(emu),
        "RtlCaptureContext" => RtlCaptureContext(emu),
        "RtlLookupFunctionEntry" => RtlLookupFunctionEntry(emu),
        _ => return false,
    }
    true
}

fn RtlZeroMemory(emu: &mut emu::Emu) {
    let dest = emu.regs().rcx;
    let length = emu.regs().rdx;
    ntdll::rtl_zero_memory(emu, dest, length);
}

fn RtlMoveMemory(emu: &mut emu::Emu) {
    let dst = emu.regs().rcx;
    let src = emu.regs().rdx;
    let sz = emu.regs().r8 as usize;
    ntdll::rtl_move_memory(emu, dst, src, sz);
}

fn NtAllocateVirtualMemory(emu: &mut emu::Emu) {
    let addr_ptr = emu.regs().rcx;
    let size_ptr = emu.regs().rdx;
    let protection_offset = 0x30;
    let protection_addr = emu.regs().rsp + protection_offset;
    let protect_value = emu
        .maps
        .read_dword(protection_addr)
        .expect("Failed to read Protection argument at NtAllocateVirtualMemory");

    let (can_read, can_write, can_execute) = ntdll::protect_to_rwx(protect_value);

    let addr = emu
        .maps
        .read_qword(addr_ptr)
        .expect("bad NtAllocateVirtualMemory address parameter");
    let size = emu
        .maps
        .read_qword(size_ptr)
        .expect("bad NtAllocateVirtualMemory size parameter");

    let do_alloc: bool = if addr == 0 {
        true
    } else {
        emu.maps.is_mapped(addr)
    };

    if size == 0 {
        panic!("NtAllocateVirtualMemory mapping zero bytes.")
    }

    let alloc_addr: u64 = if do_alloc {
        match emu.maps.alloc(size) {
            Some(a) => a,
            None => panic!("/!\\ out of memory cannot allocate ntdll!NtAllocateVirtualMemory "),
        }
    } else {
        addr
    };

    log_red!(
        emu,
        "ntdll!NtAllocateVirtualMemory  addr: 0x{:x} sz: {} alloc: 0x{:x}",
        addr,
        size,
        alloc_addr
    );

    emu.maps
        .create_map(
            format!("valloc_{:x}", alloc_addr).as_str(),
            alloc_addr,
            size,
            Permission::from_flags(can_read, can_write, can_execute),
        )
        .expect("ntdll!NtAllocateVirtualMemory cannot create map");

    if !emu.maps.write_qword(addr_ptr, alloc_addr) {
        panic!("NtAllocateVirtualMemory: cannot write on address pointer");
    }

    emu.regs_mut().rax = constants::STATUS_SUCCESS;
}

fn NtQueryVirtualMemory(emu: &mut emu::Emu) {
    let handle = emu.regs().rcx;
    let addr = emu.regs().rdx;

    log_red!(emu, "ntdll!NtQueryVirtualMemory addr: 0x{:x}", addr);

    if handle != 0xffffffff {
        log::trace!("\tusing handle of remote process {:x}", handle);

        if !helper::handler_exist(handle) {
            log::trace!("\nhandler doesnt exist.");
        }
    }

    let out_meminfo_ptr = emu.regs().r9;

    if !emu.maps.is_mapped(addr) {
        log::trace!(
            "/!\\ ntdll!NtQueryVirtualMemory: querying non maped addr: 0x{:x}",
            addr
        );

        emu.regs_mut().rax = constants::STATUS_INVALID_PARAMETER;
        return;
    }

    let base = emu.maps.get_addr_base(addr).unwrap_or(0);
    let region_size = emu
        .maps
        .get_mem_by_addr(addr)
        .map(|m| m.size() as u64)
        .unwrap_or(0);
    let alloc_protect = constants::PAGE_EXECUTE | constants::PAGE_READWRITE;
    let mem_info = structures::MemoryBasicInformation64 {
        base_address: base,
        allocation_base: base,
        allocation_protect: alloc_protect,
        partition_id: 0,
        reserved: 0,
        region_size,
        state: constants::MEM_COMMIT,
        protect: alloc_protect,
        typ: constants::MEM_PRIVATE,
    };
    mem_info.save(out_meminfo_ptr, &mut emu.maps);

    emu.regs_mut().rax = constants::STATUS_SUCCESS;
}

fn NtProtectVirtualMemory(emu: &mut emu::Emu) {
    let sz = emu.regs().rcx;
    let status = emu.regs().rdx;
    let page_number = emu.regs().r8;
    let page = emu.regs().r9;
    let prot = emu
        .maps
        .read_qword(emu.regs().rsp + 0x20)
        .expect("ntdll!NtProtectVirtualMemory error reading old prot param");

    log_red!(emu, "ntdll!NtProtectVirtualMemory sz: {} {}", sz, prot);

    emu.regs_mut().rax = constants::STATUS_SUCCESS
}

fn memset(emu: &mut emu::Emu) {
    let ptr = emu.regs().rcx;
    let byte = emu.regs().rdx;
    let count = emu.regs().r8;
    ntdll::memset(emu, ptr, byte, count);

    emu.regs_mut().rax = ptr;
}

fn RtlCopyMemory(emu: &mut emu::Emu) {
    let dst = emu.regs().rcx;
    let src = emu.regs().rdx;
    let sz = emu.regs().r8 as usize;
    let result = ntdll::memcpy(emu, dst, src, sz);
    if result == false {
        panic!("RtlCopyMemory failed to copy");
    }
    log_red!(
        emu,
        "** {} ntdll!RtlCopyMemory dst = {:x} src = {:x} sz = {}",
        emu.pos,
        dst,
        src,
        sz
    );
}

fn NtFlushInstructionCache(emu: &mut emu::Emu) {
    let proc_hndl = emu.regs().rcx;
    let addr = emu.regs().rdx;
    let sz = emu.regs().r8;

    log_red!(
        emu,
        "ntdll!NtFlushInstructionCache hndl: {:x} 0x{:x} sz: {}",
        proc_hndl,
        addr,
        sz
    );

    emu.regs_mut().rax = 0;
}

fn RtlAddFunctionTable(emu: &mut emu::Emu) {
    let function_table = emu.regs().rcx;
    let entry_count = emu.regs().rdx;
    let base_address = emu.regs().r8;

    log_red!(emu, "ntdll!RtlAddFunctionTable");

    emu.regs_mut().rax = 1;
}

fn RtlCaptureContext(emu: &mut emu::Emu) {
    let context_record = emu.regs().rcx as usize;
    log_red!(
        emu,
        "** {} ntdll!RtlCaptureContext {:x}",
        emu.pos,
        context_record
    );
}

fn RtlLookupFunctionEntry(emu: &mut emu::Emu) {
    let control_pc = emu.regs().rcx as usize;
    let image_base = emu.regs().rdx as usize;
    let history_table = emu.regs().r8 as usize;
    log_red!(
        emu,
        "** {} ntdll!RtlLookupFunctionEntry {:x} {:x} {:x}",
        emu.pos,
        control_pc,
        image_base,
        history_table
    );
    emu.regs_mut().rax = 0;
}