libmwemu 0.24.4

x86 32/64bits and system internals emulator, for securely emulating malware and other stuff.
Documentation
use crate::context::context64::Context64;
use crate::debug::console::Console;
use crate::emu;
use crate::windows::{constants, structures};

pub(super) fn dispatch(api: &str, emu: &mut emu::Emu) -> bool {
    match api {
        "ZwQueueApcThread" => ZwQueueApcThread(emu),
        "NtGetContextThread" => NtGetContextThread(emu),
        "RtlExitUserThread" => RtlExitUserThread(emu),
        "NtGetTickCount" => NtGetTickCount(emu),
        "NtQueryPerformanceCounter" => NtQueryPerformanceCounter(emu),
        "RtlGetVersion" => RtlGetVersion(emu),
        "RtlSetUnhandledExceptionFilter" => RtlSetUnhandledExceptionFilter(emu),
        "NtTerminateThread" => NtTerminateThread(emu),
        "NtSetInformationThread" => NtSetInformationThread(emu),
        _ => return false,
    }
    true
}

fn NtGetContextThread(emu: &mut emu::Emu) {
    let handle = emu.regs().rcx;
    let ctx_ptr = emu.regs().rdx;
    let ctx_ptr2 = emu
        .maps
        .read_qword(ctx_ptr)
        .expect("ntdll_NtGetContextThread: error reading context ptr");

    log_red!(emu, "ntdll_NtGetContextThread   ctx:");

    let ctx = Context64::new(&emu.regs());
    ctx.save(ctx_ptr2, &mut emu.maps);

    emu.regs_mut().rax = 0;
}

fn RtlExitUserThread(emu: &mut emu::Emu) {
    log_red!(emu, "ntdll!RtlExitUserThread");
    Console::spawn_console(emu);
    emu.stop();
}

fn ZwQueueApcThread(emu: &mut emu::Emu) {
    let thread_handle = emu.regs().rcx;
    let apc_routine = emu.regs().rdx;
    let apc_ctx = emu.regs().r8;
    let arg1 = emu.regs().r9;
    let arg2 = emu
        .maps
        .read_qword(emu.regs().rsp + 0x20)
        .expect("kernel32!ZwQueueApcThread cannot read arg2");

    log_red!(
        emu,
        "ntdll!ZwQueueApcThread hndl: {} routine: {} ctx: {} arg1: {} arg2: {}",
        thread_handle,
        apc_routine,
        apc_ctx,
        arg1,
        arg2
    );

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

fn NtGetTickCount(emu: &mut emu::Emu) {
    log_red!(emu, "ntdll!NtGetTickCount");
    emu.regs_mut().rax = emu.tick as u64;
}

fn NtQueryPerformanceCounter(emu: &mut emu::Emu) {
    let perf_counter_ptr = emu.regs().rcx;
    let perf_freq_ptr = emu.regs().rdx;

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

    emu.maps.write_dword(perf_counter_ptr, 0);
    emu.regs_mut().rax = constants::STATUS_SUCCESS;
}

fn RtlGetVersion(emu: &mut emu::Emu) {
    let versioninfo_ptr = emu.regs().rcx;

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

    let versioninfo = structures::OsVersionInfoExA::new();
    versioninfo.save(versioninfo_ptr, &mut emu.maps);

    emu.regs_mut().rax = 1;
}

fn RtlSetUnhandledExceptionFilter(emu: &mut emu::Emu) {
    let filter = emu.regs().rcx;

    log_red!(
        emu,
        "ntdll!RtlSetUnhandledExceptionFilter filter: 0x{:x}",
        filter
    );

    emu.set_uef(filter);
    emu.regs_mut().rax = 1;
}

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

    log_red!(emu, "ntdll!NtTerminateThread {:x} {}", handle, exit_status);

    emu.regs_mut().rax = 0;
}

fn NtSetInformationThread(emu: &mut emu::Emu) {
    let thread_handle = emu.regs().rcx;
    let thread_info_class = emu.regs().rdx;
    let thread_info_ptr = emu.regs().r8;
    let thread_info_length = emu.regs().r9;

    log_red!(
        emu,
        "ntdll!NtSetInformationThread handle: 0x{:x} class: {} info_ptr: 0x{:x} length: {}",
        thread_handle,
        thread_info_class,
        thread_info_ptr,
        thread_info_length
    );

    emu.regs_mut().rax = 0x00000000;
}