From 39a509ae96ec9d116d3531abee19766e28bed8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Wed, 11 Sep 2024 22:57:53 +0200 Subject: [PATCH 01/10] zero out entire struct in GetStartupInfoA As I've understand GetStartupInfoA, the caller always passes a pointer to uninitialized memory, and the function will then fill in the values. Before this change, GetStartupInfoA read the value of cb as an input parameter to get the length of the struct. In my program that part of the memory was uninitialized and happened to be 0, so the rest of the values were never zeroed out, leading to garbage data being returned in the other field. This change make sure to zero out the entire struct, and then sets cb to the actual length of the struct. --- win32/src/winapi/kernel32/dll.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/win32/src/winapi/kernel32/dll.rs b/win32/src/winapi/kernel32/dll.rs index afed3cdd..874b5b75 100644 --- a/win32/src/winapi/kernel32/dll.rs +++ b/win32/src/winapi/kernel32/dll.rs @@ -322,8 +322,11 @@ unsafe impl ::memory::Pod for STARTUPINFOA {} pub fn GetStartupInfoA(_machine: &mut Machine, lpStartupInfo: Option<&mut STARTUPINFOA>) -> u32 { // MSVC runtime library passes in uninitialized memory for lpStartupInfo, so don't trust info.cb. let info = lpStartupInfo.unwrap(); - let len = std::cmp::min(info.cb, std::mem::size_of::() as u32); + let len = std::mem::size_of::() as u32; unsafe { info.clear_memory(len) }; + + info.cb = len; + 0 } From fb7f00abf7521d0fad52ec930ac84b4fc03074b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Thu, 12 Sep 2024 13:57:45 +0200 Subject: [PATCH 02/10] add RegCreateKeyA stub --- win32/dll/advapi32.dll | Bin 2048 -> 2048 bytes win32/src/winapi/advapi32.rs | 10 ++++++++++ win32/src/winapi/builtin.rs | 16 +++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/win32/dll/advapi32.dll b/win32/dll/advapi32.dll index dee13499a75dfc71218635e2725ec7e39b7d13f4..e09ef4e8d733e64517cf0c33593e346038cff4ca 100755 GIT binary patch delta 155 zcmZn=Xb_mtz*7FD{QJa~0>+J#4H8;NN=~k1RA)T9c_Cvu6C=-N7MAaflh{}| zK?)gwKwzSxw4{py0|O(F!wSWLKz=F^S59_hQ?M2hU|?tl^7?^zE)cH;;(b62(!<2S g%)r7Bl$!3GlV6, + phkResult: Option<&mut u32>, +) -> u32 { + 0 +} + #[win32_derive::dllexport] pub fn RegCreateKeyExW( _machine: &mut Machine, diff --git a/win32/src/winapi/builtin.rs b/win32/src/winapi/builtin.rs index d439289c..4ccc2919 100644 --- a/win32/src/winapi/builtin.rs +++ b/win32/src/winapi/builtin.rs @@ -25,6 +25,13 @@ pub mod advapi32 { let hKey = ::from_stack(mem, esp + 4u32); winapi::advapi32::RegCloseKey(machine, hKey).to_raw() } + pub unsafe fn RegCreateKeyA(machine: &mut Machine, esp: u32) -> u32 { + let mem = machine.mem().detach(); + let hKey = ::from_stack(mem, esp + 4u32); + let lpSubKey = >::from_stack(mem, esp + 8u32); + let phkResult = >::from_stack(mem, esp + 12u32); + winapi::advapi32::RegCreateKeyA(machine, hKey, lpSubKey, phkResult).to_raw() + } pub unsafe fn RegCreateKeyExW(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); let hKey = ::from_stack(mem, esp + 4u32); @@ -98,6 +105,12 @@ pub mod advapi32 { stack_consumed: 4u32, is_async: false, }; + pub const RegCreateKeyA: Shim = Shim { + name: "RegCreateKeyA", + func: impls::RegCreateKeyA, + stack_consumed: 12u32, + is_async: false, + }; pub const RegCreateKeyExW: Shim = Shim { name: "RegCreateKeyExW", func: impls::RegCreateKeyExW, @@ -117,8 +130,9 @@ pub mod advapi32 { is_async: false, }; } - const SHIMS: [Shim; 4usize] = [ + const SHIMS: [Shim; 5usize] = [ shims::RegCloseKey, + shims::RegCreateKeyA, shims::RegCreateKeyExW, shims::RegQueryValueExW, shims::RegSetValueExW, From da06ed4043fe3495e5db7e545b4ef1a889f022b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Thu, 12 Sep 2024 14:18:02 +0200 Subject: [PATCH 03/10] add RegQueryValueExA stub --- win32/dll/advapi32.dll | Bin 2048 -> 2048 bytes win32/src/winapi/advapi32.rs | 13 +++++++++++++ win32/src/winapi/builtin.rs | 28 +++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/win32/dll/advapi32.dll b/win32/dll/advapi32.dll index e09ef4e8d733e64517cf0c33593e346038cff4ca..0d1bfe10cf2239e1d482b64c8aff745c15f3fe4f 100755 GIT binary patch delta 139 zcmZn=Xb_mtz+!$ZO=MzA0ppp;hKxFs6&b@BF0YSSL5JSur|pUc+X|2mtr~94`O> delta 135 zcmZn=Xb_mtz*7FD{QJa~0>+J#4H8;NN=~k1RA)T9c_Cv3(`H4M`;3zfSU4uJ zv2cQvG5~?VL`7*y7X=0eMj(e3iUWcCR3NUL?8v4f+YDs&1MyrSUJJzgfEc8niGi7c SWpWRj)#mGLnv9bj7^MNT#~$qf diff --git a/win32/src/winapi/advapi32.rs b/win32/src/winapi/advapi32.rs index 3a44d443..a9bc85cc 100644 --- a/win32/src/winapi/advapi32.rs +++ b/win32/src/winapi/advapi32.rs @@ -38,6 +38,19 @@ pub fn RegCloseKey(_machine: &mut Machine, hKey: HKEY) -> u32 { 0 // success } +#[win32_derive::dllexport] +pub fn RegQueryValueExA( + _machine: &mut Machine, + hKey: HKEY, + lpValueName: Option<&str>, + lpReserved: u32, + lpType: Option<&mut u32>, + lpData: u32, + lpcbData: Option<&mut u32>, +) -> u32 { + 2 // ERROR_FILE_NOT_FOUND +} + #[win32_derive::dllexport] pub fn RegQueryValueExW( _machine: &mut Machine, diff --git a/win32/src/winapi/builtin.rs b/win32/src/winapi/builtin.rs index 4ccc2919..816d7804 100644 --- a/win32/src/winapi/builtin.rs +++ b/win32/src/winapi/builtin.rs @@ -57,6 +57,25 @@ pub mod advapi32 { ) .to_raw() } + pub unsafe fn RegQueryValueExA(machine: &mut Machine, esp: u32) -> u32 { + let mem = machine.mem().detach(); + let hKey = ::from_stack(mem, esp + 4u32); + let lpValueName = >::from_stack(mem, esp + 8u32); + let lpReserved = ::from_stack(mem, esp + 12u32); + let lpType = >::from_stack(mem, esp + 16u32); + let lpData = ::from_stack(mem, esp + 20u32); + let lpcbData = >::from_stack(mem, esp + 24u32); + winapi::advapi32::RegQueryValueExA( + machine, + hKey, + lpValueName, + lpReserved, + lpType, + lpData, + lpcbData, + ) + .to_raw() + } pub unsafe fn RegQueryValueExW(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); let hKey = ::from_stack(mem, esp + 4u32); @@ -117,6 +136,12 @@ pub mod advapi32 { stack_consumed: 36u32, is_async: false, }; + pub const RegQueryValueExA: Shim = Shim { + name: "RegQueryValueExA", + func: impls::RegQueryValueExA, + stack_consumed: 24u32, + is_async: false, + }; pub const RegQueryValueExW: Shim = Shim { name: "RegQueryValueExW", func: impls::RegQueryValueExW, @@ -130,10 +155,11 @@ pub mod advapi32 { is_async: false, }; } - const SHIMS: [Shim; 5usize] = [ + const SHIMS: [Shim; 6usize] = [ shims::RegCloseKey, shims::RegCreateKeyA, shims::RegCreateKeyExW, + shims::RegQueryValueExA, shims::RegQueryValueExW, shims::RegSetValueExW, ]; From 9fbb275674137ef7e363ffb105fa7d7801e79200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Fri, 13 Sep 2024 18:08:17 +0200 Subject: [PATCH 04/10] add handles for resources --- win32/src/pe/resources.rs | 4 ++-- win32/src/winapi/builtin.rs | 6 +++--- win32/src/winapi/kernel32/init.rs | 4 +++- win32/src/winapi/kernel32/resource.rs | 29 +++++++++++++++++---------- win32/src/winapi/types.rs | 4 ++++ win32/src/winapi/user32/resource.rs | 2 ++ 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/win32/src/pe/resources.rs b/win32/src/pe/resources.rs index b33a19bf..1d685348 100644 --- a/win32/src/pe/resources.rs +++ b/win32/src/pe/resources.rs @@ -105,7 +105,7 @@ pub fn find_resource( section: &[u8], query_type: ResourceName, query_id: ResourceName, -) -> Option> { +) -> Option> { // Resources are structured as generic nested directories, but in practice there // are always exactly three levels with known semantics. let mut dir = IMAGE_RESOURCE_DIRECTORY::entries(section); @@ -130,5 +130,5 @@ pub fn find_resource( ResourceValue::Data(data) => data, _ => todo!(), }; - Some(data.OffsetToData as usize..(data.OffsetToData + data.Size) as usize) + Some(data.OffsetToData..(data.OffsetToData + data.Size)) } diff --git a/win32/src/winapi/builtin.rs b/win32/src/winapi/builtin.rs index 816d7804..14965f41 100644 --- a/win32/src/winapi/builtin.rs +++ b/win32/src/winapi/builtin.rs @@ -2805,8 +2805,8 @@ pub mod kernel32 { } pub unsafe fn LoadResource(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); - let hModule = ::from_stack(mem, esp + 4u32); - let hResInfo = ::from_stack(mem, esp + 8u32); + let hModule = ::from_stack(mem, esp + 4u32); + let hResInfo = ::from_stack(mem, esp + 8u32); winapi::kernel32::LoadResource(machine, hModule, hResInfo).to_raw() } pub unsafe fn LocalAlloc(machine: &mut Machine, esp: u32) -> u32 { @@ -2822,7 +2822,7 @@ pub mod kernel32 { } pub unsafe fn LockResource(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); - let hResData = ::from_stack(mem, esp + 4u32); + let hResData = ::from_stack(mem, esp + 4u32); winapi::kernel32::LockResource(machine, hResData).to_raw() } pub unsafe fn MulDiv(machine: &mut Machine, esp: u32) -> u32 { diff --git a/win32/src/winapi/kernel32/init.rs b/win32/src/winapi/kernel32/init.rs index 031c714c..f1e36a0b 100644 --- a/win32/src/winapi/kernel32/init.rs +++ b/win32/src/winapi/kernel32/init.rs @@ -1,6 +1,6 @@ //! Process initialization and startup. -use super::{FindHandle, Mappings, DLL, HMODULE, STDERR_HFILE, STDOUT_HFILE}; +use super::{FindHandle, Mappings, ResourceHandle, DLL, HMODULE, STDERR_HFILE, STDOUT_HFILE}; use crate::{ machine::MemImpl, pe, @@ -209,6 +209,7 @@ pub struct State { pub dlls: HashMap, pub resources: pe::IMAGE_DATA_DIRECTORY, + pub resource_handles: Handles, pub files: Handles>, @@ -248,6 +249,7 @@ impl State { env: env_addr, cmdline, resources: Default::default(), + resource_handles: Default::default(), } } diff --git a/win32/src/winapi/kernel32/resource.rs b/win32/src/winapi/kernel32/resource.rs index 9bd0e062..3a6d3bec 100644 --- a/win32/src/winapi/kernel32/resource.rs +++ b/win32/src/winapi/kernel32/resource.rs @@ -1,6 +1,7 @@ #![allow(non_snake_case)] use crate::winapi::kernel32::HMODULE; +use crate::winapi::types::HRSRC; use crate::winapi::user32::HINSTANCE; use crate::{ pe, @@ -12,6 +13,7 @@ use crate::{ Machine, }; use memory::Mem; +use std::ops::Range; const TRACE_CONTEXT: &'static str = "kernel32/resource"; @@ -19,6 +21,8 @@ fn IS_INTRESOURCE(x: u32) -> bool { x >> 16 == 0 } +pub struct ResourceHandle(Range); + /// ResourceKey is the type of queries into the Windows resources system, including /// e.g. LoadResource() as well as LoadBitmap() etc. /// It's parameterized over the type of name to handle both A() and W() variants. @@ -77,18 +81,18 @@ pub fn find_resource<'a>( hInstance: HINSTANCE, typ: ResourceKey<&Str16>, name: ResourceKey<&Str16>, -) -> Option<&'a [u8]> { +) -> Option> { let image = mem.slice(hInstance..); if hInstance == kernel32.image_base { let section = kernel32.resources.as_slice(image)?; - Some(&image[pe::find_resource(section, typ.into_pe(), name.into_pe())?]) + pe::find_resource(section, typ.into_pe(), name.into_pe()).map(|r| (hInstance + r.start)..(hInstance + r.end)) } else { let dll = kernel32.dlls.get(&HMODULE::from_raw(hInstance))?; match dll.dll.resources.clone() { None => return None, Some(resources) => { let section = resources.as_slice(image)?; - Some(&image[pe::find_resource(section, typ.into_pe(), name.into_pe())?]) + pe::find_resource(section, typ.into_pe(), name.into_pe()).map(|r| (hInstance + r.start)..(hInstance + r.end)) } } } @@ -100,7 +104,7 @@ pub fn FindResourceA( hModule: HMODULE, lpName: ResourceKey<&str>, lpType: ResourceKey<&str>, -) -> u32 { +) -> HRSRC { let name = lpName.to_string16(); let type_ = lpType.to_string16(); FindResourceW(machine, hModule, name.as_ref(), type_.as_ref()) @@ -112,7 +116,7 @@ pub fn FindResourceW( hModule: HMODULE, lpName: ResourceKey<&Str16>, lpType: ResourceKey<&Str16>, -) -> u32 { +) -> HRSRC { match find_resource( &machine.state.kernel32, machine.mem(), @@ -120,17 +124,20 @@ pub fn FindResourceW( lpType, lpName, ) { - None => 0, - Some(mem) => machine.mem().offset_of(mem.as_ptr()), + None => HRSRC::null(), + Some(mem) => machine.state.kernel32.resource_handles.add(ResourceHandle(mem)), } } #[win32_derive::dllexport] -pub fn LoadResource(_machine: &mut Machine, hModule: u32, hResInfo: u32) -> u32 { - hResInfo +pub fn LoadResource(machine: &mut Machine, hModule: HMODULE, hResInfo: HRSRC) -> u32 { + hResInfo.to_raw() } #[win32_derive::dllexport] -pub fn LockResource(_machine: &mut Machine, hResData: u32) -> u32 { - hResData +pub fn LockResource(machine: &mut Machine, hResData: HRSRC) -> u32 { + match machine.state.kernel32.resource_handles.get(hResData) { + None => 0, + Some(handle) => handle.0.start, + } } diff --git a/win32/src/winapi/types.rs b/win32/src/winapi/types.rs index f02caa6d..a9bfbffe 100644 --- a/win32/src/winapi/types.rs +++ b/win32/src/winapi/types.rs @@ -15,6 +15,10 @@ pub type HFILE = HANDLE; pub struct HFINDT; pub type HFIND = HANDLE; +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct HRSRCT; +pub type HRSRC = HANDLE; + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct HWNDT; pub type HWND = HANDLE; diff --git a/win32/src/winapi/user32/resource.rs b/win32/src/winapi/user32/resource.rs index 59753b8f..b9689b1c 100644 --- a/win32/src/winapi/user32/resource.rs +++ b/win32/src/winapi/user32/resource.rs @@ -75,6 +75,7 @@ fn load_bitmap( ResourceKey::Id(pe::RT::BITMAP as u32), name, )?; + let buf = machine.mem().slice(buf); let bmp = BitmapRGBA32::parse(buf, None); Some( machine @@ -166,6 +167,7 @@ fn find_string(machine: &Machine, hInstance: HINSTANCE, uID: u32) -> Option<&[u8 ResourceKey::Id(pe::RT::STRING as u32), ResourceKey::Id(resource_id), )?; + let block = machine.mem().slice(block); // Each block is a sequence of two byte length-prefixed strings. // Iterate through them to find the requested index. From f728296625d05578f0d243bac4900c82975f7c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Fri, 13 Sep 2024 18:09:19 +0200 Subject: [PATCH 05/10] implement SizeofResource --- win32/dll/kernel32.dll | Bin 6144 -> 6144 bytes win32/src/winapi/builtin.rs | 15 ++++++++++++++- win32/src/winapi/kernel32/resource.rs | 8 ++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/win32/dll/kernel32.dll b/win32/dll/kernel32.dll index 9f447e7c07e12d3b33828fecbb658edcd7bf0a9b..02fcc8aef40116f4fe2ee3f9d5b589472bbf312d 100755 GIT binary patch delta 738 zcmXZWT}YF06vy%NA5-RVOB75Kq^(GEx)i|#MO2!BH&Y4IK*g77VX!d~e1m7|K)kSA zj|oPgM($1pAJ9a)Q7o{FA%b^WAl--td82~@zd;8+hx3EO;e-l9h0`H(jrVS4Bpfg; z-q4GbOLwTJ>YF~Oa@1#IQEixYo7rx(C%#i}Eas$tyF#Tz99fxearairl#;QieLb!~iBSiw{`A7WQ$3OC;xrWS{^KQG+MwKmZzEA&NC@ zVh0B}!3Au&qKPwCqy&%g3;|4F9vj%hPyEJTB;6Oe1s6);K@)m0g4bBUI$}7+IsU+& zCz1^}%HYk@L|Pd7F@`yO#2UWh0N-(nE0|n-jZ8S6qm3TZ~*1-pansUV-8WQVjKH7!WrVQx{+RsZO1;YA&nqn$f6PjY6wthBFtGk;=4wuxVNUJHpuGu1C(MLJ`F= zd#{6gxk%)X`NU?osF3kIyG?hNiumvpAw-~K3iDXSHzaX@G%RHzxhO^@9-{?a2;&XL zu!wbh#SiS^7-z^R7jcw}E?$-fv?GitKH>{@@Dr!F!Y%A>5f`f9$1}Xb0LC$g4J2@g z6I?>85Xnagd}v0nLKo>{d5ak=U>)1o!x2(A$6sW4MDpN33F;9*7kV*@&q&}H=lF*# zFCDny#|ym1JDr%o99FQ2EhMmy6w;7N9-tO}1kr;b%wQ2~*g_Hq_>Bull}HYXP={9Z zAcBrjVhXcZ!UmE^A&nc@sznOmMm?I*hL;GT4}*we+Pr??QD$*&yUiSVIIN6-a^3;t CvxT_; diff --git a/win32/src/winapi/builtin.rs b/win32/src/winapi/builtin.rs index 14965f41..17595ded 100644 --- a/win32/src/winapi/builtin.rs +++ b/win32/src/winapi/builtin.rs @@ -2989,6 +2989,12 @@ pub mod kernel32 { winapi::kernel32::SetUnhandledExceptionFilter(machine, _lpTopLevelExceptionFilter) .to_raw() } + pub unsafe fn SizeofResource(machine: &mut Machine, esp: u32) -> u32 { + let mem = machine.mem().detach(); + let hModule = ::from_stack(mem, esp + 4u32); + let hResInfo = ::from_stack(mem, esp + 8u32); + winapi::kernel32::SizeofResource(machine, hModule, hResInfo).to_raw() + } pub unsafe fn Sleep(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); let dwMilliseconds = ::from_stack(mem, esp + 4u32); @@ -3986,6 +3992,12 @@ pub mod kernel32 { stack_consumed: 4u32, is_async: false, }; + pub const SizeofResource: Shim = Shim { + name: "SizeofResource", + func: impls::SizeofResource, + stack_consumed: 8u32, + is_async: false, + }; pub const Sleep: Shim = Shim { name: "Sleep", func: impls::Sleep, @@ -4125,7 +4137,7 @@ pub mod kernel32 { is_async: true, }; } - const SHIMS: [Shim; 148usize] = [ + const SHIMS: [Shim; 149usize] = [ shims::AcquireSRWLockExclusive, shims::AcquireSRWLockShared, shims::AddVectoredExceptionHandler, @@ -4251,6 +4263,7 @@ pub mod kernel32 { shims::SetThreadPriority, shims::SetThreadStackGuarantee, shims::SetUnhandledExceptionFilter, + shims::SizeofResource, shims::Sleep, shims::SystemTimeToFileTime, shims::TlsAlloc, diff --git a/win32/src/winapi/kernel32/resource.rs b/win32/src/winapi/kernel32/resource.rs index 3a6d3bec..619e6e1e 100644 --- a/win32/src/winapi/kernel32/resource.rs +++ b/win32/src/winapi/kernel32/resource.rs @@ -141,3 +141,11 @@ pub fn LockResource(machine: &mut Machine, hResData: HRSRC) -> u32 { Some(handle) => handle.0.start, } } + +#[win32_derive::dllexport] +pub fn SizeofResource(machine: &mut Machine, hModule: HMODULE, hResInfo: HRSRC) -> u32 { + match machine.state.kernel32.resource_handles.get(hResInfo) { + None => 0, + Some(handle) => handle.0.len() as u32, + } +} From 019de547010795e01c057ba249b814e6f545ebe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Wed, 11 Sep 2024 21:34:04 +0200 Subject: [PATCH 06/10] add stub shell32 dll --- win32/Makefile | 2 +- win32/dll/shell32.dll | Bin 0 -> 1536 bytes win32/src/winapi/builtin.rs | 21 +++++++++++++++++++++ win32/src/winapi/mod.rs | 4 +++- win32/src/winapi/shell32.rs | 0 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100755 win32/dll/shell32.dll create mode 100644 win32/src/winapi/shell32.rs diff --git a/win32/Makefile b/win32/Makefile index 1afac736..ffebd5d5 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -1,4 +1,4 @@ -DLL_SRC=advapi32.rs bass.rs ddraw/ dsound.rs gdi32/ kernel32/ ntdll.rs ole32.rs oleaut32.rs retrowin32_test.rs ucrtbase.rs vcruntime140.rs version.rs user32/ winmm/ +DLL_SRC=advapi32.rs bass.rs ddraw/ dsound.rs gdi32/ kernel32/ ntdll.rs ole32.rs oleaut32.rs retrowin32_test.rs shell32.rs ucrtbase.rs vcruntime140.rs version.rs user32/ winmm/ DLLS=$(foreach dll,$(DLL_SRC),src/winapi/$(dll)) src/winapi/builtin.rs: Makefile derive/src/*.rs src/*.rs src/winapi/* src/winapi/*/* cargo run -p win32-derive -- --dll-dir dll --builtins $@ $(DLLS) diff --git a/win32/dll/shell32.dll b/win32/dll/shell32.dll new file mode 100755 index 0000000000000000000000000000000000000000..7920520a6b36d4d25b11f940c4e4590938a7ca49 GIT binary patch literal 1536 zcmeZ`s$gJbU|?VYVr1Ze%)!B~0E+X;@8V)}H%CSL(VKjpRPyp%)W(EhKmw*aEYT-1L3lbs)0L_pgMLhwvdPOOTC5cco jp?-n68>ZEPfdPm{!DtB3Cj?-55S(4;W96tVgCqn1OQIa( literal 0 HcmV?d00001 diff --git a/win32/src/winapi/builtin.rs b/win32/src/winapi/builtin.rs index 17595ded..dc7423d0 100644 --- a/win32/src/winapi/builtin.rs +++ b/win32/src/winapi/builtin.rs @@ -4457,6 +4457,27 @@ pub mod retrowin32_test { raw: std::include_bytes!("../../dll/retrowin32_test.dll"), }; } +pub mod shell32 { + use super::*; + mod impls { + use crate::{ + machine::Machine, + winapi::{self, stack_args::*, types::*}, + }; + use memory::Extensions; + use winapi::shell32::*; + } + mod shims { + use super::impls; + use super::Shim; + } + const SHIMS: [Shim; 0usize] = []; + pub const DLL: BuiltinDLL = BuiltinDLL { + file_name: "shell32.dll", + shims: &SHIMS, + raw: std::include_bytes!("../../dll/shell32.dll"), + }; +} pub mod ucrtbase { use super::*; mod impls { diff --git a/win32/src/winapi/mod.rs b/win32/src/winapi/mod.rs index e0b95f43..b9001eee 100644 --- a/win32/src/winapi/mod.rs +++ b/win32/src/winapi/mod.rs @@ -16,6 +16,7 @@ mod ntdll; mod ole32; mod oleaut32; mod retrowin32_test; +mod shell32; mod stack_args; pub mod types; mod ucrtbase; @@ -38,7 +39,7 @@ impl<'a> std::fmt::Display for ImportSymbol<'a> { } } -pub const DLLS: [builtin::BuiltinDLL; 15] = [ +pub const DLLS: [builtin::BuiltinDLL; 16] = [ builtin::advapi32::DLL, builtin::bass::DLL, builtin::ddraw::DLL, @@ -48,6 +49,7 @@ pub const DLLS: [builtin::BuiltinDLL; 15] = [ builtin::ntdll::DLL, builtin::ole32::DLL, builtin::oleaut32::DLL, + builtin::shell32::DLL, builtin::ucrtbase::DLL, builtin::user32::DLL, builtin::vcruntime140::DLL, diff --git a/win32/src/winapi/shell32.rs b/win32/src/winapi/shell32.rs new file mode 100644 index 00000000..e69de29b From a042859377ee22ef3c11e2121636bdb12561df88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Thu, 12 Sep 2024 13:56:01 +0200 Subject: [PATCH 07/10] handle non-ascii in str16 to_string --- win32/src/str16.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/win32/src/str16.rs b/win32/src/str16.rs index d8a081ae..2596ef14 100644 --- a/win32/src/str16.rs +++ b/win32/src/str16.rs @@ -48,16 +48,7 @@ impl Str16 { } pub fn to_string(&self) -> String { - self.0 - .iter() - .map(|&c| { - if c > 0xFF { - // TODO - panic!("unhandled non-ascii {:?}", char::from_u32(c as u32)); - } - c as u8 as char - }) - .collect() + String::from_utf16(&self.0).unwrap() } } From 7e7ff8891ca01614ebb2104cc02c9ca2e4f876ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Thu, 12 Sep 2024 14:19:28 +0200 Subject: [PATCH 08/10] implement SetCurrentDirectoryA --- cli/src/host.rs | 5 +++++ web/glue/src/host.rs | 4 ++++ win32/dll/kernel32.dll | Bin 6144 -> 6144 bytes win32/src/host.rs | 2 ++ win32/src/winapi/builtin.rs | 14 +++++++++++++- win32/src/winapi/kernel32/file.rs | 25 +++++++++++++++++++++++++ 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/cli/src/host.rs b/cli/src/host.rs index fe35d854..94fdef7d 100644 --- a/cli/src/host.rs +++ b/cli/src/host.rs @@ -150,6 +150,11 @@ impl win32::Host for EnvRef { Ok(host_to_windows_path(&path)) } + fn set_current_dir(&self, path: &WindowsPath) -> Result<(), u32> { + let path = windows_to_host_path(path); + std::env::set_current_dir(path).map_err(|e| io_error_to_win32(&e)) + } + fn open(&self, path: &WindowsPath, options: FileOptions) -> Result, u32> { let path = windows_to_host_path(path); let result = std::fs::File::options() diff --git a/web/glue/src/host.rs b/web/glue/src/host.rs index 32fb2d84..751a842c 100644 --- a/web/glue/src/host.rs +++ b/web/glue/src/host.rs @@ -345,6 +345,10 @@ impl win32::Host for JsHost { todo!() } + fn set_current_dir(&self, path: &WindowsPath) -> Result<(), u32> { + todo!("set_current_dir {path}") + } + fn create_dir(&self, path: &WindowsPath) -> Result<(), u32> { todo!("create_dir {path}") } diff --git a/win32/dll/kernel32.dll b/win32/dll/kernel32.dll index 02fcc8aef40116f4fe2ee3f9d5b589472bbf312d..73e873caac8f5c28cd0f43da939db77b8c0107e7 100755 GIT binary patch delta 746 zcmXZXOGs2<6u|NGU1ro$vN9hOkxo8Fz2jq{xrx*?h#@9HjDiAR$be)Fjxa-V2MHyp z=ys{hHr7C(NCcNiNWs^vv`A2JNTEP57orQ%MMC`r5B$!HvpJEnNZIp<p#?$o;|)eJg*g6T z9|=VwS#YBY^|)PRh;+~xc!DTCVgid;!zOm26^o=G6BnVQ3SKm#6TNtiNyM=QO&3YU zdFZ$dAN&Xzq-S`GQGCG+77)iT>_T}&&OpaC_|Soec#0^-5yN-<#tsgUT*BulL?yhq zi{N23NyGSnub9IER9q>B-O9>$QoEd}v1>`)gSWcUtx;Pvo%;Njs(^dx%TCd{F5`#>rg zGvyle%gUoW)m^ozkE;&#*~qDcS?{-643G7@(s!+vcQxkPfBQn6PC1*KZd?#i472|Y zGcUSCs_jOg#$i$q^$}ZGYr81o#}LNw9IueZ0zP03C6sZ9x(<=^@Zu^$xQ!@c(C`|0 zEMXO2u!TMRM!j3aVNDF-MBaBF=Ci09hi45Lj3E!}V9aL}xlZUU-2p4=9#4SYe6f-bT#2$`d=@N0k zg Result; + /// Sets the absolute (Windows-style) path of the current working directory. + fn set_current_dir(&self, path: &WindowsPath) -> Result<(), u32>; /// Open a file at the given (Windows-style) path. fn open(&self, path: &WindowsPath, options: FileOptions) -> Result, u32>; /// Retrieve file or directory metadata at the given (Windows-style) path. diff --git a/win32/src/winapi/builtin.rs b/win32/src/winapi/builtin.rs index dc7423d0..ef5b0845 100644 --- a/win32/src/winapi/builtin.rs +++ b/win32/src/winapi/builtin.rs @@ -2898,6 +2898,11 @@ pub mod kernel32 { let _add = ::from_stack(mem, esp + 8u32); winapi::kernel32::SetConsoleCtrlHandler(machine, _handlerRoutine, _add).to_raw() } + pub unsafe fn SetCurrentDirectoryA(machine: &mut Machine, esp: u32) -> u32 { + let mem = machine.mem().detach(); + let lpPathName = >::from_stack(mem, esp + 4u32); + winapi::kernel32::SetCurrentDirectoryA(machine, lpPathName).to_raw() + } pub unsafe fn SetEndOfFile(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); let hFile = ::from_stack(mem, esp + 4u32); @@ -3914,6 +3919,12 @@ pub mod kernel32 { stack_consumed: 8u32, is_async: false, }; + pub const SetCurrentDirectoryA: Shim = Shim { + name: "SetCurrentDirectoryA", + func: impls::SetCurrentDirectoryA, + stack_consumed: 4u32, + is_async: false, + }; pub const SetEndOfFile: Shim = Shim { name: "SetEndOfFile", func: impls::SetEndOfFile, @@ -4137,7 +4148,7 @@ pub mod kernel32 { is_async: true, }; } - const SHIMS: [Shim; 149usize] = [ + const SHIMS: [Shim; 150usize] = [ shims::AcquireSRWLockExclusive, shims::AcquireSRWLockShared, shims::AddVectoredExceptionHandler, @@ -4250,6 +4261,7 @@ pub mod kernel32 { shims::ReleaseSRWLockShared, shims::RemoveDirectoryA, shims::SetConsoleCtrlHandler, + shims::SetCurrentDirectoryA, shims::SetEndOfFile, shims::SetEvent, shims::SetFileAttributesA, diff --git a/win32/src/winapi/kernel32/file.rs b/win32/src/winapi/kernel32/file.rs index 30219709..86596e1b 100644 --- a/win32/src/winapi/kernel32/file.rs +++ b/win32/src/winapi/kernel32/file.rs @@ -754,6 +754,31 @@ pub fn GetCurrentDirectoryA(machine: &mut Machine, nBufferLength: u32, lpBuffer: out_bytes.len() as u32 } +#[win32_derive::dllexport] +pub fn SetCurrentDirectoryA(machine: &mut Machine, lpPathName: Option<&str>) -> bool { + let Some(path_name) = lpPathName else { + log::debug!("SetCurrentDirectoryA failed: null lpPathName"); + set_last_error(machine, ERROR_INVALID_DATA); + return false; + }; + + let path = WindowsPath::new(path_name); + match machine.host.set_current_dir(path) { + Ok(()) => { + set_last_error(machine, ERROR_SUCCESS); + true + } + Err(code) => { + log::debug!( + "SetCurrentDirectoryA({path_name:?}) failed: {}", + win32_error_str(code) + ); + set_last_error(machine, code); + false + } + } +} + #[repr(C)] #[derive(Debug)] pub struct WIN32_FIND_DATAA { From 82379defa24dff3522aed843952f829a85deefae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Thu, 12 Sep 2024 14:38:47 +0200 Subject: [PATCH 09/10] wip: temporary give back ProgramFilesDir --- cli/src/host.rs | 1 + win32/src/winapi/advapi32.rs | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cli/src/host.rs b/cli/src/host.rs index 94fdef7d..371b935b 100644 --- a/cli/src/host.rs +++ b/cli/src/host.rs @@ -152,6 +152,7 @@ impl win32::Host for EnvRef { fn set_current_dir(&self, path: &WindowsPath) -> Result<(), u32> { let path = windows_to_host_path(path); + log::info!("set_current_dir {:?}", path); std::env::set_current_dir(path).map_err(|e| io_error_to_win32(&e)) } diff --git a/win32/src/winapi/advapi32.rs b/win32/src/winapi/advapi32.rs index a9bc85cc..a565e2af 100644 --- a/win32/src/winapi/advapi32.rs +++ b/win32/src/winapi/advapi32.rs @@ -1,10 +1,14 @@ #![allow(non_snake_case)] +use memory::ExtensionsMut; + use super::types::Str16; use crate::machine::Machine; const TRACE_CONTEXT: &'static str = "advapi32"; +const REG_SZ: u32 = 0x00000001; // A string. + pub type HKEY = u32; #[win32_derive::dllexport] @@ -40,7 +44,7 @@ pub fn RegCloseKey(_machine: &mut Machine, hKey: HKEY) -> u32 { #[win32_derive::dllexport] pub fn RegQueryValueExA( - _machine: &mut Machine, + machine: &mut Machine, hKey: HKEY, lpValueName: Option<&str>, lpReserved: u32, @@ -48,6 +52,34 @@ pub fn RegQueryValueExA( lpData: u32, lpcbData: Option<&mut u32>, ) -> u32 { + if matches!(lpValueName, Some("ProgramFilesDir")) { + // const PROGRAM_FILES: &str = "C:\\Program Files"; + const PROGRAM_FILES: &str = "C:\\Users\\linus\\Program Files"; + + if let Some(lpType) = lpType { + *lpType = REG_SZ; + } + + if lpData != 0 { + let in_out_len = lpcbData.unwrap(); + + if *in_out_len <= PROGRAM_FILES.len() as u32 { + return 234; // ERROR_MORE_DATA + } + + *in_out_len = (PROGRAM_FILES.len() as u32) + 1; + + let buf = machine.mem().sub32_mut(lpData, *in_out_len); + + buf[..PROGRAM_FILES.len()].copy_from_slice(PROGRAM_FILES.as_bytes()); + buf[PROGRAM_FILES.len()] = 0; + } else if let Some(lpcbData) = lpcbData { + *lpcbData = (PROGRAM_FILES.len() as u32) + 1; + } + + return 0; + } + 2 // ERROR_FILE_NOT_FOUND } From 85127348b91e7e04ed7a66b63ebf7a3970770109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Fri, 13 Sep 2024 17:14:11 +0200 Subject: [PATCH 10/10] add stub SetEnvironmentVariableA --- win32/dll/kernel32.dll | Bin 6144 -> 6144 bytes win32/src/winapi/builtin.rs | 15 ++++++++++++++- win32/src/winapi/kernel32/misc.rs | 9 +++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/win32/dll/kernel32.dll b/win32/dll/kernel32.dll index 73e873caac8f5c28cd0f43da939db77b8c0107e7..d97e52b8860fba914a9a123f7efb97455317ae64 100755 GIT binary patch delta 751 zcmXZYPe{{o7{~GFyXO2iDi=jF66c|*+tfNN@FJ5y$Y@3MXA^??2NLvWS`51M`+*}7 zJUD-_1tDS4pL7^>-$D<(9zG8|m*=tCthQ;(x$D2* zlTO`sY#g#rtAOoO*VR}1p7N`bo>P|7?r@da7oAl);95~L70$~2eW4DgeJ8x<>O~Yo z_P@)_xdxF+9jQ3(P=+0^ikd4Pk+Y{nqUeW(Da_&pULucW{J?Ki`$g&zLpyaWw6gHA-z*KCT65+;#B4zI9)Zz$p~N^l26j=_fz!sx_R+(Z%+n8ODYunl)m z#0x*d=t2y4FmBQw;u+@g7GJQ60ya@Xbx5QRVO&BCqj-QUa>!#DMQq_fi--qx2%#O_ zxPf7qNMvamd3?k=e&QE);A-V!w4)1G(2Eg_BaO#+4vjZ>k0q?3s7vlvr7}8raJKx2 bksKTwF@^_>yVnw9gNfdufrx&0wAQf)WuuWO delta 729 zcmXZXOGs346vy%Nzs!tQK7vvwMAS)hbgnsquT7|tZU&hIK@mSP3!Ws}15#b^VD%fLoCJHSYN-zj4LUJLrP^hoqfzRQ04xGh_2BX38sO#-?DAyi* zW^AYHauv||s#WdjUR9*NId4?drE6Voo#%EtLC>DjCm#1ivg^vljZoL^{Onr~@p&##A8IzhY?I- z1)KPQPdLCa&XMI8G5umm9ibUd&<7g}c!$sUgEJ%*i`+l~DsdlSbfO1Cn8G5qk-$&< zg{MTs3qNYmfHriMSRxi-6frDg6Z<&8FPy>%h@>D3w_&0NA+#WZe!RvO5;%roilie4 zChj4Or|88?i#CHrtl>R&kia2Mp-M$=!bBs&=)wz(A%=Ctv5W6G!8xwo<#QCH3L!i~ z4{Wr}(dMy%kJ!N%{J=kW%R~xMjyg1<1KsGyFl::from_stack(mem, esp + 4u32); winapi::kernel32::SetEndOfFile(machine, hFile).to_raw() } + pub unsafe fn SetEnvironmentVariableA(machine: &mut Machine, esp: u32) -> u32 { + let mem = machine.mem().detach(); + let name = >::from_stack(mem, esp + 4u32); + let value = >::from_stack(mem, esp + 8u32); + winapi::kernel32::SetEnvironmentVariableA(machine, name, value).to_raw() + } pub unsafe fn SetEvent(machine: &mut Machine, esp: u32) -> u32 { let mem = machine.mem().detach(); let hEvent = >::from_stack(mem, esp + 4u32); @@ -3931,6 +3937,12 @@ pub mod kernel32 { stack_consumed: 4u32, is_async: false, }; + pub const SetEnvironmentVariableA: Shim = Shim { + name: "SetEnvironmentVariableA", + func: impls::SetEnvironmentVariableA, + stack_consumed: 8u32, + is_async: false, + }; pub const SetEvent: Shim = Shim { name: "SetEvent", func: impls::SetEvent, @@ -4148,7 +4160,7 @@ pub mod kernel32 { is_async: true, }; } - const SHIMS: [Shim; 150usize] = [ + const SHIMS: [Shim; 151usize] = [ shims::AcquireSRWLockExclusive, shims::AcquireSRWLockShared, shims::AddVectoredExceptionHandler, @@ -4263,6 +4275,7 @@ pub mod kernel32 { shims::SetConsoleCtrlHandler, shims::SetCurrentDirectoryA, shims::SetEndOfFile, + shims::SetEnvironmentVariableA, shims::SetEvent, shims::SetFileAttributesA, shims::SetFilePointer, diff --git a/win32/src/winapi/kernel32/misc.rs b/win32/src/winapi/kernel32/misc.rs index f1cb07ee..decaeb34 100644 --- a/win32/src/winapi/kernel32/misc.rs +++ b/win32/src/winapi/kernel32/misc.rs @@ -98,6 +98,15 @@ pub fn GetEnvironmentVariableW( false } +#[win32_derive::dllexport] +pub fn SetEnvironmentVariableA( + _machine: &mut Machine, + name: Option<&str>, + value: Option<&str>, +) -> bool { + true +} + #[derive(Debug, win32_derive::TryFromEnum)] pub enum ProcessorFeature { FLOATING_POINT_PRECISION_ERRATA = 0,