libmwemu 0.24.3

x86 32/64bits and system internals emulator, for securely emulating malware and other stuff.
Documentation
use crate::emu;
use crate::winapi::winapi32;

use super::{HintNameItem, PE32};

macro_rules! read_u32_le {
    ($raw:expr, $off:expr) => {
        u32::from_le_bytes([
            $raw[$off],
            $raw[$off + 1],
            $raw[$off + 2],
            $raw[$off + 3],
        ])
    };
}

macro_rules! write_u32_le {
    ($raw:expr, $off:expr, $val:expr) => {
        $raw[$off + 0] = ($val & 0x000000ff) as u8;
        $raw[$off + 1] = (($val & 0x0000ff00) >> 8) as u8;
        $raw[$off + 2] = (($val & 0x00ff0000) >> 16) as u8;
        $raw[$off + 3] = (($val & 0xff000000) >> 24) as u8;
    };
}

impl PE32 {
    pub fn pe32_delay_load_binding(&mut self, emu: &mut emu::Emu, base_addr: u32) {
        log::trace!("Delay load binding started for {} ...", self.filename);
        for i in 0..self.delay_load_dir.len() {
            let dld = &self.delay_load_dir[i];
            if dld.name.is_empty() {
                continue;
            }

            if winapi32::kernel32::load_library(emu, &dld.name) == 0 {
                panic!(
                    "cannot found the library `{}` on {}",
                    &dld.name, emu.cfg.maps_folder
                );
            }

            let mut off_name = PE32::vaddr_to_off(&self.sect_hdr, dld.name_table) as usize;
            let mut off_addr =
                PE32::vaddr_to_off(&self.sect_hdr, dld.bound_delay_import_table) as usize;
            let mut rva = dld.bound_delay_import_table;

            loop {
                if self.raw.len() <= off_name + 4 || self.raw.len() <= off_addr + 4 {
                    break;
                }

                let hint = HintNameItem::load(&self.raw, off_name);
                let _addr = read_u32_le!(self.raw, off_addr);
                let off2 = PE32::vaddr_to_off(&self.sect_hdr, hint.func_name_addr) as usize;
                if off2 == 0 {
                    off_name += HintNameItem::size();
                    off_addr += 4;
                    rva += 4;
                    continue;
                }
                let func_name = PE32::read_string(&self.raw, off2 + 2);
                let real_addr = winapi32::kernel32::resolve_api_name(emu, &func_name);
                if real_addr == 0 {
                    break;
                }

                write_u32_le!(self.raw, off_addr, real_addr as u32);
                let patch_addr = base_addr as u64 + rva as u64;
                if let Some(mem) = emu.maps.get_mem_by_addr_mut(patch_addr) {
                    mem.force_write_dword(patch_addr, real_addr as u32);
                }

                off_name += HintNameItem::size();
                off_addr += 4;
                rva += 4;
            }
        }
        log::trace!("delay load bound!");
    }

    pub fn pe32_iat_binding(&mut self, emu: &mut emu::Emu, base_addr: u32) {
        let dbg = false;

        log::trace!(
            "IAT binding started image_import_descriptor.len() = {} ...",
            self.image_import_descriptor.len()
        );

        for i in 0..self.image_import_descriptor.len() {
            let iim_name = self.image_import_descriptor[i].name.clone();
            let original_first_thunk = self.image_import_descriptor[i].original_first_thunk;
            let first_thunk = self.image_import_descriptor[i].first_thunk;

            if iim_name.is_empty() {
                continue;
            }

            if winapi32::kernel32::load_library(emu, &iim_name) == 0 {
                log::trace!("cannot find the library `{}` in maps/windows/x86/", &iim_name);
                continue;
            } else if dbg {
                log::trace!("library `{}` loaded", &iim_name);
            }

            let mut off_name = PE32::vaddr_to_off(&self.sect_hdr, original_first_thunk) as usize;
            let mut off_addr = PE32::vaddr_to_off(&self.sect_hdr, first_thunk) as usize;
            let mut rva = first_thunk;

            loop {
                if self.raw.len() <= off_name + 4 || self.raw.len() <= off_addr + 4 {
                    break;
                }
                let hint = HintNameItem::load(&self.raw, off_name);
                let addr = read_u32_le!(self.raw, off_addr);
                let off2 = PE32::vaddr_to_off(&self.sect_hdr, hint.func_name_addr) as usize;
                if off2 == 0 {
                    off_name += HintNameItem::size();
                    off_addr += 4;
                    rva += 4;
                    continue;
                }
                let func_name = PE32::read_string(&self.raw, off2 + 2);
                let real_addr =
                    winapi32::kernel32::resolve_api_name_in_module(emu, &iim_name, &func_name);
                if dbg {
                    let real_addr1 = winapi32::kernel32::resolve_api_name(emu, &func_name);
                    if real_addr1 != real_addr {
                        log::trace!("--------------------------");
                        let (va, modm, func) = winapi32::kernel32::search_api_name(emu, &func_name);
                        log::trace!(
                            "inport: {}!{}  ldr: {}!{}",
                            &iim_name,
                            &func_name,
                            modm,
                            func
                        );
                        log::trace!(
                            "0x{:x} {}!{}  0x{:x}-> 0x{:x}",
                            addr,
                            iim_name,
                            func_name,
                            off_addr,
                            real_addr
                        );
                        log::trace!(
                            "*********** prev:0x{:x} == new:0x{:x}",
                            real_addr1,
                            real_addr
                        );
                        println!("0x{:x} {} {}", va, modm, func);
                        log::trace!("--------------------------");
                    }
                }
                if real_addr == 0 {
                    break;
                }
                write_u32_le!(self.raw, off_addr, real_addr as u32);
                let patch_addr = base_addr as u64 + rva as u64;
                if emu.maps.is_mapped(patch_addr) {
                    emu.maps.write_dword(patch_addr, real_addr as u32);
                }

                off_name += HintNameItem::size();
                off_addr += 4;
                rva += 4;
            }
        }
        log::trace!("{} IAT Bound.", &self.filename);
    }

    pub fn pe32_import_addr_to_name(&self, paddr: u32) -> String {
        let dbg = false;
        if paddr == 0 {
            return String::new();
        }

        for i in 0..self.image_import_descriptor.len() {
            let iim = &self.image_import_descriptor[i];
            if dbg {
                log::trace!("import: {}", iim.name);
            }

            if iim.name.is_empty() {
                continue;
            }

            let mut off_name = PE32::vaddr_to_off(&self.sect_hdr, iim.original_first_thunk) as usize;
            let mut off_addr = PE32::vaddr_to_off(&self.sect_hdr, iim.first_thunk) as usize;

            loop {
                if self.raw.len() <= off_name + 4 || self.raw.len() <= off_addr + 4 {
                    break;
                }
                let hint = HintNameItem::load(&self.raw, off_name);
                let addr = read_u32_le!(self.raw, off_addr);
                let off2 = PE32::vaddr_to_off(&self.sect_hdr, hint.func_name_addr) as usize;
                if off2 == 0 {
                    off_name += HintNameItem::size();
                    off_addr += 4;
                    continue;
                }

                if addr == paddr {
                    let func_name = PE32::read_string(&self.raw, off2 + 2);
                    return func_name;
                }

                off_name += HintNameItem::size();
                off_addr += 4;
            }
        }
        String::new()
    }
}