From ddcc8534594f8a32b7f2e71394913b2f9a0f7def Mon Sep 17 00:00:00 2001 From: kishou_yusa Date: Mon, 3 Nov 2025 15:53:30 +0700 Subject: [PATCH] Adding support for some API --- .../src/winapi/winapi32/kernel32/mod.rs | 7 ++ crates/libmwemu/src/winapi/winapi32/ntdll.rs | 24 ++++ crates/libmwemu/src/winapi/winapi32/ws2_32.rs | 113 ++++++++++++++++++ .../src/winapi/winapi64/kernel32/mod.rs | 8 +- crates/libmwemu/src/winapi/winapi64/ntdll.rs | 39 ++++++ crates/libmwemu/src/winapi/winapi64/ws2_32.rs | 102 ++++++++++++++++ 6 files changed, 292 insertions(+), 1 deletion(-) diff --git a/crates/libmwemu/src/winapi/winapi32/kernel32/mod.rs b/crates/libmwemu/src/winapi/winapi32/kernel32/mod.rs index f94d2a90..18618f55 100644 --- a/crates/libmwemu/src/winapi/winapi32/kernel32/mod.rs +++ b/crates/libmwemu/src/winapi/winapi32/kernel32/mod.rs @@ -345,6 +345,7 @@ pub use wide_char_to_multi_byte::*; pub use win_exec::*; pub use write_file::*; pub use write_process_memory::*; +use crate::emu::Emu; pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { let api = guess_api_name(emu, addr); @@ -390,6 +391,7 @@ pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { "FreeLibrary" => FreeLibrary(emu), "FreeResource" => FreeResource(emu), "GetACP" => GetACP(emu), + "GetThreadId" => GetThreadId(emu), "GetCommandLineA" => GetCommandLineA(emu), "GetCommandLineW" => GetCommandLineW(emu), "GetComputerNameA" => GetComputerNameA(emu), @@ -545,6 +547,11 @@ pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { String::new() } +fn GetThreadId(emu: &mut Emu) { + emu.stack_pop32(false); + emu.regs_mut().rax = 0x2c2878; +} + lazy_static! { static ref COUNT_READ: Mutex = Mutex::new(0); static ref COUNT_WRITE: Mutex = Mutex::new(0); diff --git a/crates/libmwemu/src/winapi/winapi32/ntdll.rs b/crates/libmwemu/src/winapi/winapi32/ntdll.rs index 667dfe2a..e6f4f3fa 100644 --- a/crates/libmwemu/src/winapi/winapi32/ntdll.rs +++ b/crates/libmwemu/src/winapi/winapi32/ntdll.rs @@ -9,6 +9,8 @@ use crate::winapi::winapi32::kernel32; use crate::maps::mem64::Permission; use scan_fmt::scan_fmt_some; +use crate::emu::Emu; +use crate::winapi::winapi64::kernel32::InitializeCriticalSection; const PAGE_NOACCESS: u32 = 0x01; const PAGE_READONLY: u32 = 0x02; @@ -36,6 +38,8 @@ pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { "NtQueryPerformanceCounter" => NtQueryPerformanceCounter(emu), "RtlGetProcessHeaps" => RtlGetProcessHeaps(emu), "RtlDosPathNameToNtPathName_U" => RtlDosPathNameToNtPathName_U(emu), + "RtlInitializeCriticalSection" => InitializeCriticalSection(emu), + "RtlZeroMemory" => RtlZeroMemory(emu), "NtCreateFile" => NtCreateFile(emu), "RtlFreeHeap" => RtlFreeHeap(emu), "NtQueryInformationFile" => NtQueryInformationFile(emu), @@ -80,6 +84,26 @@ pub fn gateway(addr: u32, emu: &mut emu::Emu) -> String { String::new() } +fn RtlZeroMemory(emu: &mut Emu) { + let dest = emu + .maps + .read_dword(emu.regs().get_esp() + 4) + .expect("bad RtlZeroMemory address pointer parameter") as u64; + let length = emu + .maps + .read_dword(emu.regs().get_esp() + 8) + .expect("bad RtlZeroMemory address length parameter") as u64; + + log_red!( + emu, + "ntdll!RtlZeroMemory dest: 0x{:x} length: {}", + dest, + length + ); + + emu.maps.memset(dest, 0, length as usize); +} + fn NtAllocateVirtualMemory(emu: &mut emu::Emu) { /* __kernel_entry NTSYSCALLAPI NTSTATUS NtAllocateVirtualMemory( diff --git a/crates/libmwemu/src/winapi/winapi32/ws2_32.rs b/crates/libmwemu/src/winapi/winapi32/ws2_32.rs index cfef9e43..79e55b53 100644 --- a/crates/libmwemu/src/winapi/winapi32/ws2_32.rs +++ b/crates/libmwemu/src/winapi/winapi32/ws2_32.rs @@ -63,6 +63,119 @@ lazy_static! { static ref COUNT_RECV: Mutex = Mutex::new(0); } +fn getaddrinfo(emu: &mut emu::Emu) { + let node_name_ptr = emu + .maps + .read_dword(emu.regs().get_esp() + 4) + .expect("ws2_32!getaddrinfo cannot read node_name_ptr"); + let service_name_ptr = emu + .maps + .read_dword(emu.regs().get_esp() + 8) + .expect("ws2_32!getaddrinfo cannot read service_name_ptr"); + let hints_ptr = emu + .maps + .read_dword(emu.regs().get_esp() + 12) + .expect("ws2_32!getaddrinfo cannot read hints_ptr"); + let result_ptr_ptr = emu + .maps + .read_dword(emu.regs().get_esp() + 16) + .expect("ws2_32!getaddrinfo cannot read result_ptr_ptr"); + + let node_name = if node_name_ptr != 0 { + emu.maps.read_string(node_name_ptr) + } else { + "NULL".to_string() + }; + + let service_name = if service_name_ptr != 0 { + emu.maps.read_string(service_name_ptr) + } else { + "NULL".to_string() + }; + + log_red!(emu, "ws2_32!getaddrinfo node: `{}` service: `{}`", node_name, service_name); + + // Read hints if provided + let mut hints_flags = 0; + let mut hints_family = 0; + let mut hints_socktype = 0; + let mut hints_protocol = 0; + + if hints_ptr != 0 { + hints_flags = emu.maps.read_dword(hints_ptr).unwrap_or(0) as i32; + hints_family = emu.maps.read_dword(hints_ptr + 4).unwrap_or(0) as i32; + hints_socktype = emu.maps.read_dword(hints_ptr + 8).unwrap_or(0) as i32; + hints_protocol = emu.maps.read_dword(hints_ptr + 12).unwrap_or(0) as i32; + } + + // Create a dummy ADDRINFO structure + let addrinfo_size = 48; // Size of ADDRINFOA structure (approximate) + let sockaddr_in_size = 16; // Size of sockaddr_in structure + + // Allocate memory for the result + let heap_management = emu.heap_management.as_mut().unwrap(); + let addrinfo_addr = heap_management.allocate((addrinfo_size + sockaddr_in_size + 100) as usize).unwrap(); + let sockaddr_addr = addrinfo_addr + addrinfo_size; + let canonname_addr = sockaddr_addr + sockaddr_in_size; + + // Create a dummy sockaddr_in (IPv4 address 127.0.0.1, port based on service) + let ip_addr = 0x0100007f; // 127.0.0.1 in network byte order + + // Determine port based on service name + let port = if service_name == "http" || service_name == "80" { + 80u16 + } else if service_name == "https" || service_name == "443" { + 443u16 + } else if service_name == "ftp" || service_name == "21" { + 21u16 + } else if service_name == "ssh" || service_name == "22" { + 22u16 + } else if service_name == "smtp" || service_name == "25" { + 25u16 + } else if service_name == "dns" || service_name == "53" { + 53u16 + } else { + service_name.parse().unwrap_or(80u16) + }; + + // Write sockaddr_in structure + emu.maps.write_word(sockaddr_addr, 2); // AF_INET = 2 + emu.maps.write_word(sockaddr_addr + 2, port.to_be()); // Port in network byte order + emu.maps.write_dword(sockaddr_addr + 4, ip_addr); // IP address (127.0.0.1) + emu.maps.memset(sockaddr_addr + 8, 0, 8); // Zero out the rest + + // Write ADDRINFO structure + emu.maps.write_dword(addrinfo_addr, hints_flags as u32); // ai_flags + emu.maps.write_dword(addrinfo_addr + 4, if hints_family != 0 { hints_family as u32 } else { 2 }); // ai_family (AF_INET) + emu.maps.write_dword(addrinfo_addr + 8, if hints_socktype != 0 { hints_socktype as u32 } else { 1 }); // ai_socktype (SOCK_STREAM) + emu.maps.write_dword(addrinfo_addr + 12, if hints_protocol != 0 { hints_protocol as u32 } else { 6 }); // ai_protocol (IPPROTO_TCP) + emu.maps.write_qword(addrinfo_addr + 16, sockaddr_in_size as u64); // ai_addrlen + emu.maps.write_qword(addrinfo_addr + 24, canonname_addr); // ai_canonname + emu.maps.write_qword(addrinfo_addr + 32, sockaddr_addr); // ai_addr + + // Set ai_canonname to the node name or "localhost" + let canon_name = if node_name == "NULL" || node_name.is_empty() || node_name == "localhost" { + "localhost.localdomain".to_string() + } else if node_name == "127.0.0.1" { + "localhost".to_string() + } else { + format!("{}.localdomain", node_name) + }; + emu.maps.write_string(canonname_addr, &canon_name); + + // ai_next is NULL (end of list) + emu.maps.write_qword(addrinfo_addr + 40, 0); + + // Store the result pointer in the ppResult parameter + emu.maps.write_qword(result_ptr_ptr, addrinfo_addr); + + log::info!("\tcreated dummy ADDRINFO for {}:{} at 0x{:x}", node_name, service_name, addrinfo_addr); + log::info!("\tsockaddr at 0x{:x}, canonname at 0x{:x}", sockaddr_addr, canonname_addr); + + // Return 0 for success (WSA error code) + emu.regs_mut().rax = 0; +} + fn WsaStartup(emu: &mut emu::Emu) { log_red!(emu, "ws2_32!WsaStartup"); diff --git a/crates/libmwemu/src/winapi/winapi64/kernel32/mod.rs b/crates/libmwemu/src/winapi/winapi64/kernel32/mod.rs index 5916f216..71293397 100644 --- a/crates/libmwemu/src/winapi/winapi64/kernel32/mod.rs +++ b/crates/libmwemu/src/winapi/winapi64/kernel32/mod.rs @@ -354,7 +354,7 @@ pub use write_console_w::WriteConsoleW; pub use write_file::WriteFile; pub use write_process_memory::WriteProcessMemory; pub use local_free::LocalFree; - +use crate::emu::Emu; // a in RCX, b in RDX, c in R8, d in R9, then e pushed on stack pub fn clear_last_error(emu: &mut emu::Emu) { @@ -447,6 +447,7 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { "GetStartupInfoA" => GetStartupInfoA(emu), "GetStartupInfoW" => GetStartupInfoW(emu), "GetStdHandle" => GetStdHandle(emu), + "GetThreadId" => GetThreadId(emu), "GetSystemDirectoryA" => GetSystemDirectoryA(emu), "GetSystemDirectoryW" => GetSystemDirectoryW(emu), "GetSystemFirmwareTable" => GetSystemFirmwareTable(emu), @@ -563,6 +564,11 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { String::new() } +fn GetThreadId(emu: &mut Emu) { + let hThread = emu.regs().rcx; + emu.regs_mut().rax = 0x2c2878; +} + lazy_static! { pub static ref COUNT_READ: Mutex = Mutex::new(0); pub static ref COUNT_WRITE: Mutex = Mutex::new(0); diff --git a/crates/libmwemu/src/winapi/winapi64/ntdll.rs b/crates/libmwemu/src/winapi/winapi64/ntdll.rs index 39c8dd97..2581d912 100644 --- a/crates/libmwemu/src/winapi/winapi64/ntdll.rs +++ b/crates/libmwemu/src/winapi/winapi64/ntdll.rs @@ -7,11 +7,13 @@ use crate::console::Console; use crate::constants; use crate::context::context64::Context64; use crate::emu; +use crate::emu::Emu; use crate::maps::mem64::Permission; use crate::serialization; use crate::structures; use crate::winapi::helper; use crate::winapi::winapi64::kernel32; +use crate::winapi::winapi64::kernel32::InitializeCriticalSection; const PAGE_NOACCESS: u32 = 0x01; const PAGE_READONLY: u32 = 0x02; @@ -44,6 +46,7 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { "NtQueryPerformanceCounter" => NtQueryPerformanceCounter(emu), "RtlGetProcessHeaps" => RtlGetProcessHeaps(emu), "RtlDosPathNameToNtPathName_U" => RtlDosPathNameToNtPathName_U(emu), + "RtlInitializeCriticalSection" => InitializeCriticalSection(emu), "NtCreateFile" => NtCreateFile(emu), "RtlFreeHeap" => RtlFreeHeap(emu), "NtQueryInformationFile" => NtQueryInformationFile(emu), @@ -65,6 +68,8 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { "NtTerminateThread" => NtTerminateThread(emu), "RtlAddFunctionTable" => RtlAddFunctionTable(emu), "RtlCaptureContext" => RtlCaptureContext(emu), + "RtlMoveMemory" => RtlMoveMemory(emu), + "RtlZeroMemory" => RtlZeroMemory(emu), "RtlLookupFunctionEntry" => RtlLookupFunctionEntry(emu), "strlen" => strlen(emu), "NtSetInformationThread" => NtSetInformationThread(emu), @@ -91,6 +96,40 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { String::new() } +fn RtlZeroMemory(emu: &mut emu::Emu) { + let dest = emu.regs().rcx; + let length = emu.regs().rdx; + + log_red!( + emu, + "ntdll!RtlZeroMemory dest: 0x{:x} length: {}", + dest, + length + ); + + emu.maps.memset(dest, 0, length as usize); +} + + +fn RtlMoveMemory(emu: &mut emu::Emu) { + let dst = emu.regs().rcx; + let src = emu.regs().rdx; + let sz = emu.regs().r8 as usize; + + let result = emu.maps.memcpy(dst, src, sz); + if result == false { + panic!("RtlMoveMemory failed to copy"); + } + + log_red!( + emu, + "** {} ntdll!RtlMoveMemory dst = {:x} src = {:x} sz = {}", + emu.pos, + dst, + src, + sz + ); +} fn NtAllocateVirtualMemory(emu: &mut emu::Emu) { /* diff --git a/crates/libmwemu/src/winapi/winapi64/ws2_32.rs b/crates/libmwemu/src/winapi/winapi64/ws2_32.rs index ea426004..b0803fdd 100644 --- a/crates/libmwemu/src/winapi/winapi64/ws2_32.rs +++ b/crates/libmwemu/src/winapi/winapi64/ws2_32.rs @@ -30,6 +30,7 @@ pub fn gateway(addr: u64, emu: &mut emu::Emu) -> String { "WsaAccept" => WsaAccept(emu), "GetSockName" => GetSockName(emu), "gethostbyname" => gethostbyname(emu), + "getaddrinfo" => getaddrinfo(emu), /* "sendto" => sendto(emu), "recvfrom" => recvfrom(emu), @@ -66,6 +67,107 @@ lazy_static! { static ref COUNT_RECV: Mutex = Mutex::new(0); } +fn getaddrinfo(emu: &mut emu::Emu) { + let node_name_ptr = emu.regs().rcx; + let service_name_ptr = emu.regs().rdx; + let hints_ptr = emu.regs().r8; + let result_ptr_ptr = emu.regs().r9; + + let node_name = if node_name_ptr != 0 { + emu.maps.read_string(node_name_ptr) + } else { + "NULL".to_string() + }; + + let service_name = if service_name_ptr != 0 { + emu.maps.read_string(service_name_ptr) + } else { + "NULL".to_string() + }; + + log_red!(emu, "ws2_32!getaddrinfo node: `{}` service: `{}`", node_name, service_name); + + // Read hints if provided + let mut hints_flags = 0; + let mut hints_family = 0; + let mut hints_socktype = 0; + let mut hints_protocol = 0; + + if hints_ptr != 0 { + hints_flags = emu.maps.read_dword(hints_ptr).unwrap_or(0) as i32; + hints_family = emu.maps.read_dword(hints_ptr + 4).unwrap_or(0) as i32; + hints_socktype = emu.maps.read_dword(hints_ptr + 8).unwrap_or(0) as i32; + hints_protocol = emu.maps.read_dword(hints_ptr + 12).unwrap_or(0) as i32; + } + + // Create a dummy ADDRINFO structure + let addrinfo_size = 48; // Size of ADDRINFOA structure (approximate) + let sockaddr_in_size = 16; // Size of sockaddr_in structure + + // Allocate memory for the result + let heap_management = emu.heap_management.as_mut().unwrap(); + let addrinfo_addr = heap_management.allocate((addrinfo_size + sockaddr_in_size + 100) as usize).unwrap(); + let sockaddr_addr = addrinfo_addr + addrinfo_size; + let canonname_addr = sockaddr_addr + sockaddr_in_size; + + // Create a dummy sockaddr_in (IPv4 address 127.0.0.1, port based on service) + let ip_addr = 0x0100007f; // 127.0.0.1 in network byte order + + // Determine port based on service name + let port = if service_name == "http" || service_name == "80" { + 80u16 + } else if service_name == "https" || service_name == "443" { + 443u16 + } else if service_name == "ftp" || service_name == "21" { + 21u16 + } else if service_name == "ssh" || service_name == "22" { + 22u16 + } else if service_name == "smtp" || service_name == "25" { + 25u16 + } else if service_name == "dns" || service_name == "53" { + 53u16 + } else { + service_name.parse().unwrap_or(80u16) + }; + + // Write sockaddr_in structure + emu.maps.write_word(sockaddr_addr, 2); // AF_INET = 2 + emu.maps.write_word(sockaddr_addr + 2, port.to_be()); // Port in network byte order + emu.maps.write_dword(sockaddr_addr + 4, ip_addr); // IP address (127.0.0.1) + emu.maps.memset(sockaddr_addr + 8, 0, 8); // Zero out the rest + + // Write ADDRINFO structure + emu.maps.write_dword(addrinfo_addr, hints_flags as u32); // ai_flags + emu.maps.write_dword(addrinfo_addr + 4, if hints_family != 0 { hints_family as u32 } else { 2 }); // ai_family (AF_INET) + emu.maps.write_dword(addrinfo_addr + 8, if hints_socktype != 0 { hints_socktype as u32 } else { 1 }); // ai_socktype (SOCK_STREAM) + emu.maps.write_dword(addrinfo_addr + 12, if hints_protocol != 0 { hints_protocol as u32 } else { 6 }); // ai_protocol (IPPROTO_TCP) + emu.maps.write_qword(addrinfo_addr + 16, sockaddr_in_size as u64); // ai_addrlen + emu.maps.write_qword(addrinfo_addr + 24, canonname_addr); // ai_canonname + emu.maps.write_qword(addrinfo_addr + 32, sockaddr_addr); // ai_addr + + // Set ai_canonname to the node name or "localhost" + let canon_name = if node_name == "NULL" || node_name.is_empty() || node_name == "localhost" { + "localhost.localdomain".to_string() + } else if node_name == "127.0.0.1" { + "localhost".to_string() + } else { + format!("{}.localdomain", node_name) + }; + emu.maps.write_string(canonname_addr, &canon_name); + + // ai_next is NULL (end of list) + emu.maps.write_qword(addrinfo_addr + 40, 0); + + // Store the result pointer in the ppResult parameter + emu.maps.write_qword(result_ptr_ptr, addrinfo_addr); + + log::info!("\tcreated dummy ADDRINFO for {}:{} at 0x{:x}", node_name, service_name, addrinfo_addr); + log::info!("\tsockaddr at 0x{:x}, canonname at 0x{:x}", sockaddr_addr, canonname_addr); + + // Return 0 for success (WSA error code) + emu.regs_mut().rax = 0; +} + fn WsaStartup(emu: &mut emu::Emu) { log_red!(emu, "ws2_32!WsaStartup");