diff --git a/CMakeLists.txt b/CMakeLists.txt index ca6d742..33dff39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,5 @@ cmake_minimum_required(VERSION 3.13) -set(CMAKE_C_FLAGS_INIT "-m32") -set(CMAKE_CXX_FLAGS_INIT "-m32 -fno-exceptions -fno-rtti") -set(CMAKE_EXE_LINKER_FLAGS_INIT "-m32") -set(CMAKE_SHARED_LINKER_FLAGS_INIT "-m32") - project(wibo LANGUAGES ASM C CXX) set(WIBO_VERSION "" CACHE STRING "Version string for the wibo binary; if empty, attempts to use git describe") @@ -46,11 +41,21 @@ configure_file( @ONLY ) +option(WIBO_64 "Build wibo for 64-bit host" OFF) option(WIBO_ENABLE_FIXTURE_TESTS "Enable Win32 fixture tests (requires i686-w64-mingw32)" ON) option(WIBO_ENABLE_LIBURING "Enable liburing for asynchronous I/O" OFF) set(WIBO_ENABLE_LTO "AUTO" CACHE STRING "Enable link-time optimization (LTO)") set_property(CACHE WIBO_ENABLE_LTO PROPERTY STRINGS "AUTO" "ON" "OFF") +add_compile_options( + $,-m64,-m32> + $<$:-fno-exceptions> + $<$:-fno-rtti> +) +add_link_options( + $,-m64,-m32> +) + if (WIBO_ENABLE_LTO STREQUAL "AUTO") if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") include(CheckIPOSupported) @@ -88,6 +93,10 @@ FetchContent_MakeAvailable(mimalloc) # Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1` target_compile_options(mimalloc-obj PRIVATE -Wno-psabi) target_compile_definitions(mimalloc-obj PRIVATE MI_USE_BUILTIN_THREAD_POINTER=1) +if (WIBO_64) + # Disable a noisy warning on startup + target_compile_definitions(mimalloc-obj PRIVATE MI_DEBUG=0) +endif() if (WIBO_ENABLE_LIBURING) FetchContent_Declare( @@ -126,12 +135,12 @@ endif() add_executable(wibo dll/advapi32.cpp + dll/advapi32/md5.c dll/advapi32/processthreadsapi.cpp dll/advapi32/securitybaseapi.cpp dll/advapi32/winbase.cpp dll/advapi32/wincrypt.cpp dll/advapi32/winreg.cpp - dll/advapi32/md5.c dll/bcrypt.cpp dll/crt.cpp dll/kernel32.cpp @@ -144,8 +153,8 @@ add_executable(wibo dll/kernel32/interlockedapi.cpp dll/kernel32/ioapiset.cpp dll/kernel32/libloaderapi.cpp - dll/kernel32/namedpipeapi.cpp dll/kernel32/memoryapi.cpp + dll/kernel32/namedpipeapi.cpp dll/kernel32/processenv.cpp dll/kernel32/processthreadsapi.cpp dll/kernel32/profileapi.cpp @@ -162,8 +171,8 @@ add_executable(wibo dll/mscoree.cpp dll/msvcrt.cpp dll/ntdll.cpp - dll/rpcrt4.cpp dll/ole32.cpp + dll/rpcrt4.cpp dll/user32.cpp dll/vcruntime.cpp dll/version.cpp @@ -173,21 +182,22 @@ add_executable(wibo src/errors.cpp src/files.cpp src/handles.cpp - src/loader.cpp src/heap.cpp + src/loader.cpp src/main.cpp src/modules.cpp src/processes.cpp src/resources.cpp + src/setup.S src/strutil.cpp src/tls.cpp ) target_compile_definitions(wibo PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64) target_compile_features(wibo PRIVATE cxx_std_20) target_compile_options(wibo PRIVATE -Wall -Wextra) -target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x90000000) +target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x70000000) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(wibo PRIVATE -fno-pie -maccumulate-outgoing-args) + target_compile_options(wibo PRIVATE -maccumulate-outgoing-args) target_link_options(wibo PRIVATE -maccumulate-outgoing-args) endif() target_include_directories(wibo PRIVATE dll src ${WIBO_GENERATED_HEADER_DIR}) @@ -242,15 +252,17 @@ function(wibo_codegen_module) --dll ${module_NAME} --headers ${module_HEADERS} --namespace ${module_NAME} - --arch x86 + --arch $,x86_64,x86> --out-asm ${out_asm} --out-hdr ${out_hdr} -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}/dll -I ${CMAKE_CURRENT_SOURCE_DIR}/src - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_trampolines.py ${module_HEADERS}) + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_trampolines.py + ${module_HEADERS} + ) target_sources(wibo PRIVATE ${out_asm}) - set_source_files_properties(${out_asm} PROPERTIES COMPILE_FLAGS "-m32") + set_source_files_properties(${out_asm} PROPERTIES COMPILE_FLAGS $,-m64,-m32>) endfunction() wibo_codegen_module(NAME advapi32 HEADERS diff --git a/CMakePresets.json b/CMakePresets.json index fa89127..95cdee2 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -53,6 +53,46 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } + }, + { + "name": "debug64", + "displayName": "Debug (64-bit)", + "inherits": ["ninja-base"], + "binaryDir": "${sourceDir}/build/debug64", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "WIBO_64": "ON" + } + }, + { + "name": "release64", + "displayName": "Release (64-bit)", + "inherits": ["ninja-base"], + "binaryDir": "${sourceDir}/build/release64", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "WIBO_64": "ON" + } + }, + { + "name": "debug64-clang", + "displayName": "Debug (64-bit, Clang)", + "inherits": ["ninja-base", "clang-base"], + "binaryDir": "${sourceDir}/build/debug64-clang", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "WIBO_64": "ON" + } + }, + { + "name": "release64-clang", + "displayName": "Release (64-bit, Clang)", + "inherits": ["ninja-base", "clang-base"], + "binaryDir": "${sourceDir}/build/release64-clang", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "WIBO_64": "ON" + } } ], "buildPresets": [ @@ -83,6 +123,34 @@ "configurePreset": "release-clang", "targets": ["wibo", "wibo_test_fixtures"], "configuration": "Release" + }, + { + "name": "debug64", + "displayName": "Build (Debug, 64-bit)", + "configurePreset": "debug64", + "targets": ["wibo", "wibo_test_fixtures"], + "configuration": "Debug" + }, + { + "name": "release64", + "displayName": "Build (Release, 64-bit)", + "configurePreset": "release64", + "targets": ["wibo", "wibo_test_fixtures"], + "configuration": "Release" + }, + { + "name": "debug64-clang", + "displayName": "Build (Debug, 64-bit, Clang)", + "configurePreset": "debug64-clang", + "targets": ["wibo", "wibo_test_fixtures"], + "configuration": "Debug" + }, + { + "name": "release64-clang", + "displayName": "Build (Release, 64-bit, Clang)", + "configurePreset": "release64-clang", + "targets": ["wibo", "wibo_test_fixtures"], + "configuration": "Release" } ], "testPresets": [ @@ -125,6 +193,46 @@ "outputOnFailure": true, "shortProgress": true } + }, + { + "name": "debug64", + "displayName": "Run tests (Debug, 64-bit)", + "configurePreset": "debug64", + "configuration": "Debug", + "output": { + "outputOnFailure": true, + "shortProgress": true + } + }, + { + "name": "release64", + "displayName": "Run tests (Release, 64-bit)", + "configurePreset": "release64", + "configuration": "Release", + "output": { + "outputOnFailure": true, + "shortProgress": true + } + }, + { + "name": "debug64-clang", + "displayName": "Run tests (Debug, 64-bit, Clang)", + "configurePreset": "debug64-clang", + "configuration": "Debug", + "output": { + "outputOnFailure": true, + "shortProgress": true + } + }, + { + "name": "release64-clang", + "displayName": "Run tests (Release, 64-bit, Clang)", + "configurePreset": "release64-clang", + "configuration": "Release", + "output": { + "outputOnFailure": true, + "shortProgress": true + } } ] } diff --git a/dll/advapi32/internal.h b/dll/advapi32/internal.h index 1ea1a11..d57a15c 100644 --- a/dll/advapi32/internal.h +++ b/dll/advapi32/internal.h @@ -6,8 +6,6 @@ constexpr DWORD SECURITY_LOCAL_SYSTEM_RID = 18; -constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5}; - struct TokenObject : ObjectBase { static constexpr ObjectType kType = ObjectType::Token; diff --git a/dll/advapi32/securitybaseapi.cpp b/dll/advapi32/securitybaseapi.cpp index c91bc6d..6a276ff 100644 --- a/dll/advapi32/securitybaseapi.cpp +++ b/dll/advapi32/securitybaseapi.cpp @@ -6,6 +6,7 @@ #include "handles.h" #include "internal.h" #include "kernel32/internal.h" +#include "types.h" #include #include @@ -13,6 +14,8 @@ namespace { +constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5}; + constexpr size_t kAceAlignment = 4; constexpr DWORD ERROR_REVISION_MISMATCH = 1306; constexpr DWORD ERROR_INVALID_ACL = 1336; @@ -202,14 +205,14 @@ BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask return TRUE; } -BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) { +BOOL WINAPI FindFirstFreeAce(PACL pAcl, GUEST_PTR *pAce) { HOST_CONTEXT_GUARD(); DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce); if (!pAce) { kernel32::setLastError(ERROR_INVALID_PARAMETER); return FALSE; } - *pAce = nullptr; + *pAce = GUEST_NULL; if (!pAcl) { kernel32::setLastError(ERROR_INVALID_PARAMETER); return FALSE; @@ -220,13 +223,13 @@ BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) { kernel32::setLastError(ERROR_INVALID_ACL); return FALSE; } - *pAce = reinterpret_cast(pAcl) + used; + *pAce = toGuestPtr(reinterpret_cast(pAcl) + used); pAcl->AclSize = static_cast(std::max(pAcl->AclSize, used)); return TRUE; } -BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, - LPBOOL lpbDaclDefaulted) { +BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, GUEST_PTR *pDacl, + LPBOOL lpbDaclDefaulted) { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl, lpbDaclDefaulted); @@ -246,7 +249,7 @@ BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, *lpbDaclPresent = hasDacl; if (!hasDacl) { if (pDacl) { - *pDacl = nullptr; + *pDacl = GUEST_NULL; } if (lpbDaclDefaulted) { *lpbDaclDefaulted = FALSE; @@ -315,7 +318,7 @@ BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken) { } BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes, - DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) { + DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) { HOST_CONTEXT_GUARD(); DEBUG_LOG("DuplicateTokenEx(%p, 0x%x, %p, %u, %u, %p)\n", hExistingToken, dwDesiredAccess, lpTokenAttributes, ImpersonationLevel, TokenType, phNewToken); @@ -399,7 +402,7 @@ BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2) { } BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR SecurityDescriptor) { + PSECURITY_DESCRIPTOR SecurityDescriptor) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor); (void)SecurityInformation; @@ -425,15 +428,15 @@ BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescripto pSecurityDescriptor->Revision = static_cast(dwRevision); pSecurityDescriptor->Sbz1 = 0; pSecurityDescriptor->Control = 0; - pSecurityDescriptor->Owner = nullptr; - pSecurityDescriptor->Group = nullptr; - pSecurityDescriptor->Sacl = nullptr; - pSecurityDescriptor->Dacl = nullptr; + pSecurityDescriptor->Owner = GUEST_NULL; + pSecurityDescriptor->Group = GUEST_NULL; + pSecurityDescriptor->Sacl = GUEST_NULL; + pSecurityDescriptor->Dacl = GUEST_NULL; return TRUE; } BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, - BOOL bDaclDefaulted) { + BOOL bDaclDefaulted) { HOST_CONTEXT_GUARD(); DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted); if (!pSecurityDescriptor || pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) { @@ -446,16 +449,16 @@ BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, if (bDaclDefaulted) { control = static_cast(control | SE_DACL_DEFAULTED); } - pSecurityDescriptor->Dacl = pDacl; + pSecurityDescriptor->Dacl = toGuestPtr(pDacl); } else { - pSecurityDescriptor->Dacl = nullptr; + pSecurityDescriptor->Dacl = GUEST_NULL; } pSecurityDescriptor->Control = control; return TRUE; } BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, - LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) { + LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength, ReturnLength); @@ -535,7 +538,7 @@ BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS Toke } BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, - DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) { + DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) { HOST_CONTEXT_GUARD(); DEBUG_LOG("AdjustTokenPrivileges(%p, %u, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, NewState, BufferLength, PreviousState, ReturnLength); @@ -549,7 +552,7 @@ BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, } BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, - LPVOID TokenInformation, DWORD TokenInformationLength) { + LPVOID TokenInformation, DWORD TokenInformationLength) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength); diff --git a/dll/advapi32/securitybaseapi.h b/dll/advapi32/securitybaseapi.h index 3cf9b8c..472aeb8 100644 --- a/dll/advapi32/securitybaseapi.h +++ b/dll/advapi32/securitybaseapi.h @@ -30,10 +30,10 @@ struct SECURITY_DESCRIPTOR { BYTE Revision; BYTE Sbz1; WORD Control; - void *Owner; - void *Group; - ACL *Sacl; - ACL *Dacl; + GUEST_PTR Owner; + GUEST_PTR Group; + GUEST_PTR Sacl; + GUEST_PTR Dacl; }; using PSECURITY_DESCRIPTOR = SECURITY_DESCRIPTOR *; @@ -85,28 +85,28 @@ namespace advapi32 { BOOL WINAPI InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision); BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid); -BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce); +BOOL WINAPI FindFirstFreeAce(PACL pAcl, GUEST_PTR *pAce); PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid); PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid); PDWORD WINAPI GetSidSubAuthority(PSID pSid, DWORD nSubAuthority); BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken); BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes, - DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken); + DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken); BOOL WINAPI CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid); BOOL WINAPI InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount); BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2); -BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, - LPBOOL lpbDaclDefaulted); +BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, GUEST_PTR *pDacl, + LPBOOL lpbDaclDefaulted); BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, - PSECURITY_DESCRIPTOR SecurityDescriptor); + PSECURITY_DESCRIPTOR SecurityDescriptor); BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision); BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, - BOOL bDaclDefaulted); + BOOL bDaclDefaulted); BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, - LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength); + LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength); BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, - DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength); + DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength); BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, - LPVOID TokenInformation, DWORD TokenInformationLength); + LPVOID TokenInformation, DWORD TokenInformationLength); } // namespace advapi32 diff --git a/dll/advapi32/winbase.cpp b/dll/advapi32/winbase.cpp index 8b75562..31d3d81 100644 --- a/dll/advapi32/winbase.cpp +++ b/dll/advapi32/winbase.cpp @@ -15,6 +15,7 @@ namespace { constexpr WCHAR kAccountSystem[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'}; constexpr WCHAR kDomainNtAuthority[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'}; +constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5}; std::mutex g_privilegeMapMutex; std::unordered_map g_privilegeLuidCache; diff --git a/dll/advapi32/winbase.h b/dll/advapi32/winbase.h index 4df329b..c4a6a00 100644 --- a/dll/advapi32/winbase.h +++ b/dll/advapi32/winbase.h @@ -17,8 +17,8 @@ enum SID_NAME_USE : DWORD { namespace advapi32 { -BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, - LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse); +BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName, + LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse); BOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid); BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid); BOOL WINAPI GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer); diff --git a/dll/advapi32/wincrypt.h b/dll/advapi32/wincrypt.h index d7ba5bf..476dcb7 100644 --- a/dll/advapi32/wincrypt.h +++ b/dll/advapi32/wincrypt.h @@ -18,7 +18,7 @@ namespace advapi32 { BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags); BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType, - DWORD dwFlags); + DWORD dwFlags); BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash); BOOL WINAPI CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags); diff --git a/dll/advapi32/winreg.cpp b/dll/advapi32/winreg.cpp index 4a309fa..42d7778 100644 --- a/dll/advapi32/winreg.cpp +++ b/dll/advapi32/winreg.cpp @@ -29,17 +29,17 @@ struct RegistryKeyObject : ObjectBase { }; struct PredefinedKeyInfo { - uintptr_t value; + HKEY value; const char16_t *name; }; constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = { - {static_cast(0x80000000u), u"HKEY_CLASSES_ROOT"}, - {static_cast(0x80000001u), u"HKEY_CURRENT_USER"}, - {static_cast(0x80000002u), u"HKEY_LOCAL_MACHINE"}, - {static_cast(0x80000003u), u"HKEY_USERS"}, - {static_cast(0x80000004u), u"HKEY_PERFORMANCE_DATA"}, - {static_cast(0x80000005u), u"HKEY_CURRENT_CONFIG"}, + {static_cast(0x80000000u), u"HKEY_CLASSES_ROOT"}, + {static_cast(0x80000001u), u"HKEY_CURRENT_USER"}, + {static_cast(0x80000002u), u"HKEY_LOCAL_MACHINE"}, + {static_cast(0x80000003u), u"HKEY_USERS"}, + {static_cast(0x80000004u), u"HKEY_PERFORMANCE_DATA"}, + {static_cast(0x80000005u), u"HKEY_CURRENT_CONFIG"}, }; constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos); @@ -82,7 +82,7 @@ std::u16string canonicalizeKeySegment(LPCWSTR input) { return canonicalizeKeySegment(wide); } -Pin predefinedHandleForValue(uintptr_t value) { +Pin predefinedHandleForValue(HKEY value) { static std::array, kPredefinedKeyCount> g_predefinedHandles = [] { std::array, kPredefinedKeyCount> arr; for (size_t i = 0; i < kPredefinedKeyCount; ++i) { @@ -101,11 +101,10 @@ Pin predefinedHandleForValue(uintptr_t value) { } Pin handleDataFromHKeyLocked(HKEY hKey) { - uintptr_t raw = reinterpret_cast(hKey); - if (raw == 0) { + if (hKey == NO_HANDLE) { return {}; } - if (auto predefined = predefinedHandleForValue(raw)) { + if (auto predefined = predefinedHandleForValue(hKey)) { return predefined; } auto obj = wibo::handles().getAs(hKey); @@ -116,9 +115,8 @@ Pin handleDataFromHKeyLocked(HKEY hKey) { } bool isPredefinedKeyHandle(HKEY hKey) { - uintptr_t raw = reinterpret_cast(hKey); return std::any_of(std::begin(kPredefinedKeyInfos), std::end(kPredefinedKeyInfos), - [raw](const PredefinedKeyInfo &info) { return info.value == raw; }); + [hKey](const PredefinedKeyInfo &info) { return info.value == hKey; }); } } // namespace @@ -139,7 +137,7 @@ LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWS kernel32::setLastError(ERROR_INVALID_PARAMETER); return ERROR_INVALID_PARAMETER; } - *phkResult = nullptr; + *phkResult = NO_HANDLE; if (Reserved != 0) { kernel32::setLastError(ERROR_INVALID_PARAMETER); return ERROR_INVALID_PARAMETER; @@ -220,7 +218,7 @@ LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSA kernel32::setLastError(ERROR_INVALID_PARAMETER); return ERROR_INVALID_PARAMETER; } - *phkResult = nullptr; + *phkResult = NO_HANDLE; if ((ulOptions & ~REG_OPTION_OPEN_LINK) != 0) { kernel32::setLastError(ERROR_INVALID_PARAMETER); return ERROR_INVALID_PARAMETER; diff --git a/dll/advapi32/winreg.h b/dll/advapi32/winreg.h index 574fc7d..1c4c42c 100644 --- a/dll/advapi32/winreg.h +++ b/dll/advapi32/winreg.h @@ -34,21 +34,19 @@ constexpr REGSAM KEY_WOW64_32KEY = 0x00000200; namespace advapi32 { LSTATUS WINAPI RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, - REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, - LPDWORD lpdwDisposition); + REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, - REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, - LPDWORD lpdwDisposition); + REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); LSTATUS WINAPI RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); LSTATUS WINAPI RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData, - LPDWORD lpcbData); + LPDWORD lpcbData); LSTATUS WINAPI RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData, - LPDWORD lpcbData); + LPDWORD lpcbData); LSTATUS WINAPI RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved, - LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime); + LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime); LSTATUS WINAPI RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved, - LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime); + LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime); LSTATUS WINAPI RegCloseKey(HKEY hKey); } // namespace advapi32 diff --git a/dll/crt.cpp b/dll/crt.cpp index eccd6bf..0172c6f 100644 --- a/dll/crt.cpp +++ b/dll/crt.cpp @@ -6,6 +6,7 @@ #include "heap.h" #include "kernel32/internal.h" #include "modules.h" +#include "types.h" #include #include @@ -42,24 +43,29 @@ int _fmode = 0; std::vector<_PVFV> atexitFuncs; _invalid_parameter_handler invalidParameterHandler = nullptr; -void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end) { +GUEST_PTR guestArgv = GUEST_NULL; +GUEST_PTR guestEnviron = GUEST_NULL; + +void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end); do { - if (_PVFV pfn = *++ppfn) { + if (GUEST_PTR pfn = *++ppfn) { DEBUG_LOG("-> calling %p\n", pfn); - call__PVFV(pfn); + auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn)); + call__PVFV(fn); } } while (ppfn < end); } -int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) { +int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end); do { - if (_PIFV pfn = *++ppfn) { + if (GUEST_PTR pfn = *++ppfn) { DEBUG_LOG("-> calling %p\n", pfn); - int err = call__PIFV(pfn); + auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn)); + int err = call__PIFV(fn); if (err) return err; } @@ -80,16 +86,16 @@ int CDECL _set_fmode(int mode) { return 0; } -int *CDECL __p__commode() { +GUEST_PTR CDECL __p__commode() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__commode()\n"); - return &_commode; + return toGuestPtr(&_commode); } -int *CDECL __p__fmode() { +GUEST_PTR CDECL __p__fmode() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__fmode()\n"); - return &_fmode; + return toGuestPtr(&_fmode); } int CDECL _crt_atexit(void (*func)()) { @@ -137,28 +143,79 @@ int CDECL _set_new_mode(int newhandlermode) { return 0; } -char **CDECL _get_initial_narrow_environment() { +GUEST_PTR CDECL _get_initial_narrow_environment() { HOST_CONTEXT_GUARD(); DEBUG_LOG("_get_initial_narrow_environment()\n"); - return environ; + if (guestEnviron == GUEST_NULL) { + int count = 0; + while (environ[count]) { + count++; + } + GUEST_PTR *buf = reinterpret_cast(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR))); + if (!buf) { + return GUEST_NULL; + } + for (int i = 0; i < count; i++) { + size_t len = ::strlen(environ[i]); + char *str = reinterpret_cast(wibo::heap::guestMalloc(len + 1)); + ::memcpy(str, environ[i], len + 1); + buf[i] = toGuestPtr(str); + } + guestEnviron = toGuestPtr(buf); + } + return guestEnviron; } -char ***CDECL __p__environ() { +GUEST_PTR CDECL __p__environ() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__environ()\n"); - return &environ; + if (guestEnviron == GUEST_NULL) { + int count = 0; + while (environ[count]) { + count++; + } + GUEST_PTR *buf = reinterpret_cast(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR))); + if (!buf) { + return GUEST_NULL; + } + for (int i = 0; i < count; i++) { + size_t len = ::strlen(environ[i]); + char *str = reinterpret_cast(wibo::heap::guestMalloc(len + 1)); + ::memcpy(str, environ[i], len + 1); + buf[i] = toGuestPtr(str); + } + guestEnviron = toGuestPtr(buf); + } + return toGuestPtr(&environ); } -char ***CDECL __p___argv() { +GUEST_PTR CDECL __p___argv() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p___argv()\n"); - return &wibo::argv; + if (guestArgv == GUEST_NULL) { + int count = 0; + while (wibo::argv[count]) { + count++; + } + GUEST_PTR *buf = reinterpret_cast(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR))); + if (!buf) { + return GUEST_NULL; + } + for (int i = 0; i < count; i++) { + size_t len = ::strlen(wibo::argv[i]); + char *str = reinterpret_cast(wibo::heap::guestMalloc(len + 1)); + ::memcpy(str, wibo::argv[i], len + 1); + buf[i] = toGuestPtr(str); + } + guestArgv = toGuestPtr(buf); + } + return toGuestPtr(&guestArgv); } -int *CDECL __p___argc() { +GUEST_PTR CDECL __p___argc() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p___argc()\n"); - return &wibo::argc; + return toGuestPtr(&wibo::argc); } SIZE_T CDECL strlen(const char *str) { @@ -258,9 +315,9 @@ int CDECL _initialize_onexit_table(_onexit_table_t *table) { return -1; if (table->first != table->last) return 0; - table->first = nullptr; - table->last = nullptr; - table->end = nullptr; + table->first = GUEST_NULL; + table->last = GUEST_NULL; + table->end = GUEST_NULL; return 0; } @@ -269,20 +326,23 @@ int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func) { DEBUG_LOG("_register_onexit_function(%p, %p)\n", table, func); if (!table || !func) return -1; - if (table->last == table->end) { - size_t count = table->end - table->first; + GUEST_PTR *first = reinterpret_cast(fromGuestPtr(table->first)); + GUEST_PTR *last = reinterpret_cast(fromGuestPtr(table->last)); + GUEST_PTR *end = reinterpret_cast(fromGuestPtr(table->end)); + if (last == end) { + size_t count = end - first; size_t newCount = count + 1; if (newCount <= 0) return -1; - _onexit_t *newTable = - static_cast<_onexit_t *>(wibo::heap::guestRealloc(table->first, newCount * sizeof(_onexit_t))); + GUEST_PTR *newTable = static_cast(wibo::heap::guestRealloc(first, newCount * sizeof(GUEST_PTR))); if (!newTable) return -1; - table->first = newTable; - table->last = newTable + count; - table->end = newTable + newCount; + table->first = toGuestPtr(newTable); + last = newTable + count; + table->end = toGuestPtr(newTable + newCount); } - *table->last++ = func; + *last = toGuestPtr(reinterpret_cast(func)); + table->last = toGuestPtr(last + 1); return 0; } @@ -291,9 +351,12 @@ int CDECL _execute_onexit_table(_onexit_table_t *table) { DEBUG_LOG("_execute_onexit_table(%p)\n", table); if (!table) return -1; - for (auto it = table->first; it != table->last; ++it) { - DEBUG_LOG("Calling onexit_table function %p\n", *it); - call__onexit_t(*it); + GUEST_PTR *first = reinterpret_cast(fromGuestPtr(table->first)); + GUEST_PTR *last = reinterpret_cast(fromGuestPtr(table->last)); + for (auto it = first; it != last; ++it) { + _onexit_t fn = reinterpret_cast<_onexit_t>(fromGuestPtr(*it)); + DEBUG_LOG("Calling onexit_table function %p\n", fn); + call__onexit_t(fn); } return 0; } @@ -345,7 +408,7 @@ void *CDECL __acrt_iob_func(unsigned int index) { return nullptr; } -int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale, +int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale, va_list args) { HOST_CONTEXT_GUARD(); DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args); @@ -355,8 +418,8 @@ int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *str return vfprintf(hostFile, format, args); } -int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format, - void *locale, va_list args) { +int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format, void *locale, + va_list args) { HOST_CONTEXT_GUARD(); DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale); if (!buffer || !format) diff --git a/dll/crt.h b/dll/crt.h index af9ae96..816b606 100644 --- a/dll/crt.h +++ b/dll/crt.h @@ -23,9 +23,9 @@ typedef int(_CC_CDECL *sort_compare)(const void *, const void *); typedef int(_CC_CDECL *_onexit_t)(); struct _onexit_table_t { - _onexit_t *first; - _onexit_t *last; - _onexit_t *end; + GUEST_PTR first; + GUEST_PTR last; + GUEST_PTR end; }; namespace crt { @@ -33,23 +33,23 @@ namespace crt { extern int _commode; extern int _fmode; -void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end); -int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end); +void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end); +int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end); void CDECL _set_app_type(_crt_app_type type); int CDECL _set_fmode(int mode); -int *CDECL __p__commode(); -int *CDECL __p__fmode(); -int CDECL _crt_atexit(void (*func)()); +GUEST_PTR CDECL __p__commode(); +GUEST_PTR CDECL __p__fmode(); +int CDECL _crt_atexit(_PVFV func); int CDECL _configure_narrow_argv(_crt_argv_mode mode); _invalid_parameter_handler CDECL _set_invalid_parameter_handler(_invalid_parameter_handler newHandler); int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask); int CDECL _configthreadlocale(int per_thread_locale_type); int CDECL _initialize_narrow_environment(); int CDECL _set_new_mode(int newhandlermode); -char **CDECL _get_initial_narrow_environment(); -char ***CDECL __p__environ(); -char ***CDECL __p___argv(); -int *CDECL __p___argc(); +GUEST_PTR CDECL _get_initial_narrow_environment(); +GUEST_PTR CDECL __p__environ(); +GUEST_PTR CDECL __p___argv(); +GUEST_PTR CDECL __p___argc(); SIZE_T CDECL strlen(const char *str); int CDECL strcmp(const char *lhs, const char *rhs); int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count); @@ -74,10 +74,12 @@ void CDECL _exit(int status); void CDECL abort(); signal_handler CDECL signal(int signum, signal_handler handler); void *CDECL __acrt_iob_func(unsigned int index); -int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale, +#ifndef __x86_64__ // TODO +int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale, va_list args); -int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format, +int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format, void *locale, va_list args); +#endif void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare); int CDECL puts(const char *str); diff --git a/dll/kernel32/errhandlingapi.h b/dll/kernel32/errhandlingapi.h index 0860b44..1578951 100644 --- a/dll/kernel32/errhandlingapi.h +++ b/dll/kernel32/errhandlingapi.h @@ -7,14 +7,14 @@ constexpr DWORD EXCEPTION_MAXIMUM_PARAMETERS = 15; struct EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; - EXCEPTION_RECORD *ExceptionRecord; - PVOID ExceptionAddress; + GUEST_PTR ExceptionRecord; + GUEST_PTR ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; }; -using PEXCEPTION_RECORD = EXCEPTION_RECORD *; -using PCONTEXT = void *; +using PEXCEPTION_RECORD = GUEST_PTR; +using PCONTEXT = GUEST_PTR; struct EXCEPTION_POINTERS { PEXCEPTION_RECORD ExceptionRecord; diff --git a/dll/kernel32/fileapi.cpp b/dll/kernel32/fileapi.cpp index 9b971fb..cda4d3b 100644 --- a/dll/kernel32/fileapi.cpp +++ b/dll/kernel32/fileapi.cpp @@ -12,6 +12,7 @@ #include "overlapped_util.h" #include "strutil.h" #include "timeutil.h" +#include "types.h" #include #include @@ -146,24 +147,24 @@ struct FindSearchHandle { }; std::mutex g_findHandleMutex; -std::unordered_map> g_findHandles; +HANDLE g_nextFindHandle = 1; +std::unordered_map> g_findHandles; HANDLE registerFindHandle(std::unique_ptr handle) { if (!handle) { return INVALID_HANDLE_VALUE; } - FindSearchHandle *raw = handle.get(); std::lock_guard lk(g_findHandleMutex); + HANDLE raw = g_nextFindHandle++; g_findHandles.emplace(raw, std::move(handle)); - return reinterpret_cast(raw); + return raw; } FindSearchHandle *lookupFindHandleLocked(HANDLE handle) { - if (handle == nullptr) { + if (handle == NO_HANDLE) { return nullptr; } - auto *raw = reinterpret_cast(handle); - auto it = g_findHandles.find(raw); + auto it = g_findHandles.find(handle); if (it == g_findHandles.end()) { return nullptr; } @@ -172,8 +173,7 @@ FindSearchHandle *lookupFindHandleLocked(HANDLE handle) { std::unique_ptr detachFindHandle(HANDLE handle) { std::lock_guard lk(g_findHandleMutex); - auto *raw = reinterpret_cast(handle); - auto it = g_findHandles.find(raw); + auto it = g_findHandles.find(handle); if (it == g_findHandles.end()) { return nullptr; } @@ -1185,7 +1185,7 @@ DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistance HOST_CONTEXT_GUARD(); DEBUG_LOG("SetFilePointer(%p, %ld, %p, %u)\n", hFile, static_cast(lDistanceToMove), lpDistanceToMoveHigh, dwMoveMethod); - if (hFile == nullptr) { + if (hFile == NO_HANDLE) { setLastError(ERROR_INVALID_HANDLE); return INVALID_SET_FILE_POINTER; } @@ -1224,7 +1224,8 @@ DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistance BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) { HOST_CONTEXT_GUARD(); - if (hFile == nullptr) { + DEBUG_LOG("SetFilePointerEx(%p, %lld, %p, %u)\n", hFile, liDistanceToMove.QuadPart, lpNewFilePointer, dwMoveMethod); + if (hFile == NO_HANDLE) { setLastError(ERROR_INVALID_HANDLE); return FALSE; } @@ -1537,12 +1538,12 @@ DWORD WINAPI GetFileType(HANDLE hFile) { return type; } -DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart) { +DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, GUEST_PTR *lpFilePart) { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetFullPathNameA(%s, %u)\n", lpFileName ? lpFileName : "(null)", nBufferLength); if (lpFilePart) { - *lpFilePart = nullptr; + *lpFilePart = GUEST_NULL; } if (!lpFileName) { @@ -1580,21 +1581,21 @@ DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBu if (lpFilePart) { if (info.filePartOffset != std::string::npos && info.filePartOffset < pathLen) { - *lpFilePart = lpBuffer + info.filePartOffset; + *lpFilePart = toGuestPtr(lpBuffer + info.filePartOffset); } else { - *lpFilePart = nullptr; + *lpFilePart = GUEST_NULL; } } return static_cast(pathLen); } -DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart) { +DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, GUEST_PTR *lpFilePart) { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetFullPathNameW(%p, %u)\n", lpFileName, nBufferLength); if (lpFilePart) { - *lpFilePart = nullptr; + *lpFilePart = GUEST_NULL; } if (!lpFileName) { @@ -1633,9 +1634,9 @@ DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lp if (lpFilePart) { if (info.filePartOffset != std::string::npos && info.filePartOffset < info.path.size()) { - *lpFilePart = lpBuffer + info.filePartOffset; + *lpFilePart = toGuestPtr(lpBuffer + info.filePartOffset); } else { - *lpFilePart = nullptr; + *lpFilePart = GUEST_NULL; } } @@ -1883,7 +1884,7 @@ BOOL WINAPI FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) { BOOL WINAPI FindClose(HANDLE hFindFile) { HOST_CONTEXT_GUARD(); DEBUG_LOG("FindClose(%p)\n", hFindFile); - if (hFindFile == nullptr) { + if (hFindFile == NO_HANDLE) { DEBUG_LOG(" -> ERROR_INVALID_HANDLE\n"); setLastError(ERROR_INVALID_HANDLE); return FALSE; diff --git a/dll/kernel32/fileapi.h b/dll/kernel32/fileapi.h index 3cda7de..a21afc1 100644 --- a/dll/kernel32/fileapi.h +++ b/dll/kernel32/fileapi.h @@ -56,8 +56,8 @@ constexpr DWORD INVALID_FILE_SIZE = 0xFFFFFFFF; namespace kernel32 { -DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart); -DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart); +DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, GUEST_PTR *lpFilePart); +DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, GUEST_PTR *lpFilePart); DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer); DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer); UINT WINAPI GetTempFileNameA(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName); diff --git a/dll/kernel32/handleapi.cpp b/dll/kernel32/handleapi.cpp index b6e3bae..7ab07d2 100644 --- a/dll/kernel32/handleapi.cpp +++ b/dll/kernel32/handleapi.cpp @@ -11,7 +11,7 @@ namespace kernel32 { BOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, - LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) { + LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) { HOST_CONTEXT_GUARD(); DEBUG_LOG("DuplicateHandle(%p, %p, %p, %p, %x, %d, %x)\n", hSourceProcessHandle, hSourceHandle, hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions); diff --git a/dll/kernel32/heapapi.cpp b/dll/kernel32/heapapi.cpp index ac36aba..59006e1 100644 --- a/dll/kernel32/heapapi.cpp +++ b/dll/kernel32/heapapi.cpp @@ -18,7 +18,7 @@ using kernel32::HeapObject; namespace { std::once_flag g_processHeapInitFlag; -HANDLE g_processHeapHandle = nullptr; +HANDLE g_processHeapHandle = NO_HANDLE; HeapObject *g_processHeapRecord = nullptr; void ensureProcessHeapInitialized() { @@ -71,7 +71,7 @@ HeapObject::~HeapObject() { heap = nullptr; } if (isProcessHeap) { - g_processHeapHandle = nullptr; + g_processHeapHandle = NO_HANDLE; g_processHeapRecord = nullptr; } } @@ -83,13 +83,13 @@ HANDLE WINAPI HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximum DEBUG_LOG("HeapCreate(%u, %zu, %zu)\n", flOptions, dwInitialSize, dwMaximumSize); if (dwMaximumSize != 0 && dwInitialSize > dwMaximumSize) { setLastError(ERROR_INVALID_PARAMETER); - return nullptr; + return NO_HANDLE; } mi_heap_t *heap = wibo::heap::createGuestHeap(); if (!heap) { setLastError(ERROR_NOT_ENOUGH_MEMORY); - return nullptr; + return NO_HANDLE; } auto record = make_pin(heap); diff --git a/dll/kernel32/interlockedapi.h b/dll/kernel32/interlockedapi.h index 44c222b..fab6962 100644 --- a/dll/kernel32/interlockedapi.h +++ b/dll/kernel32/interlockedapi.h @@ -5,13 +5,13 @@ namespace kernel32 { struct SLIST_ENTRY { - SLIST_ENTRY *Next; + GUEST_PTR Next; }; using PSLIST_ENTRY = SLIST_ENTRY *; struct SLIST_HEADER { - SLIST_ENTRY *Head; + GUEST_PTR Head; unsigned short Depth; unsigned short Sequence; }; diff --git a/dll/kernel32/internal.h b/dll/kernel32/internal.h index 66fd410..6b7d5b9 100644 --- a/dll/kernel32/internal.h +++ b/dll/kernel32/internal.h @@ -160,17 +160,15 @@ struct HeapObject : public ObjectBase { [[nodiscard]] inline bool canAccess() const { return isProcessHeap || (isOwner() && heap != nullptr); } }; -inline constexpr uintptr_t kPseudoCurrentProcessHandleValue = static_cast(-1); -inline constexpr uintptr_t kPseudoCurrentThreadHandleValue = static_cast(-2); +inline constexpr HANDLE kPseudoCurrentProcessHandleValue = static_cast(-1); +inline constexpr HANDLE kPseudoCurrentThreadHandleValue = static_cast(-2); inline bool isPseudoCurrentProcessHandle(HANDLE h) { - uintptr_t rawHandle = reinterpret_cast(h); - return rawHandle == kPseudoCurrentProcessHandleValue; + return h == kPseudoCurrentProcessHandleValue; } inline bool isPseudoCurrentThreadHandle(HANDLE h) { - uintptr_t rawHandle = reinterpret_cast(h); - return rawHandle == kPseudoCurrentThreadHandleValue; + return h == kPseudoCurrentThreadHandleValue; } void tryMarkExecutable(void *mem); diff --git a/dll/kernel32/libloaderapi.cpp b/dll/kernel32/libloaderapi.cpp index 4ec82e3..91bf07b 100644 --- a/dll/kernel32/libloaderapi.cpp +++ b/dll/kernel32/libloaderapi.cpp @@ -6,6 +6,7 @@ #include "modules.h" #include "resources.h" #include "strutil.h" +#include "types.h" #include #include @@ -20,13 +21,13 @@ HRSRC findResourceInternal(HMODULE hModule, const wibo::ResourceIdentifier &type auto *exe = wibo::executableFromModule(hModule); if (!exe) { kernel32::setLastError(ERROR_RESOURCE_DATA_NOT_FOUND); - return nullptr; + return NO_HANDLE; } wibo::ResourceLocation loc; if (!exe->findResource(type, name, language, loc)) { - return nullptr; + return NO_HANDLE; } - return reinterpret_cast(const_cast(loc.dataEntry)); + return toGuestPtr(loc.dataEntry); } } // namespace @@ -58,7 +59,7 @@ HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName) { const auto *module = wibo::findLoadedModule(lpModuleName); if (!module) { setLastError(ERROR_MOD_NOT_FOUND); - return nullptr; + return NO_HANDLE; } return module->handle; } @@ -111,7 +112,7 @@ DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize) DWORD WINAPI GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("GetModuleFileNameW(%p, %s, %u)\n", hModule, wideStringToString(lpFilename).c_str(), nSize); + DEBUG_LOG("GetModuleFileNameW(%p, %p, %u)\n", hModule, lpFilename, nSize); if (!lpFilename) { setLastError(ERROR_INVALID_PARAMETER); return 0; @@ -187,25 +188,25 @@ HGLOBAL WINAPI LoadResource(HMODULE hModule, HRSRC hResInfo) { DEBUG_LOG("LoadResource %p %p\n", hModule, hResInfo); if (!hResInfo) { setLastError(ERROR_RESOURCE_DATA_NOT_FOUND); - return nullptr; + return GUEST_NULL; } auto *exe = wibo::executableFromModule(hModule); if (!exe || !exe->rsrcBase) { setLastError(ERROR_RESOURCE_DATA_NOT_FOUND); - return nullptr; + return GUEST_NULL; } const auto *entry = reinterpret_cast(hResInfo); if (!wibo::resourceEntryBelongsToExecutable(*exe, entry)) { setLastError(ERROR_INVALID_PARAMETER); - return nullptr; + return GUEST_NULL; } - return const_cast(exe->fromRVA(entry->offsetToData)); + return toGuestPtr(exe->fromRVA(entry->offsetToData)); } LPVOID WINAPI LockResource(HGLOBAL hResData) { HOST_CONTEXT_GUARD(); DEBUG_LOG("LockResource(%p)\n", hResData); - return hResData; + return (LPVOID)hResData; } DWORD WINAPI SizeofResource(HMODULE hModule, HRSRC hResInfo) { @@ -234,7 +235,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName) { const auto *info = wibo::loadModule(lpLibFileName); if (!info) { // lastError is set by loadModule - return nullptr; + return NO_HANDLE; } return info->handle; } @@ -242,7 +243,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName) { HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName) { HOST_CONTEXT_GUARD(); if (!lpLibFileName) { - return nullptr; + return NO_HANDLE; } auto filename = wideStringToString(lpLibFileName); DEBUG_LOG("LoadLibraryW(%s)\n", filename.c_str()); diff --git a/dll/kernel32/memoryapi.cpp b/dll/kernel32/memoryapi.cpp index b1d41bf..48a7907 100644 --- a/dll/kernel32/memoryapi.cpp +++ b/dll/kernel32/memoryapi.cpp @@ -7,6 +7,7 @@ #include "heap.h" #include "internal.h" #include "strutil.h" +#include "types.h" #include #include @@ -161,8 +162,8 @@ bool mappedViewRegionForAddress(uintptr_t request, uintptr_t pageBase, MEMORY_BA } uintptr_t blockStart = viewStart; uintptr_t blockEnd = alignUp(viewEnd, pageSize); - info.BaseAddress = reinterpret_cast(blockStart); - info.AllocationBase = reinterpret_cast(view.viewBase); + info.BaseAddress = toGuestPtr(reinterpret_cast(blockStart)); + info.AllocationBase = toGuestPtr(reinterpret_cast(view.viewBase)); info.AllocationProtect = view.allocationProtect; info.RegionSize = blockEnd > blockStart ? blockEnd - blockStart : 0; info.State = MEM_COMMIT; @@ -189,7 +190,7 @@ HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappi if (flProtect != PAGE_READONLY && flProtect != PAGE_READWRITE && flProtect != PAGE_WRITECOPY) { DEBUG_LOG("CreateFileMappingA: unsupported protection 0x%x\n", flProtect); setLastError(ERROR_INVALID_PARAMETER); - return nullptr; + return NO_HANDLE; } auto mapping = make_pin(); @@ -200,25 +201,25 @@ HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappi mapping->fd = -1; if (size == 0) { setLastError(ERROR_INVALID_PARAMETER); - return nullptr; + return NO_HANDLE; } mapping->maxSize = size; } else { auto file = wibo::handles().getAs(hFile); if (!file || !file->valid()) { setLastError(ERROR_INVALID_HANDLE); - return nullptr; + return NO_HANDLE; } int dupFd = fcntl(file->fd, F_DUPFD_CLOEXEC, 0); if (dupFd == -1) { setLastErrorFromErrno(); - return nullptr; + return NO_HANDLE; } mapping->fd = dupFd; if (size == 0) { off_t fileSize = lseek(dupFd, 0, SEEK_END); if (fileSize < 0) { - return nullptr; + return NO_HANDLE; } size = static_cast(fileSize); } diff --git a/dll/kernel32/minwinbase.h b/dll/kernel32/minwinbase.h index 5aaa20e..439eb4f 100644 --- a/dll/kernel32/minwinbase.h +++ b/dll/kernel32/minwinbase.h @@ -4,7 +4,7 @@ struct SECURITY_ATTRIBUTES { DWORD nLength; - LPVOID lpSecurityDescriptor; + GUEST_PTR lpSecurityDescriptor; BOOL bInheritHandle; }; @@ -86,7 +86,7 @@ typedef struct _OVERLAPPED { DWORD Offset; DWORD OffsetHigh; }; - PVOID Pointer; + GUEST_PTR Pointer; }; HANDLE hEvent; } OVERLAPPED, *LPOVERLAPPED; diff --git a/dll/kernel32/namedpipeapi.cpp b/dll/kernel32/namedpipeapi.cpp index f1b29cd..c08e5eb 100644 --- a/dll/kernel32/namedpipeapi.cpp +++ b/dll/kernel32/namedpipeapi.cpp @@ -355,8 +355,8 @@ BOOL WINAPI CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBU setLastError(ERROR_INVALID_PARAMETER); return FALSE; } - *hReadPipe = nullptr; - *hWritePipe = nullptr; + *hReadPipe = NO_HANDLE; + *hWritePipe = NO_HANDLE; int pipeFds[2]; if (pipe(pipeFds) != 0) { diff --git a/dll/kernel32/overlapped_util.h b/dll/kernel32/overlapped_util.h index 1c353e2..1f60128 100644 --- a/dll/kernel32/overlapped_util.h +++ b/dll/kernel32/overlapped_util.h @@ -1,17 +1,14 @@ #pragma once -#include "errors.h" #include "handles.h" #include "internal.h" #include "minwinbase.h" -#include - namespace kernel32::detail { inline HANDLE normalizedOverlappedEventHandle(const OVERLAPPED *ov) { - if (!ov || (reinterpret_cast(ov->hEvent) & 1U) != 0) { - return nullptr; + if (!ov || (ov->hEvent & 1U) != 0) { + return NO_HANDLE; } return ov->hEvent; } diff --git a/dll/kernel32/processenv.cpp b/dll/kernel32/processenv.cpp index 4c74fe8..1c9d5d9 100644 --- a/dll/kernel32/processenv.cpp +++ b/dll/kernel32/processenv.cpp @@ -6,6 +6,7 @@ #include "heap.h" #include "internal.h" #include "strutil.h" +#include "types.h" #include #include @@ -16,6 +17,9 @@ namespace { +GUEST_PTR g_commandLineA = GUEST_NULL; +GUEST_PTR g_commandLineW = GUEST_NULL; + std::string convertEnvValueForWindows(const std::string &name, const char *rawValue) { if (!rawValue) { return {}; @@ -42,16 +46,26 @@ std::string convertEnvValueToHost(const std::string &name, const char *rawValue) namespace kernel32 { -LPSTR WINAPI GetCommandLineA() { +GUEST_PTR WINAPI GetCommandLineA() { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetCommandLineA() -> %s\n", wibo::commandLine.c_str()); - return const_cast(wibo::commandLine.c_str()); + if (g_commandLineA == GUEST_NULL) { + void *tmp = wibo::heap::guestCalloc(1, wibo::commandLine.size() + 1); + memcpy(tmp, wibo::commandLine.c_str(), wibo::commandLine.size()); + g_commandLineA = toGuestPtr(tmp); + } + return g_commandLineA; } -LPWSTR WINAPI GetCommandLineW() { +GUEST_PTR WINAPI GetCommandLineW() { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetCommandLineW() -> %s\n", wideStringToString(wibo::commandLineW.data()).c_str()); - return wibo::commandLineW.data(); + if (g_commandLineW == GUEST_NULL) { + void *tmp = wibo::heap::guestCalloc(1, wibo::commandLineW.size() * sizeof(WCHAR) + sizeof(WCHAR)); + memcpy(tmp, wibo::commandLineW.data(), wibo::commandLineW.size() * sizeof(WCHAR)); + g_commandLineW = toGuestPtr(tmp); + } + return g_commandLineW; } HANDLE WINAPI GetStdHandle(DWORD nStdHandle) { @@ -66,7 +80,11 @@ BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle) { return files::setStdHandle(nStdHandle, hHandle); } -LPCH WINAPI GetEnvironmentStrings() { +GUEST_PTR WINAPI GetEnvironmentStrings() { + return GetEnvironmentStringsA(); +} + +GUEST_PTR WINAPI GetEnvironmentStringsA() { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetEnvironmentStrings()\n"); @@ -82,7 +100,7 @@ LPCH WINAPI GetEnvironmentStrings() { char *buffer = static_cast(wibo::heap::guestMalloc(bufSize)); if (!buffer) { setLastError(ERROR_NOT_ENOUGH_MEMORY); - return nullptr; + return GUEST_NULL; } char *ptr = buffer; work = environ; @@ -96,10 +114,10 @@ LPCH WINAPI GetEnvironmentStrings() { } *ptr = 0; - return buffer; + return toGuestPtr(buffer); } -LPWCH WINAPI GetEnvironmentStringsW() { +GUEST_PTR WINAPI GetEnvironmentStringsW() { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetEnvironmentStringsW()\n"); @@ -115,7 +133,7 @@ LPWCH WINAPI GetEnvironmentStringsW() { uint16_t *buffer = static_cast(wibo::heap::guestMalloc(bufSizeW * sizeof(uint16_t))); if (!buffer) { setLastError(ERROR_NOT_ENOUGH_MEMORY); - return nullptr; + return GUEST_NULL; } uint16_t *ptr = buffer; work = environ; @@ -131,7 +149,7 @@ LPWCH WINAPI GetEnvironmentStringsW() { } *ptr = 0; - return buffer; + return toGuestPtr(buffer); } BOOL WINAPI FreeEnvironmentStringsA(LPCH penv) { diff --git a/dll/kernel32/processenv.h b/dll/kernel32/processenv.h index d04c7fa..872753b 100644 --- a/dll/kernel32/processenv.h +++ b/dll/kernel32/processenv.h @@ -4,12 +4,13 @@ namespace kernel32 { -LPSTR WINAPI GetCommandLineA(); -LPWSTR WINAPI GetCommandLineW(); +GUEST_PTR WINAPI GetCommandLineA(); +GUEST_PTR WINAPI GetCommandLineW(); HANDLE WINAPI GetStdHandle(DWORD nStdHandle); BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle); -LPCH WINAPI GetEnvironmentStrings(); -LPWCH WINAPI GetEnvironmentStringsW(); +GUEST_PTR WINAPI GetEnvironmentStrings(); +GUEST_PTR WINAPI GetEnvironmentStringsA(); +GUEST_PTR WINAPI GetEnvironmentStringsW(); BOOL WINAPI FreeEnvironmentStringsA(LPCH penv); BOOL WINAPI FreeEnvironmentStringsW(LPWCH penv); DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize); diff --git a/dll/kernel32/processthreadsapi.cpp b/dll/kernel32/processthreadsapi.cpp index b8a5a40..57de67f 100644 --- a/dll/kernel32/processthreadsapi.cpp +++ b/dll/kernel32/processthreadsapi.cpp @@ -13,6 +13,7 @@ #include "strutil.h" #include "timeutil.h" #include "tls.h" +#include "types.h" #include #include @@ -83,7 +84,7 @@ template void populateStartupInfo(StartupInfo *info) { info->dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; info->wShowWindow = SW_SHOWNORMAL; info->cbReserved2 = 0; - info->lpReserved2 = nullptr; + info->lpReserved2 = GUEST_NULL; info->hStdInput = files::getStdHandle(STD_INPUT_HANDLE); info->hStdOutput = files::getStdHandle(STD_OUTPUT_HANDLE); info->hStdError = files::getStdHandle(STD_ERROR_HANDLE); @@ -182,7 +183,7 @@ BOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature) { HANDLE WINAPI GetCurrentProcess() { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetCurrentProcess() -> %p\n", reinterpret_cast(static_cast(-1))); - return reinterpret_cast(static_cast(-1)); + return kPseudoCurrentProcessHandleValue; } DWORD WINAPI GetCurrentProcessId() { @@ -395,9 +396,9 @@ LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex) { setLastError(ERROR_INVALID_PARAMETER); return nullptr; } - void *result = wibo::tls::getValue(dwTlsIndex); + GUEST_PTR result = wibo::tls::getValue(dwTlsIndex); setLastError(ERROR_SUCCESS); - return result; + return reinterpret_cast(result); } BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) { @@ -407,7 +408,7 @@ BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) { setLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (!wibo::tls::setValue(dwTlsIndex, lpTlsValue)) { + if (!wibo::tls::setValue(dwTlsIndex, toGuestPtr(lpTlsValue))) { setLastError(ERROR_INVALID_PARAMETER); return FALSE; } @@ -463,7 +464,7 @@ HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwSt if ((dwCreationFlags & ~SUPPORTED_FLAGS) != 0) { DEBUG_LOG("CreateThread: unsupported creation flags 0x%x\n", dwCreationFlags); setLastError(ERROR_NOT_SUPPORTED); - return nullptr; + return NO_HANDLE; } Pin obj = make_pin(0); // tid set during pthread_create @@ -554,7 +555,7 @@ int WINAPI GetThreadPriority(HANDLE hThread) { DWORD WINAPI GetPriorityClass(HANDLE hProcess) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("GetPriorityClass(%p)\n", hProcess); + DEBUG_LOG("STUB: GetPriorityClass(%p)\n", hProcess); (void)hProcess; return NORMAL_PRIORITY_CLASS; } diff --git a/dll/kernel32/processthreadsapi.h b/dll/kernel32/processthreadsapi.h index a185efc..1d8e3ac 100644 --- a/dll/kernel32/processthreadsapi.h +++ b/dll/kernel32/processthreadsapi.h @@ -15,9 +15,9 @@ using LPPROCESS_INFORMATION = PROCESS_INFORMATION *; struct STARTUPINFOA { DWORD cb; - LPSTR lpReserved; - LPSTR lpDesktop; - LPSTR lpTitle; + GUEST_PTR lpReserved; + GUEST_PTR lpDesktop; + GUEST_PTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; @@ -28,7 +28,7 @@ struct STARTUPINFOA { DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; - LPBYTE lpReserved2; + GUEST_PTR lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; @@ -38,9 +38,9 @@ using LPSTARTUPINFOA = STARTUPINFOA *; struct STARTUPINFOW { DWORD cb; - LPWSTR lpReserved; - LPWSTR lpDesktop; - LPWSTR lpTitle; + GUEST_PTR lpReserved; + GUEST_PTR lpDesktop; + GUEST_PTR lpTitle; DWORD dwX; DWORD dwY; DWORD dwXSize; @@ -51,7 +51,7 @@ struct STARTUPINFOW { DWORD dwFlags; WORD wShowWindow; WORD cbReserved2; - LPBYTE lpReserved2; + GUEST_PTR lpReserved2; HANDLE hStdInput; HANDLE hStdOutput; HANDLE hStdError; diff --git a/dll/kernel32/synchapi.cpp b/dll/kernel32/synchapi.cpp index ad81411..ebe22f9 100644 --- a/dll/kernel32/synchapi.cpp +++ b/dll/kernel32/synchapi.cpp @@ -4,8 +4,10 @@ #include "context.h" #include "errors.h" #include "handles.h" +#include "heap.h" #include "internal.h" #include "strutil.h" +#include "types.h" #include #include @@ -158,7 +160,7 @@ HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitia if (!mu) { // Name exists but isn't a mutex setLastError(ERROR_INVALID_HANDLE); - return nullptr; + return NO_HANDLE; } HANDLE h = wibo::handles().alloc(std::move(mu), grantedAccess, handleFlags); setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS); @@ -204,7 +206,7 @@ BOOL WINAPI ReleaseMutex(HANDLE hMutex) { } HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, - LPCWSTR lpName) { + LPCWSTR lpName) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CreateEventW(%p, %d, %d, %s)\n", lpEventAttributes, static_cast(bManualReset), static_cast(bInitialState), wideStringToString(lpName).c_str()); @@ -222,7 +224,7 @@ HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual if (!ev) { // Name exists but isn't an event setLastError(ERROR_INVALID_HANDLE); - return nullptr; + return NO_HANDLE; } HANDLE h = wibo::handles().alloc(std::move(ev), grantedAccess, handleFlags); DEBUG_LOG("-> %p (created=%d)\n", h, created ? 1 : 0); @@ -231,7 +233,7 @@ HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual } HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, - LPCSTR lpName) { + LPCSTR lpName) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CreateEventA -> "); std::vector wideName; @@ -241,7 +243,7 @@ HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual } HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, - LPCWSTR lpName) { + LPCWSTR lpName) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CreateSemaphoreW(%p, %ld, %ld, %s)\n", lpSemaphoreAttributes, lInitialCount, lMaximumCount, wideStringToString(lpName).c_str()); @@ -260,7 +262,7 @@ HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG if (!sem) { // Name exists but isn't an event setLastError(ERROR_INVALID_HANDLE); - return nullptr; + return NO_HANDLE; } HANDLE h = wibo::handles().alloc(std::move(sem), granted, hflags); setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS); @@ -268,7 +270,7 @@ HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG } HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, - LPCSTR lpName) { + LPCSTR lpName) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CreateSemaphoreA -> "); std::vector wideName; @@ -545,38 +547,37 @@ DWORD WINAPI WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { HOST_CONTEXT_GUARD(); - VERBOSE_LOG("STUB: InitializeCriticalSection(%p)\n", lpCriticalSection); - if (!lpCriticalSection) { - return; - } - std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection)); + VERBOSE_LOG("InitializeCriticalSection(%p)\n", lpCriticalSection); + InitializeCriticalSectionEx(lpCriticalSection, 0, 0); } BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("STUB: InitializeCriticalSectionEx(%p, %u, 0x%x)\n", lpCriticalSection, dwSpinCount, Flags); + DEBUG_LOG("InitializeCriticalSectionEx(%p, %u, 0x%x)\n", lpCriticalSection, dwSpinCount, Flags); if (!lpCriticalSection) { setLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (Flags & ~CRITICAL_SECTION_NO_DEBUG_INFO) { - setLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection)); + if (Flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) { + lpCriticalSection->DebugInfo = static_cast(-1); + } else { + auto *debugInfo = reinterpret_cast( + wibo::heap::guestCalloc(1, sizeof(RTL_CRITICAL_SECTION_DEBUG))); + debugInfo->CriticalSection = toGuestPtr(lpCriticalSection); + debugInfo->ProcessLocksList.Blink = toGuestPtr(&debugInfo->ProcessLocksList); + debugInfo->ProcessLocksList.Flink = toGuestPtr(&debugInfo->ProcessLocksList); + lpCriticalSection->DebugInfo = toGuestPtr(debugInfo); + } + lpCriticalSection->LockCount = -1; lpCriticalSection->SpinCount = dwSpinCount; return TRUE; } BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("STUB: InitializeCriticalSectionAndSpinCount(%p, %u)\n", lpCriticalSection, dwSpinCount); - if (!lpCriticalSection) { - setLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection)); - lpCriticalSection->SpinCount = dwSpinCount; + DEBUG_LOG("InitializeCriticalSectionAndSpinCount(%p, %u)\n", lpCriticalSection, dwSpinCount); + InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0); return TRUE; } @@ -598,7 +599,7 @@ void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) { (void)lpCriticalSection; } -BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext) { +BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, GUEST_PTR *lpContext) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: InitOnceBeginInitialize(%p, %u, %p, %p)\n", lpInitOnce, dwFlags, fPending, lpContext); if (!lpInitOnce) { @@ -613,7 +614,7 @@ BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL *fPending = TRUE; } if (lpContext) { - *lpContext = nullptr; + *lpContext = GUEST_NULL; } return TRUE; } diff --git a/dll/kernel32/synchapi.h b/dll/kernel32/synchapi.h index 060bff9..db0378f 100644 --- a/dll/kernel32/synchapi.h +++ b/dll/kernel32/synchapi.h @@ -15,14 +15,20 @@ constexpr DWORD INIT_ONCE_ASYNC = 0x00000002UL; constexpr DWORD INIT_ONCE_INIT_FAILED = 0x00000004UL; constexpr DWORD INIT_ONCE_CTX_RESERVED_BITS = 2; -constexpr DWORD CRITICAL_SECTION_NO_DEBUG_INFO = 0x01000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO = 0x01000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN = 0x02000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_FLAG_STATIC_INIT = 0x04000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE = 0x08000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO = 0x10000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_ALL_FLAG_BITS = 0xff000000UL; +constexpr DWORD RTL_CRITICAL_SECTION_FLAG_RESERVED = 0xe0000000UL; struct RTL_CRITICAL_SECTION; struct RTL_CRITICAL_SECTION_DEBUG { WORD Type; WORD CreatorBackTraceIndex; - RTL_CRITICAL_SECTION *CriticalSection; + GUEST_PTR CriticalSection; LIST_ENTRY ProcessLocksList; DWORD EntryCount; DWORD ContentionCount; @@ -33,7 +39,7 @@ struct RTL_CRITICAL_SECTION_DEBUG { }; struct RTL_CRITICAL_SECTION { - RTL_CRITICAL_SECTION_DEBUG *DebugInfo; + GUEST_PTR DebugInfo; LONG LockCount; LONG RecursionCount; HANDLE OwningThread; @@ -47,7 +53,7 @@ using PCRITICAL_SECTION = RTL_CRITICAL_SECTION *; using PRTL_CRITICAL_SECTION_DEBUG = RTL_CRITICAL_SECTION_DEBUG *; union RTL_RUN_ONCE { - PVOID Ptr; + GUEST_PTR Ptr; }; using PRTL_RUN_ONCE = RTL_RUN_ONCE *; @@ -55,17 +61,17 @@ using INIT_ONCE = RTL_RUN_ONCE; using PINIT_ONCE = INIT_ONCE *; using LPINIT_ONCE = INIT_ONCE *; -constexpr INIT_ONCE INIT_ONCE_STATIC_INIT{nullptr}; +constexpr INIT_ONCE INIT_ONCE_STATIC_INIT{GUEST_NULL}; union RTL_SRWLOCK { - PVOID Ptr; + GUEST_PTR Ptr; }; using SRWLOCK = RTL_SRWLOCK; using PSRWLOCK = SRWLOCK *; using PRTL_SRWLOCK = SRWLOCK *; -constexpr SRWLOCK SRWLOCK_INIT{nullptr}; +constexpr SRWLOCK SRWLOCK_INIT{GUEST_NULL}; namespace kernel32 { @@ -92,7 +98,7 @@ BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalS void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection); void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); -BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext); +BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, GUEST_PTR *lpContext); BOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext); void WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock); void WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock); diff --git a/dll/kernel32/sysinfoapi.cpp b/dll/kernel32/sysinfoapi.cpp index 2ef5913..0d6dc67 100644 --- a/dll/kernel32/sysinfoapi.cpp +++ b/dll/kernel32/sysinfoapi.cpp @@ -4,6 +4,7 @@ #include "context.h" #include "errors.h" #include "internal.h" +#include "ntdll.h" #include "timeutil.h" #include @@ -52,12 +53,12 @@ void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) { } lpSystemInfo->dwPageSize = static_cast(pageSize); - lpSystemInfo->lpMinimumApplicationAddress = reinterpret_cast(0x00010000); - if (sizeof(void *) == 4) { - lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast(0x7FFEFFFF); - } else { - lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast(0x00007FFFFFFEFFFFull); - } + lpSystemInfo->lpMinimumApplicationAddress = toGuestPtr(reinterpret_cast(0x00010000)); +#ifdef _WIN64 + lpSystemInfo->lpMaximumApplicationAddress = toGuestPtr(reinterpret_cast(0x00007FFFFFFEFFFFull)); +#else + lpSystemInfo->lpMaximumApplicationAddress = toGuestPtr(reinterpret_cast(0x7FFEFFFF)); +#endif unsigned int cpuCount = 1; long reported = sysconf(_SC_NPROCESSORS_ONLN); @@ -198,11 +199,62 @@ BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation) { setLastError(ERROR_INVALID_PARAMETER); return FALSE; } - std::memset(lpVersionInformation, 0, lpVersionInformation->dwOSVersionInfoSize); - lpVersionInformation->dwMajorVersion = kMajorVersion; - lpVersionInformation->dwMinorVersion = kMinorVersion; - lpVersionInformation->dwBuildNumber = kBuildNumber; - lpVersionInformation->dwPlatformId = 2; + + DWORD size = lpVersionInformation->dwOSVersionInfoSize; + if (size < sizeof(OSVERSIONINFOA)) { + setLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + DWORD requestSize = (size >= sizeof(OSVERSIONINFOEXA)) ? sizeof(OSVERSIONINFOEXW) : sizeof(OSVERSIONINFOW); + OSVERSIONINFOEXW wideInfo{}; + wideInfo.dwOSVersionInfoSize = requestSize; + NTSTATUS status = ntdll::RtlGetVersion(reinterpret_cast(&wideInfo)); + if (status != STATUS_SUCCESS) { + setLastError(wibo::winErrorFromNtStatus(status)); + return FALSE; + } + + std::memset(lpVersionInformation, 0, size); + lpVersionInformation->dwOSVersionInfoSize = size; + lpVersionInformation->dwMajorVersion = wideInfo.dwMajorVersion; + lpVersionInformation->dwMinorVersion = wideInfo.dwMinorVersion; + lpVersionInformation->dwBuildNumber = wideInfo.dwBuildNumber; + lpVersionInformation->dwPlatformId = wideInfo.dwPlatformId; + + if (size >= sizeof(OSVERSIONINFOEXA)) { + auto extended = reinterpret_cast(lpVersionInformation); + extended->wServicePackMajor = wideInfo.wServicePackMajor; + extended->wServicePackMinor = wideInfo.wServicePackMinor; + extended->wSuiteMask = wideInfo.wSuiteMask; + extended->wProductType = wideInfo.wProductType; + extended->wReserved = wideInfo.wReserved; + } + + return TRUE; +} + +BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) { + HOST_CONTEXT_GUARD(); + DEBUG_LOG("GetVersionExW(%p)\n", lpVersionInformation); + if (!lpVersionInformation) { + setLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + DWORD size = lpVersionInformation->dwOSVersionInfoSize; + if (size < sizeof(OSVERSIONINFOW)) { + setLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + NTSTATUS status = ntdll::RtlGetVersion(reinterpret_cast(lpVersionInformation)); + if (status != STATUS_SUCCESS) { + setLastError(wibo::winErrorFromNtStatus(status)); + return FALSE; + } + + lpVersionInformation->dwOSVersionInfoSize = size; return TRUE; } diff --git a/dll/kernel32/sysinfoapi.h b/dll/kernel32/sysinfoapi.h index 44c196c..2b82282 100644 --- a/dll/kernel32/sysinfoapi.h +++ b/dll/kernel32/sysinfoapi.h @@ -12,8 +12,8 @@ struct SYSTEM_INFO { }; }; DWORD dwPageSize; - LPVOID lpMinimumApplicationAddress; - LPVOID lpMaximumApplicationAddress; + GUEST_PTR lpMinimumApplicationAddress; + GUEST_PTR lpMaximumApplicationAddress; DWORD_PTR dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; @@ -35,6 +35,37 @@ struct OSVERSIONINFOA { using LPOSVERSIONINFOA = OSVERSIONINFOA *; +struct OSVERSIONINFOW { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + WCHAR szCSDVersion[128]; +}; + +using LPOSVERSIONINFOW = OSVERSIONINFOW *; + +struct OSVERSIONINFOEXA : OSVERSIONINFOA { + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; +}; + +using LPOSVERSIONINFOEXA = OSVERSIONINFOEXA *; + +struct OSVERSIONINFOEXW : OSVERSIONINFOW { + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; +}; + +using LPOSVERSIONINFOEXW = OSVERSIONINFOEXW *; + namespace kernel32 { void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo); @@ -44,5 +75,6 @@ void WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime); DWORD WINAPI GetTickCount(); DWORD WINAPI GetVersion(); BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation); +BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation); } // namespace kernel32 diff --git a/dll/kernel32/winbase.cpp b/dll/kernel32/winbase.cpp index e8f9e78..2d22738 100644 --- a/dll/kernel32/winbase.cpp +++ b/dll/kernel32/winbase.cpp @@ -235,7 +235,7 @@ bool doFree(void *mem) { DEBUG_LOG("doFree(%p) -> virtualFree\n", mem); MEMORY_BASIC_INFORMATION info; auto result = wibo::heap::virtualQuery(mem, &info); - if (result != wibo::heap::VmStatus::Success || info.BaseAddress != mem) { + if (result != wibo::heap::VmStatus::Success || fromGuestPtr(info.BaseAddress) != mem) { return false; } wibo::heap::virtualFree(mem, info.RegionSize, MEM_RELEASE); @@ -697,7 +697,7 @@ BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid, ReturnedData->ulDataFormatVersion = 1; ReturnedData->ulFlags = ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX; if (dwFlags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) { - ReturnedData->hActCtx = reinterpret_cast(&g_builtinActCtx); + ReturnedData->hActCtx = toGuestPtr(&g_builtinActCtx); } if (!matchedEntry) { @@ -705,9 +705,9 @@ BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid, return FALSE; } - ReturnedData->lpData = const_cast(&matchedEntry->dllData); + ReturnedData->lpData = toGuestPtr(&matchedEntry->dllData); ReturnedData->ulLength = matchedEntry->dllData.Size; - ReturnedData->lpSectionBase = const_cast(&matchedEntry->dllData); + ReturnedData->lpSectionBase = toGuestPtr(&matchedEntry->dllData); ReturnedData->ulSectionTotalLength = matchedEntry->dllData.Size; ReturnedData->ulAssemblyRosterIndex = 1; ReturnedData->AssemblyMetadata = {}; @@ -805,20 +805,20 @@ HGLOBAL WINAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes) { if (uFlags & GMEM_MOVEABLE) { // not implemented rn assert(0); - return nullptr; + return NO_HANDLE; } bool zero = (uFlags & GMEM_ZEROINIT) != 0; void *ret = doAlloc(static_cast(dwBytes), zero); DEBUG_LOG("-> %p\n", ret); - return ret; + return toGuestPtr(ret); } HGLOBAL WINAPI GlobalFree(HGLOBAL hMem) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("GlobalFree(%p)\n", hMem); - if (doFree(hMem)) { + if (doFree(reinterpret_cast(hMem))) { DEBUG_LOG("-> success\n"); - return nullptr; + return NO_HANDLE; } else { DEBUG_LOG("-> failure\n"); return hMem; @@ -830,12 +830,12 @@ HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags) { VERBOSE_LOG("GlobalReAlloc(%p, %zu, %x)\n", hMem, static_cast(dwBytes), uFlags); if (uFlags & GMEM_MODIFY) { assert(0); - return nullptr; + return NO_HANDLE; } bool zero = (uFlags & GMEM_ZEROINIT) != 0; - void *ret = doRealloc(hMem, static_cast(dwBytes), zero); + void *ret = doRealloc(reinterpret_cast(hMem), static_cast(dwBytes), zero); DEBUG_LOG("-> %p\n", ret); - return ret; + return toGuestPtr(ret); } UINT WINAPI GlobalFlags(HGLOBAL hMem) { @@ -855,20 +855,24 @@ HLOCAL WINAPI LocalAlloc(UINT uFlags, SIZE_T uBytes) { void *result = doAlloc(static_cast(uBytes), zero); if (!result) { setLastError(ERROR_NOT_SUPPORTED); - return nullptr; + return NO_HANDLE; } // Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalAlloc. tryMarkExecutable(result); DEBUG_LOG(" -> %p\n", result); - return result; + return toGuestPtr(result); } HLOCAL WINAPI LocalFree(HLOCAL hMem) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("LocalFree(%p)\n", hMem); - // Windows returns NULL on success. - std::free(hMem); - return nullptr; + if (doFree(reinterpret_cast(hMem))) { + DEBUG_LOG("-> success\n"); + return NO_HANDLE; + } else { + DEBUG_LOG("-> failure\n"); + return hMem; + } } HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) { @@ -878,27 +882,27 @@ HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) { if ((uFlags & LMEM_MOVEABLE) != 0) { DEBUG_LOG(" ignoring LMEM_MOVEABLE\n"); } - void *result = doRealloc(hMem, static_cast(uBytes), zero); + void *result = doRealloc(reinterpret_cast(hMem), static_cast(uBytes), zero); if (!result && uBytes != 0) { setLastError(ERROR_NOT_SUPPORTED); - return nullptr; + return NO_HANDLE; } // Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalReAlloc. tryMarkExecutable(result); DEBUG_LOG(" -> %p\n", result); - return result; + return toGuestPtr(result); } HLOCAL WINAPI LocalHandle(LPCVOID pMem) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("LocalHandle(%p)\n", pMem); - return const_cast(pMem); + return toGuestPtr(pMem); } LPVOID WINAPI LocalLock(HLOCAL hMem) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("LocalLock(%p)\n", hMem); - return hMem; + return reinterpret_cast(hMem); } BOOL WINAPI LocalUnlock(HLOCAL hMem) { @@ -911,7 +915,7 @@ BOOL WINAPI LocalUnlock(HLOCAL hMem) { SIZE_T WINAPI LocalSize(HLOCAL hMem) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("LocalSize(%p)\n", hMem); - return hMem ? mi_usable_size(hMem) : 0; + return hMem ? mi_usable_size(reinterpret_cast(hMem)) : 0; } UINT WINAPI LocalFlags(HLOCAL hMem) { diff --git a/dll/kernel32/winbase.h b/dll/kernel32/winbase.h index 4f2af22..6cf1bab 100644 --- a/dll/kernel32/winbase.h +++ b/dll/kernel32/winbase.h @@ -5,21 +5,21 @@ struct GUID; struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA { - PVOID lpInformation; - PVOID lpSectionBase; + GUEST_PTR lpInformation; + GUEST_PTR lpSectionBase; ULONG ulSectionLength; - PVOID lpSectionGlobalData; + GUEST_PTR lpSectionGlobalData; ULONG ulSectionGlobalDataLength; }; struct ACTCTX_SECTION_KEYED_DATA { ULONG cbSize; ULONG ulDataFormatVersion; - PVOID lpData; + GUEST_PTR lpData; ULONG ulLength; - PVOID lpSectionGlobalData; + GUEST_PTR lpSectionGlobalData; ULONG ulSectionGlobalDataLength; - PVOID lpSectionBase; + GUEST_PTR lpSectionBase; ULONG ulSectionTotalLength; HANDLE hActCtx; ULONG ulAssemblyRosterIndex; @@ -68,8 +68,8 @@ ATOM WINAPI AddAtomW(LPCWSTR lpString); UINT WINAPI GetAtomNameA(ATOM nAtom, LPSTR lpBuffer, int nSize); UINT WINAPI GetAtomNameW(ATOM nAtom, LPWSTR lpBuffer, int nSize); UINT WINAPI SetHandleCount(UINT uNumber); -DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, - DWORD nSize, va_list *Arguments); +// DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, +// DWORD nSize, va_list *Arguments); PVOID WINAPI EncodePointer(PVOID Ptr); PVOID WINAPI DecodePointer(PVOID Ptr); BOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName); diff --git a/dll/kernel32/winnls.cpp b/dll/kernel32/winnls.cpp index b0324d0..1773793 100644 --- a/dll/kernel32/winnls.cpp +++ b/dll/kernel32/winnls.cpp @@ -19,6 +19,9 @@ constexpr DWORD kNormIgnoreCase = 0x00000001; constexpr DWORD LCID_INSTALLED = 0x00000001; constexpr DWORD LCID_SUPPORTED = 0x00000002; constexpr DWORD LCID_ALTERNATE_SORTS = 0x00000004; +constexpr LCID kEnUsLcid = 0x0409; +constexpr LCID kInvariantLcid = 0x007f; +constexpr DWORD LOCALE_ALLOW_NEUTRAL_NAMES = 0x08000000; int compareStrings(const std::string &a, const std::string &b, DWORD dwCmpFlags) { for (size_t i = 0;; ++i) { @@ -102,6 +105,50 @@ LANGID WINAPI GetUserDefaultUILanguage() { return 0; } +int WINAPI GetUserDefaultLocaleName(LPWSTR lpLocaleName, int cchLocaleName) { + HOST_CONTEXT_GUARD(); + DEBUG_LOG("GetUserDefaultLocaleName(%p, %d)\n", lpLocaleName, cchLocaleName); + if (!lpLocaleName || cchLocaleName < 0) { + setLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + constexpr char16_t localeName[] = u"en-US"; + constexpr int requiredChars = static_cast(sizeof(localeName) / sizeof(char16_t)); + if (cchLocaleName < requiredChars) { + setLastError(ERROR_INSUFFICIENT_BUFFER); + return 0; + } + + std::memcpy(lpLocaleName, localeName, sizeof(localeName)); + return requiredChars; +} + +LCID WINAPI LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags) { + HOST_CONTEXT_GUARD(); + DEBUG_LOG("LocaleNameToLCID(%p, 0x%x)\n", lpName, dwFlags); + if (dwFlags & ~LOCALE_ALLOW_NEUTRAL_NAMES) { + setLastError(ERROR_INVALID_PARAMETER); + return 0; + } + if (!lpName) { + return kEnUsLcid; + } + + std::string localeName = wideStringToString(lpName); + if (localeName.empty()) { + return kInvariantLcid; + } + + std::string normalized = stringToLower(localeName); + if (normalized == "en-us" || normalized == "en_us" || normalized == "!x-sys-default-locale") { + return kEnUsLcid; + } + + setLastError(ERROR_INVALID_PARAMETER); + return 0; +} + BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo) { HOST_CONTEXT_GUARD(); DEBUG_LOG("GetCPInfo(%u, %p)\n", CodePage, lpCPInfo); @@ -120,7 +167,7 @@ BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo) { } int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, - int cchCount2) { + int cchCount2) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CompareStringA(%u, %u, %s, %d, %s, %d)\n", Locale, dwCmpFlags, lpString1 ? lpString1 : "(null)", cchCount1, lpString2 ? lpString2 : "(null)", cchCount2); @@ -143,7 +190,7 @@ int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int c } int WINAPI CompareStringW(LCID Locale, DWORD dwCmpFlags, LPCWCH lpString1, int cchCount1, LPCWCH lpString2, - int cchCount2) { + int cchCount2) { HOST_CONTEXT_GUARD(); DEBUG_LOG("CompareStringW(%u, %u, %p, %d, %p, %d)\n", Locale, dwCmpFlags, lpString1, cchCount1, lpString2, cchCount2); diff --git a/dll/kernel32/winnls.h b/dll/kernel32/winnls.h index 78341ac..2bc8e38 100644 --- a/dll/kernel32/winnls.h +++ b/dll/kernel32/winnls.h @@ -19,6 +19,8 @@ namespace kernel32 { UINT WINAPI GetACP(); LANGID WINAPI GetSystemDefaultLangID(); LANGID WINAPI GetUserDefaultUILanguage(); +int WINAPI GetUserDefaultLocaleName(LPWSTR lpLocaleName, int cchLocaleName); +LCID WINAPI LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags); BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo); int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2, int cchCount2); diff --git a/dll/kernel32/wow64apiset.cpp b/dll/kernel32/wow64apiset.cpp index f0f8f62..4dde49f 100644 --- a/dll/kernel32/wow64apiset.cpp +++ b/dll/kernel32/wow64apiset.cpp @@ -5,14 +5,15 @@ #include "errors.h" #include "handles.h" #include "internal.h" +#include "types.h" namespace kernel32 { -BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue) { +BOOL WINAPI Wow64DisableWow64FsRedirection(GUEST_PTR *OldValue) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: Wow64DisableWow64FsRedirection(%p)\n", OldValue); if (OldValue) { - *OldValue = nullptr; + *OldValue = GUEST_NULL; } return TRUE; } diff --git a/dll/kernel32/wow64apiset.h b/dll/kernel32/wow64apiset.h index 4194db0..0fe5f85 100644 --- a/dll/kernel32/wow64apiset.h +++ b/dll/kernel32/wow64apiset.h @@ -4,7 +4,7 @@ namespace kernel32 { -BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue); +BOOL WINAPI Wow64DisableWow64FsRedirection(GUEST_PTR *OldValue); BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OldValue); BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process); diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index e6e463a..531fed7 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -9,6 +9,7 @@ #include "msvcrt_trampolines.h" #include "processes.h" #include "strutil.h" +#include "types.h" #include #include @@ -97,10 +98,10 @@ int closeGuestFile(_FILE *file) { namespace msvcrt { int _commode; int _fmode; - char** __initenv; - uint16_t** __winitenv; - uint16_t* _wpgmptr = nullptr; - char* _pgmptr = nullptr; + GUEST_PTR __initenv = GUEST_NULL; + GUEST_PTR __winitenv = GUEST_NULL; + GUEST_PTR _wpgmptr = GUEST_NULL; + GUEST_PTR _pgmptr = GUEST_NULL; int __mb_cur_max = 1; _FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}}; @@ -381,11 +382,11 @@ namespace msvcrt { return mbCodePageSetting; } - int* CDECL __p___mb_cur_max() { + GUEST_PTR CDECL __p___mb_cur_max() { HOST_CONTEXT_GUARD(); ensureMbctypeInitialized(); DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max); - return &__mb_cur_max; + return toGuestPtr(&__mb_cur_max); } int CDECL _setmbcp(int codepage) { @@ -414,19 +415,19 @@ namespace msvcrt { return 0; } - unsigned char *CDECL __p__mbctype() { + GUEST_PTR CDECL __p__mbctype() { HOST_CONTEXT_GUARD(); ensureMbctypeInitialized(); DEBUG_LOG("__p__mbctype() -> %p\n", mbctypeTable.data()); - return mbctypeTable.data(); + return toGuestPtr(mbctypeTable.data()); } - unsigned short **CDECL __p__pctype() { + GUEST_PTR CDECL __p__pctype() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__pctype()\n"); static unsigned short *pointer = nullptr; pointer = pctypeTable().data() + 1; - return &pointer; + return toGuestPtr(&pointer); } int CDECL _isctype(int ch, int mask) { @@ -502,11 +503,11 @@ namespace msvcrt { template struct StringListStorage { - std::vector> strings; - std::unique_ptr pointers; + std::vector> strings; + wibo::heap::guest_ptr pointers; template - CharT **assign(char **source, Converter convert) { + GUEST_PTR *assign(char **source, Converter convert) { if (!source) { strings.clear(); pointers.reset(); @@ -520,18 +521,18 @@ namespace msvcrt { strings.clear(); strings.reserve(count); - pointers = std::make_unique(count + 1); + pointers = wibo::heap::make_guest_unique(count + 1); for (SIZE_T i = 0; i < count; ++i) { auto data = convert(source[i]); - auto buffer = std::make_unique(data.size()); + auto buffer = wibo::heap::make_guest_unique(data.size()); std::copy(data.begin(), data.end(), buffer.get()); CharT *raw = buffer.get(); strings.emplace_back(std::move(buffer)); - pointers[i] = raw; + pointers[i] = toGuestPtr(raw); } - pointers[count] = nullptr; + pointers[count] = GUEST_NULL; return pointers.get(); } }; @@ -554,7 +555,7 @@ namespace msvcrt { template // NOLINTNEXTLINE(readability-non-const-parameter) - int getMainArgsCommon(int *argcOut, CharT ***argvOut, CharT ***envOut, Converter convert) { + int getMainArgsCommon(int *argcOut, GUEST_PTR *argvOut, GUEST_PTR *envOut, Converter convert) { if (argcOut) { *argcOut = wibo::argc; } @@ -563,18 +564,18 @@ namespace msvcrt { static StringListStorage envStorage; if (argvOut) { - *argvOut = argvStorage.assign(wibo::argv, convert); + *argvOut = toGuestPtr(argvStorage.assign(wibo::argv, convert)); } - CharT **envData = envStorage.assign(environ, convert); + GUEST_PTR *envData = envStorage.assign(environ, convert); if (envOut) { - *envOut = envData; + *envOut = toGuestPtr(envData); } if constexpr (std::is_same_v) { - __winitenv = envData; + __winitenv = toGuestPtr(envData); } else if constexpr (std::is_same_v) { - __initenv = envData; + __initenv = toGuestPtr(envData); } return 0; @@ -633,7 +634,7 @@ namespace msvcrt { if (!__winitenv) { getMainArgsCommon(nullptr, nullptr, nullptr, copyWideString); } - return __winitenv; + return reinterpret_cast(__winitenv); } } // namespace @@ -644,42 +645,44 @@ namespace msvcrt { (void)at; } - int* CDECL __p__fmode() { + GUEST_PTR CDECL __p__fmode() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__fmode() -> %p\n", &_fmode); - return &_fmode; + return toGuestPtr(&_fmode); } - int* CDECL __p__commode() { + GUEST_PTR CDECL __p__commode() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__commode() -> %p\n", &_commode); - return &_commode; + return toGuestPtr(&_commode); } - void CDECL _initterm(const _PVFV *ppfn, const _PVFV* end) { + + void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end); - for (; ppfn < end; ppfn++) { - _PVFV func = *ppfn; - if (func) { - DEBUG_LOG("_initterm: calling %p\n", func); - call__PVFV(func); + do { + if (GUEST_PTR pfn = *++ppfn) { + DEBUG_LOG("-> calling %p\n", pfn); + auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn)); + call__PVFV(fn); } - } + } while (ppfn < end); } - int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) { + int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end); - for (; ppfn < end; ppfn++) { - _PIFV func = *ppfn; - if (func) { - int err = call__PIFV(func); - DEBUG_LOG("_initterm_e: calling %p -> %d\n", func, err); - if (err != 0) + do { + if (GUEST_PTR pfn = *++ppfn) { + DEBUG_LOG("-> calling %p\n", pfn); + auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn)); + int err = call__PIFV(fn); + if (err) return err; } - } + } while (ppfn < end); + return 0; } @@ -720,7 +723,7 @@ namespace msvcrt { } // NOLINTNEXTLINE(readability-non-const-parameter) - int CDECL __wgetmainargs(int *wargc, uint16_t ***wargv, uint16_t ***wenv, int doWildcard, int *startInfo) { + int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo) { HOST_CONTEXT_GUARD(); DEBUG_LOG("__wgetmainargs(doWildcard=%d)\n", doWildcard); (void)startInfo; @@ -733,7 +736,7 @@ namespace msvcrt { } // NOLINTNEXTLINE(readability-non-const-parameter) - int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo) { + int CDECL __getmainargs(int *argc, GUEST_PTR *argv, GUEST_PTR *env, int doWildcard, int *startInfo) { HOST_CONTEXT_GUARD(); DEBUG_LOG("__getmainargs(doWildcard=%d)\n", doWildcard); (void)startInfo; @@ -749,10 +752,10 @@ namespace msvcrt { return std::getenv(varname); } - char*** CDECL __p___initenv() { + GUEST_PTR CDECL __p___initenv() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p___initenv() -> %p\n", &__initenv); - return &__initenv; + return toGuestPtr(&__initenv); } char* CDECL strcat(char *dest, const char *src) { @@ -881,7 +884,7 @@ namespace msvcrt { } if (!prev) { - long diff = static_cast(current - start); + LONG diff = static_cast(current - start); DEBUG_LOG("_mbsdec fallback start=%p current=%p diff=%ld first-bytes=%02x %02x %02x %02x\n", start, current, diff, start ? start[0] : 0, start ? start[1] : 0, @@ -1166,11 +1169,11 @@ namespace msvcrt { return ::close(fd); } - long CDECL _lseek(int fd, long offset, int origin) { + LONG CDECL _lseek(int fd, LONG offset, int origin) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_lseek(%d, %ld, %d)\n", fd, offset, origin); off_t result = ::lseek(fd, static_cast(offset), origin); - return static_cast(result); + return static_cast(result); } int CDECL _unlink(const char *path) { @@ -1199,7 +1202,7 @@ namespace msvcrt { return ::utime(hostPath.c_str(), &native); } - int CDECL _chsize(int fd, long size) { + int CDECL _chsize(int fd, LONG size) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_chsize(%d, %ld)\n", fd, size); return ::ftruncate(fd, static_cast(size)); @@ -1238,13 +1241,13 @@ namespace msvcrt { return std::strtok(str, delim); } - long CDECL _adj_fdiv_r(long value) { + LONG CDECL _adj_fdiv_r(LONG value) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: _adj_fdiv_r(%ld)\n", value); return value; } - void CDECL _adjust_fdiv(long n) { + void CDECL _adjust_fdiv(LONG n) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: _adjust_fdiv(%ld)\n", n); (void)n; @@ -1261,14 +1264,14 @@ namespace msvcrt { if (gettimeofday(&tv, nullptr) != 0) { return -1; } - timeptr->time = tv.tv_sec; + timeptr->time = static_cast(tv.tv_sec); timeptr->millitm = static_cast(tv.tv_usec / 1000); timeptr->timezone = 0; timeptr->dstflag = 0; return 0; } - unsigned long CDECL _ultoa(unsigned long value, char *str, int radix) { + ULONG CDECL _ultoa(ULONG value, char *str, int radix) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_ultoa(%lu, %p, %d)\n", value, str, radix); if (!str || radix < 2 || radix > 36) { @@ -1282,15 +1285,15 @@ namespace msvcrt { *--cursor = '0'; } while (value > 0) { - unsigned long digit = value % static_cast(radix); - value /= static_cast(radix); + ULONG digit = value % static_cast(radix); + value /= static_cast(radix); *--cursor = static_cast(digit < 10 ? '0' + digit : 'A' + (digit - 10)); } std::strcpy(str, cursor); - return static_cast(std::strlen(str)); + return static_cast(std::strlen(str)); } - char* CDECL _ltoa(long value, char *str, int radix) { + char* CDECL _ltoa(LONG value, char *str, int radix) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_ltoa(%ld, %p, %d)\n", value, str, radix); if (!str || radix < 2 || radix > 36) { @@ -1298,9 +1301,9 @@ namespace msvcrt { return nullptr; } bool negative = value < 0; - unsigned long absValue = negative ? static_cast(-value) : static_cast(value); + ULONG absValue = negative ? static_cast(-value) : static_cast(value); char buffer[65]; - unsigned long length = _ultoa(absValue, buffer, radix); + ULONG length = _ultoa(absValue, buffer, radix); std::string result; if (negative) { result.push_back('-'); @@ -1437,7 +1440,7 @@ namespace msvcrt { TIME_T CDECL time(TIME_T *t) { HOST_CONTEXT_GUARD(); DEBUG_LOG("time(%p)\n", t); - TIME_T result = std::time(nullptr); + TIME_T result = static_cast(std::time(nullptr)); if (t) { *t = result; } @@ -1468,11 +1471,11 @@ namespace msvcrt { return result; } - int CDECL _wdupenv_s(uint16_t **buffer, SIZE_T *numberOfElements, const uint16_t *varname){ + int CDECL _wdupenv_s(GUEST_PTR *buffer, SIZE_T *numberOfElements, const uint16_t *varname){ HOST_CONTEXT_GUARD(); DEBUG_LOG("_wdupenv_s(%p, %p, %s)\n", buffer, numberOfElements, wideStringToString(varname).c_str()); if (buffer) { - *buffer = nullptr; + *buffer = GUEST_NULL; } if (numberOfElements) { *numberOfElements = 0; @@ -1504,7 +1507,7 @@ namespace msvcrt { wstrncpy(copy, match->value, value_len); copy[value_len] = 0; - *buffer = copy; + *buffer = toGuestPtr(copy); if (numberOfElements) { *numberOfElements = value_len + 1; } @@ -1678,10 +1681,18 @@ namespace msvcrt { return copy; } - unsigned long CDECL strtoul(const char *str, char **endptr, int base) { + ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("strtoul(%s, %p, %d)\n", str, endptr, base); - return ::strtoul(str, endptr, base); + int ret; + if (endptr != nullptr) { + char *endptr_host = reinterpret_cast(fromGuestPtr(*endptr)); + ret = ::strtoul(str, &endptr_host, base); + *endptr = toGuestPtr(endptr_host); + } else { + ret = ::strtoul(str, nullptr, base); + } + return ret; } void* CDECL malloc(SIZE_T size){ @@ -1728,7 +1739,7 @@ namespace msvcrt { lockTable()[static_cast(locknum)].unlock(); } - _onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **pbegin, _onexit_t **pend) { + _onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend) { HOST_CONTEXT_GUARD(); DEBUG_LOG("__dllonexit(%p, %p, %p)\n", func, pbegin, pend); if (!pbegin || !pend) { @@ -1740,13 +1751,13 @@ namespace msvcrt { return nullptr; } - _onexit_t *table = static_cast<_onexit_t *>(wibo::heap::guestRealloc(pbegin, len * sizeof(_onexit_t))); + GUEST_PTR *table = static_cast(wibo::heap::guestRealloc(pbegin, len * sizeof(GUEST_PTR))); if (!table) { return nullptr; } - *pbegin = table; - *pend = table + len; - table[len - 1] = func; + *pbegin = toGuestPtr(table); + *pend = toGuestPtr(table + len); + table[len - 1] = toGuestPtr(reinterpret_cast(func)); return func; } @@ -1827,14 +1838,14 @@ namespace msvcrt { return isatty(fd); } - int CDECL fseek(_FILE *stream, long offset, int origin) { + int CDECL fseek(_FILE *stream, LONG offset, int origin) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin); FILE* host = mapToHostFile(stream); return std::fseek(host, offset, origin); } - long CDECL ftell(_FILE *stream) { + LONG CDECL ftell(_FILE *stream) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("ftell(%p)\n", stream); FILE* host = mapToHostFile(stream); @@ -1895,7 +1906,7 @@ namespace msvcrt { return std::fgetwc(host); } - int CDECL _wfopen_s(_FILE **stream, const uint16_t *filename, const uint16_t *mode) { + int CDECL _wfopen_s(GUEST_PTR *stream, const uint16_t *filename, const uint16_t *mode) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(), wideStringToString(mode).c_str()); @@ -1907,10 +1918,10 @@ namespace msvcrt { std::string narrowMode = wideStringToString(mode); FILE *handle = std::fopen(narrowName.c_str(), narrowMode.c_str()); if (!handle) { - *stream = nullptr; + *stream = GUEST_NULL; return errno ? errno : EINVAL; } - *stream = mapToGuestFile(handle); + *stream = toGuestPtr(mapToGuestFile(handle)); return 0; } @@ -2061,13 +2072,13 @@ namespace msvcrt { return 0; } - unsigned long CDECL wcsspn(const uint16_t *str1, const uint16_t *str2) { + ULONG CDECL wcsspn(const uint16_t *str1, const uint16_t *str2) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("wcsspn(%p, %p)\n", str1, str2); if (!str1 || !str2) { return 0; } - unsigned long count = 0; + ULONG count = 0; for (const uint16_t *p = str1; *p; ++p) { bool match = false; for (const uint16_t *q = str2; *q; ++q) { @@ -2084,7 +2095,7 @@ namespace msvcrt { return count; } - long CDECL _wtol(const uint16_t *str) { + LONG CDECL _wtol(const uint16_t *str) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("_wtol(%p)\n", str); return wstrtol(str, nullptr, 10); @@ -2341,13 +2352,13 @@ namespace msvcrt { return 0; } - long CDECL _XcptFilter(unsigned long code, void *) { + LONG CDECL _XcptFilter(ULONG code, void *) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: _XcptFilter(%lu)\n", code); return 0; } - int CDECL _get_wpgmptr(uint16_t **pValue) { + int CDECL _get_wpgmptr(GUEST_PTR *pValue) { HOST_CONTEXT_GUARD(); DEBUG_LOG("_get_wpgmptr(%p)\n", pValue); if (!pValue) { @@ -2358,22 +2369,25 @@ namespace msvcrt { return 0; } - const auto wStr = stringToWideString(wibo::guestExecutablePath.c_str()); - delete[] _wpgmptr; + // TODO + // const auto wStr = stringToWideString(wibo::guestExecutablePath.c_str()); + // delete[] _wpgmptr; - _wpgmptr = new uint16_t[wStr.size() + 1]; - std::copy(wStr.begin(), wStr.end(), _wpgmptr); - _wpgmptr[wStr.size()] = 0; + // _wpgmptr = new uint16_t[wStr.size() + 1]; + // std::copy(wStr.begin(), wStr.end(), _wpgmptr); + // _wpgmptr[wStr.size()] = 0; - *pValue = _wpgmptr; + // *pValue = _wpgmptr; return 0; } - char** CDECL __p__pgmptr() { + GUEST_PTR CDECL __p__pgmptr() { HOST_CONTEXT_GUARD(); DEBUG_LOG("__p__pgmptr()\n"); - _pgmptr = const_cast(wibo::guestExecutablePath.c_str()); - return &_pgmptr; + // TODO + // _pgmptr = const_cast(wibo::guestExecutablePath.c_str()); + // return &_pgmptr; + return GUEST_NULL; } int CDECL _wsplitpath_s(const uint16_t * path, uint16_t * drive, SIZE_T driveNumberOfElements, uint16_t *dir, SIZE_T dirNumberOfElements, @@ -2564,7 +2578,7 @@ namespace msvcrt { return wstrtol(str, nullptr, 10); } - int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix) { + int CDECL _ltoa_s(LONG value, char *buffer, SIZE_T sizeInChars, int radix) { HOST_CONTEXT_GUARD(); VERBOSE_LOG("_ltoa_s(%ld, %p, %zu, %d)\n", value, buffer, sizeInChars, radix); if (!buffer || sizeInChars == 0) { @@ -2782,10 +2796,18 @@ namespace msvcrt { return wstrrchr(str, c); } - unsigned long CDECL wcstoul(const uint16_t *strSource, uint16_t **endptr, int base){ + ULONG CDECL wcstoul(const uint16_t *strSource, GUEST_PTR *endptr, int base){ HOST_CONTEXT_GUARD(); VERBOSE_LOG("wcstoul(%p, %p, %d)\n", strSource, endptr, base); - return wstrtoul(strSource, endptr, base); + int ret; + if (endptr != nullptr) { + uint16_t *endptr_host = reinterpret_cast(fromGuestPtr(*endptr)); + ret = ::wstrtoul(strSource, &endptr_host, base); + *endptr = toGuestPtr(endptr_host); + } else { + ret = ::wstrtoul(strSource, nullptr, base); + } + return ret; } _FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){ @@ -2842,7 +2864,7 @@ namespace msvcrt { return &errno; } - LONG_PTR CDECL _wspawnvp(int mode, const uint16_t* cmdname, const uint16_t* const * argv) { + LONG_PTR CDECL _wspawnvp(int mode, const uint16_t* cmdname, GUEST_PTR *argv) { HOST_CONTEXT_GUARD(); if (!cmdname || !argv) { errno = EINVAL; @@ -2853,8 +2875,9 @@ namespace msvcrt { DEBUG_LOG("_wspawnvp(%d, %s)\n", mode, command.c_str()); std::vector argStorage; - for (const uint16_t *const *cursor = argv; *cursor; ++cursor) { - argStorage.emplace_back(wideStringToString(*cursor)); + for (GUEST_PTR *cursor = argv; *cursor; ++cursor) { + const WCHAR *arg = reinterpret_cast(fromGuestPtr(*cursor)); + argStorage.emplace_back(wideStringToString(arg)); } auto resolved = wibo::resolveExecutable(command, false); @@ -2891,7 +2914,7 @@ namespace msvcrt { return static_cast(po->pid); } - LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, const char * const *argv) { + LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv) { HOST_CONTEXT_GUARD(); if (!cmdname || !argv) { errno = EINVAL; @@ -2902,8 +2925,9 @@ namespace msvcrt { DEBUG_LOG("_spawnvp(%d, %s)\n", mode, command.c_str()); std::vector argStorage; - for (const char * const *cursor = argv; *cursor; ++cursor) { - argStorage.emplace_back(*cursor); + for (GUEST_PTR *cursor = argv; *cursor; ++cursor) { + const char *arg = reinterpret_cast(fromGuestPtr(*cursor)); + argStorage.emplace_back(arg); } auto resolved = wibo::resolveExecutable(command, false); diff --git a/dll/msvcrt.h b/dll/msvcrt.h index 6238ed7..c78d37e 100644 --- a/dll/msvcrt.h +++ b/dll/msvcrt.h @@ -12,8 +12,8 @@ typedef void(_CC_CDECL *signal_handler)(int); typedef int(_CC_CDECL *sort_compare)(const void *, const void *); struct _utimbuf { - long actime; - long modtime; + LONG actime; + LONG modtime; }; struct _timeb { @@ -29,10 +29,10 @@ namespace msvcrt { extern int _commode; extern int _fmode; -extern char **__initenv; -extern WCHAR **__winitenv; -extern WCHAR *_wpgmptr; -extern char *_pgmptr; +extern GUEST_PTR __initenv; +extern GUEST_PTR __winitenv; +extern GUEST_PTR _wpgmptr; +extern GUEST_PTR _pgmptr; extern int __mb_cur_max; extern _FILE _iob[_IOB_ENTRIES]; @@ -42,23 +42,23 @@ void CDECL setbuf(_FILE *stream, char *buffer); void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext); int CDECL _fileno(_FILE *stream); int CDECL _getmbcp(); -int *CDECL __p___mb_cur_max(); +GUEST_PTR CDECL __p___mb_cur_max(); int CDECL _setmbcp(int codepage); -unsigned char *CDECL __p__mbctype(); -unsigned short **CDECL __p__pctype(); +GUEST_PTR CDECL __p__mbctype(); +GUEST_PTR CDECL __p__pctype(); int CDECL _isctype(int ch, int mask); void CDECL __set_app_type(int at); -int *CDECL __p__fmode(); -int *CDECL __p__commode(); -void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end); -int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end); +GUEST_PTR CDECL __p__fmode(); +GUEST_PTR CDECL __p__commode(); +void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end); +int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end); unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask); int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask); _onexit_t CDECL _onexit(_onexit_t func); -int CDECL __wgetmainargs(int *wargc, WCHAR ***wargv, WCHAR ***wenv, int doWildcard, int *startInfo); -int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo); +int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo); +int CDECL __getmainargs(int *argc, GUEST_PTR *argv, GUEST_PTR *env, int doWildcard, int *startInfo); char *CDECL getenv(const char *varname); -char ***CDECL __p___initenv(); +GUEST_PTR CDECL __p___initenv(); char *CDECL strcat(char *dest, const char *src); char *CDECL strcpy(char *dest, const char *src); int CDECL _access(const char *path, int mode); @@ -84,31 +84,33 @@ int CDECL _ismbcdigit(unsigned int ch); int CDECL _stricmp(const char *lhs, const char *rhs); int CDECL _strnicmp(const char *lhs, const char *rhs, SIZE_T count); int CDECL _memicmp(const void *lhs, const void *rhs, SIZE_T count); +#ifndef __x86_64__ // TODO int CDECL_NO_CONV _vsnprintf(char *buffer, SIZE_T count, const char *format, va_list args); int CDECL_NO_CONV _snprintf(char *buffer, SIZE_T count, const char *format, ...); int CDECL_NO_CONV sprintf(char *buffer, const char *format, ...); int CDECL_NO_CONV printf(const char *format, ...); int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...); +#endif char *CDECL fgets(char *str, int count, _FILE *stream); SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream); _FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag); int CDECL _sopen(const char *path, int oflag, int shflag, int pmode); int CDECL _read(int fd, void *buffer, unsigned int count); int CDECL _close(int fd); -long CDECL _lseek(int fd, long offset, int origin); +LONG CDECL _lseek(int fd, LONG offset, int origin); int CDECL _unlink(const char *path); int CDECL _utime(const char *path, const _utimbuf *times); -int CDECL _chsize(int fd, long size); +int CDECL _chsize(int fd, LONG size); char *CDECL strncpy(char *dest, const char *src, SIZE_T count); char *CDECL strpbrk(const char *str, const char *accept); char *CDECL strstr(const char *haystack, const char *needle); char *CDECL strrchr(const char *str, int ch); char *CDECL strtok(char *str, const char *delim); -long CDECL _adj_fdiv_r(long value); -void CDECL _adjust_fdiv(long n); +LONG CDECL _adj_fdiv_r(LONG value); +void CDECL _adjust_fdiv(LONG n); int CDECL _ftime(struct _timeb *timeptr); -unsigned long CDECL _ultoa(unsigned long value, char *str, int radix); -char *CDECL _ltoa(long value, char *str, int radix); +ULONG CDECL _ultoa(ULONG value, char *str, int radix); +char *CDECL _ltoa(LONG value, char *str, int radix); char *CDECL _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext); char *CDECL _fullpath(char *absPath, const char *relPath, SIZE_T maxLength); int CDECL _putenv(const char *envString); @@ -119,7 +121,7 @@ TIME_T CDECL time(TIME_T *t); char *CDECL __unDName(char *outputString, const char *mangledName, int maxStringLength, void *(*allocFunc)(SIZE_T), void (*freeFunc)(void *), unsigned short); char *CDECL setlocale(int category, const char *locale); -int CDECL _wdupenv_s(WCHAR **buffer, SIZE_T *numberOfElements, const WCHAR *varname); +int CDECL _wdupenv_s(GUEST_PTR *buffer, SIZE_T *numberOfElements, const WCHAR *varname); int CDECL _wgetenv_s(SIZE_T *pReturnValue, WCHAR *buffer, SIZE_T numberOfElements, const WCHAR *varname); SIZE_T CDECL strlen(const char *str); int CDECL strcmp(const char *lhs, const char *rhs); @@ -129,38 +131,40 @@ int CDECL strcpy_s(char *dest, SIZE_T dest_size, const char *src); int CDECL strcat_s(char *dest, SIZE_T numberOfElements, const char *src); int CDECL strncpy_s(char *dest, SIZE_T dest_size, const char *src, SIZE_T count); char *CDECL _strdup(const char *strSource); -unsigned long CDECL strtoul(const char *str, char **endptr, int base); +ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base); void *CDECL malloc(SIZE_T size); void *CDECL calloc(SIZE_T count, SIZE_T size); void *CDECL realloc(void *ptr, SIZE_T size); void *CDECL _malloc_crt(SIZE_T size); void CDECL _lock(int locknum); void CDECL _unlock(int locknum); -_onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **pbegin, _onexit_t **pend); +_onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend); void CDECL free(void *ptr); void *CDECL memcpy(void *dest, const void *src, SIZE_T count); void *CDECL memmove(void *dest, const void *src, SIZE_T count); int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count); void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare); int CDECL fflush(_FILE *stream); +#ifndef __x86_64__ // TODO int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args); +#endif _FILE *CDECL fopen(const char *filename, const char *mode); int CDECL _dup2(int fd1, int fd2); int CDECL _isatty(int fd); -int CDECL fseek(_FILE *stream, long offset, int origin); -long CDECL ftell(_FILE *stream); +int CDECL fseek(_FILE *stream, LONG offset, int origin); +LONG CDECL ftell(_FILE *stream); int CDECL feof(_FILE *stream); int CDECL fputws(const WCHAR *str, _FILE *stream); int CDECL _cputws(const WCHAR *string); WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream); WINT_T CDECL fgetwc(_FILE *stream); -int CDECL _wfopen_s(_FILE **stream, const WCHAR *filename, const WCHAR *mode); +int CDECL _wfopen_s(GUEST_PTR *stream, const WCHAR *filename, const WCHAR *mode); int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs); int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname, const WCHAR *ext); int CDECL _wputenv_s(const WCHAR *varname, const WCHAR *value); -unsigned long CDECL wcsspn(const WCHAR *str1, const WCHAR *str2); -long CDECL _wtol(const WCHAR *str); +ULONG CDECL wcsspn(const WCHAR *str1, const WCHAR *str2); +LONG CDECL _wtol(const WCHAR *str); int CDECL _wcsupr_s(WCHAR *str, SIZE_T size); int CDECL _wcslwr_s(WCHAR *str, SIZE_T size); WINT_T CDECL towlower(WINT_T ch); @@ -172,8 +176,10 @@ int CDECL _crt_debugger_hook(int value); int CDECL _configthreadlocale(int mode); void CDECL __setusermatherr(void *handler); void CDECL _cexit(); +#ifndef __x86_64__ // TODO int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args); int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...); +#endif int CDECL fputc(int ch, _FILE *stream); SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream); char *CDECL strerror(int errnum); @@ -188,9 +194,9 @@ void CDECL _invoke_watson(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UIN void CDECL terminateShim(); int CDECL _purecall(); int CDECL _except_handler4_common(void *, void *, void *, void *); -long CDECL _XcptFilter(unsigned long code, void *); -int CDECL _get_wpgmptr(WCHAR **pValue); -char **CDECL __p__pgmptr(); +LONG CDECL _XcptFilter(ULONG code, void *); +int CDECL _get_wpgmptr(GUEST_PTR *pValue); +GUEST_PTR CDECL __p__pgmptr(); int CDECL _wsplitpath_s(const WCHAR *path, WCHAR *drive, SIZE_T driveNumberOfElements, WCHAR *dir, SIZE_T dirNumberOfElements, WCHAR *fname, SIZE_T nameNumberOfElements, WCHAR *ext, SIZE_T extNumberOfElements); @@ -202,28 +208,32 @@ int CDECL wcsncpy_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSou int CDECL wcsncat_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSource, SIZE_T count); int CDECL _itow_s(int value, WCHAR *buffer, SIZE_T size, int radix); int CDECL _wtoi(const WCHAR *str); -int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix); +int CDECL _ltoa_s(LONG value, char *buffer, SIZE_T sizeInChars, int radix); int CDECL wcscpy_s(WCHAR *dest, SIZE_T dest_size, const WCHAR *src); +#ifndef __x86_64__ // TODO int CDECL_NO_CONV swprintf_s(WCHAR *buffer, SIZE_T sizeOfBuffer, const WCHAR *format, ...); int CDECL_NO_CONV swscanf_s(const WCHAR *buffer, const WCHAR *format, ...); +#endif int *CDECL _get_osfhandle(int fd); int CDECL _write(int fd, const void *buffer, unsigned int count); void CDECL exit(int status); int CDECL wcsncmp(const WCHAR *string1, const WCHAR *string2, SIZE_T count); +#ifndef __x86_64__ // TODO int CDECL_NO_CONV _vswprintf_c_l(WCHAR *buffer, SIZE_T size, const WCHAR *format, ...); +#endif const WCHAR *CDECL wcsstr(const WCHAR *dest, const WCHAR *src); int CDECL iswspace(WINT_T w); int CDECL iswdigit(WINT_T w); const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c); const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c); -unsigned long CDECL wcstoul(const WCHAR *strSource, WCHAR **endptr, int base); +ULONG CDECL wcstoul(const WCHAR *strSource, GUEST_PTR *endptr, int base); _FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag); int CDECL puts(const char *str); int CDECL fclose(_FILE *stream); int CDECL _flushall(); int *CDECL _errno(); -LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv); -LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, const char *const *argv); +LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, GUEST_PTR *argv); +LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv); int CDECL _wunlink(const WCHAR *filename); WCHAR *CDECL _wfullpath(WCHAR *absPath, const WCHAR *relPath, SIZE_T maxLength); diff --git a/dll/ntdll.cpp b/dll/ntdll.cpp index 775061e..b2b4290 100644 --- a/dll/ntdll.cpp +++ b/dll/ntdll.cpp @@ -24,7 +24,7 @@ namespace { struct PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; - PEB *PebBaseAddress; + GUEST_PTR PebBaseAddress; ULONG_PTR AffinityMask; LONG BasePriority; ULONG_PTR UniqueProcessId; @@ -94,8 +94,8 @@ std::string windowsImagePathFor(const ProcessHandleDetails &details) { } // namespace namespace kernel32 { -BOOL WIN_FUNC SetEvent(HANDLE hEvent); -BOOL WIN_FUNC ResetEvent(HANDLE hEvent); +BOOL WINAPI SetEvent(HANDLE hEvent); +BOOL WINAPI ResetEvent(HANDLE hEvent); } // namespace kernel32 namespace ntdll { @@ -262,7 +262,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Apc return status; } -NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, +NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect) { HOST_CONTEXT_GUARD(); DEBUG_LOG("NtAllocateVirtualMemory(%p, %p, %lu, %p, %lu, %lu) ", ProcessHandle, BaseAddress, ZeroBits, RegionSize, @@ -276,20 +276,24 @@ NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress return STATUS_INVALID_PARAMETER; } - wibo::heap::VmStatus vmStatus = - wibo::heap::virtualAlloc(reinterpret_cast(BaseAddress), reinterpret_cast(RegionSize), - static_cast(AllocationType), static_cast(Protect)); + void *baseAddress = fromGuestPtr(*BaseAddress); + size_t regionSize = static_cast(*RegionSize); + wibo::heap::VmStatus vmStatus = wibo::heap::virtualAlloc( + &baseAddress, ®ionSize, static_cast(AllocationType), static_cast(Protect)); if (vmStatus != wibo::heap::VmStatus::Success) { NTSTATUS status = wibo::heap::ntStatusFromVmStatus(vmStatus); DEBUG_LOG("-> 0x%x\n", status); return status; } + *BaseAddress = toGuestPtr(baseAddress); + *RegionSize = static_cast(regionSize); + DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS); return STATUS_SUCCESS; } -NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect, +NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, PSIZE_T NumberOfBytesToProtect, ULONG NewAccessProtection, PULONG OldAccessProtection) { HOST_CONTEXT_GUARD(); DEBUG_LOG("NtProtectVirtualMemory(%p, %p, %p, %lu, %p) ", ProcessHandle, BaseAddress, NumberOfBytesToProtect, @@ -303,8 +307,8 @@ NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, return STATUS_INVALID_PARAMETER; } - void *base = *BaseAddress; - std::size_t length = static_cast(*NumberOfBytesToProtect); + void *base = fromGuestPtr(*BaseAddress); + size_t length = static_cast(*NumberOfBytesToProtect); wibo::heap::VmStatus vmStatus = wibo::heap::virtualProtect(base, length, static_cast(NewAccessProtection), OldAccessProtection); if (vmStatus != wibo::heap::VmStatus::Success) { @@ -351,7 +355,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("NtQueryInformationProcess(%p, %u, %p, %u, %p) ", ProcessHandle, ProcessInformationClass, + DEBUG_LOG("NtQueryInformationProcess(%d, %u, %p, %u, %p) ", ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength); if (!ProcessInformation) { DEBUG_LOG("-> 0x%x\n", STATUS_INVALID_PARAMETER); @@ -378,7 +382,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS auto *info = reinterpret_cast(ProcessInformation); std::memset(info, 0, sizeof(*info)); info->ExitStatus = static_cast(details.exitCode); - info->PebBaseAddress = details.peb; + info->PebBaseAddress = toGuestPtr(details.peb); DWORD_PTR processMask = 0; DWORD_PTR systemMask = 0; if (kernel32::GetProcessAffinityMask(ProcessHandle, &processMask, &systemMask)) { @@ -440,7 +444,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS size_t characterCount = widePath.empty() ? 0 : widePath.size() - 1; unicode->Length = static_cast(characterCount * sizeof(uint16_t)); unicode->MaximumLength = static_cast(widePath.size() * sizeof(uint16_t)); - unicode->Buffer = buffer; + unicode->Buffer = toGuestPtr(buffer); DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS); return STATUS_SUCCESS; } diff --git a/dll/ntdll.h b/dll/ntdll.h index aa5b908..fee54fa 100644 --- a/dll/ntdll.h +++ b/dll/ntdll.h @@ -7,7 +7,7 @@ using PIO_APC_ROUTINE = PVOID; typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; - PVOID Pointer; + GUEST_PTR Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; @@ -38,12 +38,13 @@ NTSTATUS WINAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcR NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); -NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize, - ULONG AllocationType, ULONG Protect); -NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect, +NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, ULONG_PTR ZeroBits, + PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); +NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, PSIZE_T NumberOfBytesToProtect, ULONG NewAccessProtection, PULONG OldAccessProtection); NTSTATUS WINAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation); NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, - PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); + PVOID ProcessInformation, ULONG ProcessInformationLength, + PULONG ReturnLength); } // namespace ntdll diff --git a/dll/ole32.cpp b/dll/ole32.cpp index 1ba7e57..fe24fd6 100644 --- a/dll/ole32.cpp +++ b/dll/ole32.cpp @@ -119,7 +119,7 @@ HRESULT WINAPI CoInitialize(LPVOID pvReserved) { } HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, - LPVOID *ppv) { + GUEST_PTR *ppv) { HOST_CONTEXT_GUARD(); DEBUG_LOG("STUB: CoCreateInstance(0x%x, %p, %d, 0x%x, %p)\n", rclsid->Data1, pUnkOuter, dwClsContext, riid->Data1, *ppv); diff --git a/dll/ole32.h b/dll/ole32.h index c2f0292..1171136 100644 --- a/dll/ole32.h +++ b/dll/ole32.h @@ -5,7 +5,7 @@ namespace ole32 { HRESULT WINAPI CoInitialize(LPVOID pvReserved); -HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, LPVOID *ppv); +HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, GUEST_PTR *ppv); HRESULT WINAPI CLSIDFromString(LPCWSTR lpsz, GUID *pclsid); } // namespace ole32 diff --git a/dll/rpcrt4.cpp b/dll/rpcrt4.cpp index 0ea1ee6..6cac81d 100644 --- a/dll/rpcrt4.cpp +++ b/dll/rpcrt4.cpp @@ -4,8 +4,8 @@ #include "context.h" #include "heap.h" #include "modules.h" +#include "types.h" -#include #include #include #include @@ -44,7 +44,7 @@ struct BindingHandleData { }; std::unordered_map g_stringBindings; -std::unordered_map> g_bindingHandles; +std::unordered_map> g_bindingHandles; std::u16string toU16(RPC_WSTR str) { if (!str) { @@ -112,7 +112,7 @@ BindingHandleData *getBinding(RPC_BINDING_HANDLE handle) { namespace rpcrt4 { RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint, - RPC_WSTR options, RPC_WSTR *stringBinding) { + RPC_WSTR options, GUEST_PTR *stringBinding) { HOST_CONTEXT_GUARD(); BindingComponents components; components.objectUuid = toU16(objUuid); @@ -136,18 +136,18 @@ RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, R buffer[length] = 0; RPC_WSTR result = reinterpret_cast(buffer); g_stringBindings[result] = components; - *stringBinding = result; + *stringBinding = toGuestPtr(result); } return RPC_S_OK; } -RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding) { +RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, GUEST_PTR *binding) { HOST_CONTEXT_GUARD(); if (!binding) { return RPC_S_INVALID_ARG; } - *binding = nullptr; + *binding = GUEST_NULL; if (!stringBinding) { return RPC_S_INVALID_STRING_BINDING; } @@ -155,13 +155,13 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDI if (it == g_stringBindings.end()) { return RPC_S_INVALID_STRING_BINDING; } - auto handleData = std::make_unique(); + auto handleData = wibo::heap::make_guest_unique(); handleData->components = it->second; handleData->bindingString = composeString(handleData->components); handleData->serverReachable = false; RPC_BINDING_HANDLE handle = reinterpret_cast(handleData.get()); g_bindingHandles.emplace(handle, std::move(handleData)); - *binding = handle; + *binding = toGuestPtr(handle); DEBUG_LOG("RpcBindingFromStringBindingW(handle=%p)\n", handle); return RPC_S_OK; } @@ -190,12 +190,12 @@ RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR return RPC_S_OK; } -RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) { +RPC_STATUS WINAPI RpcBindingFree(GUEST_PTR *binding) { HOST_CONTEXT_GUARD(); if (!binding) { return RPC_S_INVALID_ARG; } - RPC_BINDING_HANDLE handle = *binding; + RPC_BINDING_HANDLE handle = reinterpret_cast(fromGuestPtr(*binding)); if (!handle) { return RPC_S_INVALID_BINDING; } @@ -204,17 +204,17 @@ RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) { return RPC_S_INVALID_BINDING; } g_bindingHandles.erase(it); - *binding = nullptr; + *binding = GUEST_NULL; DEBUG_LOG("RpcBindingFree\n"); return RPC_S_OK; } -RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) { +RPC_STATUS WINAPI RpcStringFreeW(GUEST_PTR *string) { HOST_CONTEXT_GUARD(); if (!string) { return RPC_S_INVALID_ARG; } - RPC_WSTR value = *string; + RPC_WSTR value = reinterpret_cast(fromGuestPtr(*string)); if (!value) { return RPC_S_OK; } @@ -223,7 +223,7 @@ RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) { g_stringBindings.erase(it); } std::free(reinterpret_cast(value)); - *string = nullptr; + *string = GUEST_NULL; return RPC_S_OK; } diff --git a/dll/rpcrt4.h b/dll/rpcrt4.h index 8260826..56e6dba 100644 --- a/dll/rpcrt4.h +++ b/dll/rpcrt4.h @@ -15,25 +15,27 @@ struct RPC_SECURITY_QOS { ULONG Capabilities; ULONG IdentityTracking; ULONG ImpersonationType; - PVOID AdditionalSecurityInfo; + GUEST_PTR AdditionalSecurityInfo; }; union CLIENT_CALL_RETURN { - PVOID Pointer; + GUEST_PTR Pointer; LONG_PTR Simple; }; namespace rpcrt4 { RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint, - RPC_WSTR options, RPC_WSTR *stringBinding); -RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding); + RPC_WSTR options, GUEST_PTR *stringBinding); +RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, GUEST_PTR *binding); RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR serverPrincName, ULONG authnLevel, ULONG authnSvc, RPC_AUTH_IDENTITY_HANDLE authIdentity, ULONG authzSvc, RPC_SECURITY_QOS *securityQos); -RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding); -RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string); +RPC_STATUS WINAPI RpcBindingFree(GUEST_PTR *binding); +RPC_STATUS WINAPI RpcStringFreeW(GUEST_PTR *string); +#ifndef __x86_64__ // TODO CLIENT_CALL_RETURN CDECL_NO_CONV NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...); +#endif VOID WINAPI NdrServerCall2(PRPC_MESSAGE message); } // namespace rpcrt4 diff --git a/dll/user32.cpp b/dll/user32.cpp index f134e74..1d30c1d 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -12,7 +12,7 @@ namespace user32 { constexpr uint32_t RT_STRING_ID = 6; -constexpr uintptr_t kDefaultKeyboardLayout = 0x04090409; +constexpr HKL kDefaultKeyboardLayout = 0x04090409; constexpr int UOI_FLAGS = 1; constexpr DWORD WSF_VISIBLE = 0x0001; @@ -135,15 +135,14 @@ int WINAPI MessageBoxA(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { HKL WINAPI GetKeyboardLayout(DWORD idThread) { HOST_CONTEXT_GUARD(); - DEBUG_LOG("GetKeyboardLayout(%u)\n", idThread); + DEBUG_LOG("STUB: GetKeyboardLayout(%u)\n", idThread); (void)idThread; - return reinterpret_cast(kDefaultKeyboardLayout); + return kDefaultKeyboardLayout; } HWINSTA WINAPI GetProcessWindowStation() { - DEBUG_LOG("GetProcessWindowStation()\n"); - static int kWindowStationStub; - return reinterpret_cast(&kWindowStationStub); + DEBUG_LOG("STUB: GetProcessWindowStation()\n"); + return NO_HANDLE; } BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) { @@ -173,7 +172,7 @@ BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWO HWND WINAPI GetActiveWindow() { DEBUG_LOG("GetActiveWindow()\n"); - return nullptr; + return NO_HANDLE; } } // namespace user32 diff --git a/dll/version.cpp b/dll/version.cpp index dbac1b0..7040c76 100644 --- a/dll/version.cpp +++ b/dll/version.cpp @@ -8,6 +8,7 @@ #include "modules.h" #include "resources.h" #include "strutil.h" +#include "types.h" #include #include @@ -239,7 +240,7 @@ UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwL return 1; } -static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, void **lplpBuffer, +static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, GUEST_PTR *lplpBuffer, unsigned int *puLen) { if (!pBlock) return 0; @@ -264,20 +265,20 @@ static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &sub std::string narrow = wideStringToString(reinterpret_cast(outPtr), static_cast(outLen)); std::memcpy(dest, narrow.c_str(), narrow.size() + 1); if (lplpBuffer) - *lplpBuffer = dest; + *lplpBuffer = toGuestPtr(dest); if (puLen) *puLen = static_cast(narrow.size()); return 1; } if (lplpBuffer) - *lplpBuffer = const_cast(outPtr); + *lplpBuffer = toGuestPtr(outPtr); if (puLen) *puLen = outLen; return 1; } -UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) { +UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen) { HOST_CONTEXT_GUARD(); DEBUG_LOG("VerQueryValueA(%p, %s, %p, %p)\n", pBlock, lpSubBlock ? lpSubBlock : "(null)", lplpBuffer, puLen); if (!lpSubBlock) @@ -299,7 +300,7 @@ UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dw return GetFileVersionInfoA(narrow.c_str(), dwHandle, dwLen, lpData); } -UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) { +UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen) { HOST_CONTEXT_GUARD(); if (!lpSubBlock) return 0; diff --git a/dll/version.h b/dll/version.h index ab71966..0b072c6 100644 --- a/dll/version.h +++ b/dll/version.h @@ -6,9 +6,9 @@ namespace version { UINT WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle); UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); -UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen); +UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen); UINT WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle); UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData); -UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen); +UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen); } // namespace version diff --git a/src/files.cpp b/src/files.cpp index e6a9333..41f6a45 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -1,11 +1,11 @@ #include "files.h" #include "common.h" +#include "errors.h" #include "handles.h" #include "strutil.h" #include #include -#include #include #include #include @@ -312,7 +312,7 @@ HANDLE getStdHandle(DWORD nStdHandle) { case STD_ERROR_HANDLE: return stderrHandle; default: - return (void *)0xFFFFFFFF; + return INVALID_HANDLE_VALUE; } } diff --git a/src/handles.cpp b/src/handles.cpp index 5e0ea44..f77c2ce 100644 --- a/src/handles.cpp +++ b/src/handles.cpp @@ -1,4 +1,5 @@ #include "handles.h" +#include "types.h" #include #include #include @@ -12,7 +13,7 @@ constexpr uint32_t kCompatMaxIndex = (0xFFFFu >> kHandleAlignShift) - 1; constexpr uint32_t kQuarantineLen = 64; inline uint32_t indexOf(HANDLE h) noexcept { - uint32_t v = static_cast(reinterpret_cast(h)); + uint32_t v = static_cast(h); if (v == 0 || (v & ((1U << kHandleAlignShift) - 1)) != 0) { return UINT32_MAX; } @@ -21,7 +22,7 @@ inline uint32_t indexOf(HANDLE h) noexcept { inline HANDLE makeHandle(uint32_t index) noexcept { uint32_t v = (index + 1) << kHandleAlignShift; - return reinterpret_cast(static_cast(v)); + return static_cast(v); } inline bool isPseudo(HANDLE h) noexcept { return reinterpret_cast(h) < 0; } @@ -83,7 +84,7 @@ HANDLE Handles::alloc(Pin<> obj, uint32_t grantedAccess, uint32_t flags) { } Pin<> Handles::get(HANDLE h, HandleMeta *metaOut) { - if (h == nullptr || isPseudo(h)) { + if (h == NO_HANDLE || isPseudo(h)) { return {}; // pseudo-handles have no entries } diff --git a/src/heap.cpp b/src/heap.cpp index bdc3c33..4265ab2 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -35,6 +35,7 @@ namespace { constexpr uintptr_t kLowMemoryStart = 0x00110000UL; // 1 MiB + 64 KiB +constexpr uintptr_t kHeapMax = 0x60000000UL; // 1 GiB constexpr uintptr_t kTopDownStart = 0x7F000000UL; // Just below 2GB constexpr uintptr_t kTwoGB = 0x80000000UL; constexpr std::size_t kGuestArenaSize = 512ULL * 1024ULL * 1024ULL; // 512 MiB @@ -195,7 +196,7 @@ bool overlapsExistingMapping(uintptr_t base, std::size_t length) { if (info.RegionSize == 0) { continue; } - uintptr_t mapStart = reinterpret_cast(info.BaseAddress); + uintptr_t mapStart = reinterpret_cast(fromGuestPtr(info.BaseAddress)); uintptr_t mapEnd = mapStart + static_cast(info.RegionSize); if (mapEnd <= base) { continue; @@ -214,8 +215,8 @@ void recordGuestMapping(uintptr_t base, std::size_t size, DWORD allocationProtec return; } MEMORY_BASIC_INFORMATION info{}; - info.BaseAddress = reinterpret_cast(base); - info.AllocationBase = reinterpret_cast(base); + info.BaseAddress = toGuestPtr(reinterpret_cast(base)); + info.AllocationBase = toGuestPtr(reinterpret_cast(base)); info.AllocationProtect = allocationProtect; info.RegionSize = size; info.State = state; @@ -435,7 +436,7 @@ void initializeImpl() { // Map and register guest arena (below 2GB, exclusive) ArenaRange guest; - if (mapArena(kGuestArenaSize, kLowMemoryStart, kTopDownStart, true, "wibo guest arena", guest)) { + if (mapArena(kGuestArenaSize, kLowMemoryStart, kHeapMax, true, "wibo guest arena", guest)) { bool ok = mi_manage_os_memory_ex(guest.start, guest.size, /*is_committed*/ false, /*is_pinned*/ false, @@ -910,8 +911,8 @@ VmStatus virtualQuery(const void *address, MEMORY_BASIC_INFORMATION *outInfo) { regionEnd = regionStart + pageSize; } allocLock.unlock(); - outInfo->BaseAddress = reinterpret_cast(regionStart); - outInfo->AllocationBase = nullptr; + outInfo->BaseAddress = toGuestPtr(reinterpret_cast(regionStart)); + outInfo->AllocationBase = GUEST_NULL; outInfo->AllocationProtect = 0; outInfo->RegionSize = regionEnd - regionStart; outInfo->State = MEM_FREE; @@ -961,8 +962,8 @@ VmStatus virtualQuery(const void *address, MEMORY_BASIC_INFORMATION *outInfo) { DWORD finalProtect = committed ? pageProtect : PAGE_NOACCESS; allocLock.unlock(); - outInfo->BaseAddress = reinterpret_cast(blockStart); - outInfo->AllocationBase = reinterpret_cast(region->base); + outInfo->BaseAddress = toGuestPtr(reinterpret_cast(blockStart)); + outInfo->AllocationBase = toGuestPtr(reinterpret_cast(region->base)); outInfo->AllocationProtect = allocationProtect; outInfo->RegionSize = blockEnd - blockStart; outInfo->State = committed ? MEM_COMMIT : MEM_RESERVE; @@ -1153,7 +1154,7 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS]) if (numMappings < MAX_NUM_MAPPINGS) { if (numMappings > 0) { auto &prevMapping = mappings[numMappings - 1]; - uintptr_t prevMapStart = reinterpret_cast(prevMapping.BaseAddress); + uintptr_t prevMapStart = reinterpret_cast(fromGuestPtr(prevMapping.BaseAddress)); uintptr_t prevMapEnd = prevMapStart + prevMapping.RegionSize; if (mapStart <= prevMapEnd) { // Extend the previous mapping @@ -1164,10 +1165,10 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS]) } } mappings[numMappings++] = (MEMORY_BASIC_INFORMATION){ - .BaseAddress = reinterpret_cast(mapStart), - .AllocationBase = reinterpret_cast(mapStart), + .BaseAddress = toGuestPtr(reinterpret_cast(mapStart)), + .AllocationBase = toGuestPtr(reinterpret_cast(mapStart)), .AllocationProtect = PAGE_NOACCESS, - .RegionSize = mapEnd - mapStart, + .RegionSize = static_cast(mapEnd - mapStart), .State = MEM_RESERVE, .Protect = PAGE_NOACCESS, .Type = 0, // external @@ -1225,9 +1226,9 @@ __attribute__((used)) static void wibo_heap_constructor() { g_mappings = new std::map; for (size_t i = 0; i < numMappings; ++i) { if (debug) { - fprintf(stderr, "Existing %zu: BaseAddress=%p, RegionSize=%lu\n", i, mappings[i].BaseAddress, + fprintf(stderr, "Existing %zu: BaseAddress=%x, RegionSize=%u\n", i, mappings[i].BaseAddress, mappings[i].RegionSize); } - g_mappings->emplace(reinterpret_cast(mappings[i].BaseAddress), mappings[i]); + g_mappings->emplace(reinterpret_cast(fromGuestPtr(mappings[i].BaseAddress)), mappings[i]); } } diff --git a/src/heap.h b/src/heap.h index e80da91..90eeb5b 100644 --- a/src/heap.h +++ b/src/heap.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include struct mi_heap_s; typedef struct mi_heap_s mi_heap_t; @@ -50,4 +52,100 @@ NTSTATUS ntStatusFromVmStatus(VmStatus status); bool reserveGuestStack(std::size_t stackSizeBytes, void **outStackLimit, void **outStackBase); +//-------------------- deleters -------------------- +template struct single_deleter { + void operator()(U *p) const noexcept { + if (!p) + return; + p->~U(); + wibo::heap::guestFree(static_cast(p)); + } +}; + +template struct array_deleter { + std::size_t n{}; // number of elements + void operator()(U *p) const noexcept { + if (!p) + return; + for (std::size_t i = n; i > 0; --i) + (p + (i - 1))->~U(); + wibo::heap::guestFree(static_cast(p)); + } +}; + +//-------------------- pointer alias picking T or T[] -------------------- +template struct unique_type { + using type = std::unique_ptr>; +}; +template struct unique_type { + using type = std::unique_ptr>; +}; +// template struct unique_type; // no bounded arrays (int[N]) + +template using guest_ptr = typename unique_type::type; + +//-------------------- helpers -------------------- +inline bool mul_overflows(std::size_t a, std::size_t b) { + return b != 0 && a > (std::numeric_limits::max)() / b; +} + +//-------------------- single object -------------------- +template + requires(!std::is_array_v) +guest_ptr make_guest_unique(Args &&...args) noexcept { + // Optional: insist on nothrow construction in a no-exception build + static_assert(std::is_nothrow_constructible_v, + "T must be nothrow-constructible when exceptions are disabled"); + + void *raw = wibo::heap::guestMalloc(sizeof(T)); + if (!raw) + return {}; + + // placement-new without exceptions + T *p = ::new (raw) T(std::forward(args)...); + return guest_ptr(p, single_deleter{}); +} + +//-------------------- unbounded array: default-construct -------------------- +template + requires std::is_unbounded_array_v +guest_ptr make_guest_unique(std::size_t n) noexcept { + using U = std::remove_extent_t; + static_assert(std::is_nothrow_default_constructible_v, + "U must be nothrow default-constructible when exceptions are disabled"); + + if (mul_overflows(n, sizeof(U))) + return {}; + void *raw = wibo::heap::guestMalloc(n * sizeof(U)); + if (!raw) + return {}; + U *p = static_cast(raw); + + for (std::size_t i = 0; i < n; ++i) + ::new (p + i) U(); + + return guest_ptr(p, array_deleter{n}); +} + +//-------------------- unbounded array: per-element args -------------------- +template + requires std::is_unbounded_array_v +guest_ptr make_guest_unique(std::size_t n, Args &&...args) noexcept { + using U = std::remove_extent_t; + static_assert(std::is_nothrow_constructible_v, + "U(args...) must be nothrow-constructible when exceptions are disabled"); + + if (mul_overflows(n, sizeof(U))) + return {}; + void *raw = wibo::heap::guestMalloc(n * sizeof(U)); + if (!raw) + return {}; + U *p = static_cast(raw); + + for (std::size_t i = 0; i < n; ++i) + ::new (p + i) U(std::forward(args)...); + + return guest_ptr(p, array_deleter{n}); +} + } // namespace wibo::heap diff --git a/src/loader.cpp b/src/loader.cpp index 91277c5..22356d6 100644 --- a/src/loader.cpp +++ b/src/loader.cpp @@ -86,11 +86,11 @@ struct PESectionHeader { uint32_t characteristics; }; struct PEImportDirectoryEntry { - uint32_t *importLookupTable; + uint32_t importLookupTable; uint32_t timeDateStamp; uint32_t forwarderChain; - char *name; - uint32_t *importAddressTable; + uint32_t name; + uint32_t importAddressTable; }; struct PEHintNameTableEntry { uint16_t hint; @@ -254,7 +254,9 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) { allocStatus = wibo::heap::virtualAlloc( &allocatedBase, &allocationSize, MEM_RESERVE | MEM_COMMIT, initialProtect, MEM_IMAGE); } - if (allocStatus != wibo::heap::VmStatus::Success) { + if (allocStatus == wibo::heap::VmStatus::Success) { + DEBUG_LOG("loadPE: mapped image at %p\n", allocatedBase); + } else { DEBUG_LOG("Image mapping failed (status=%u)\n", static_cast(allocStatus)); imageBase = nullptr; return false; @@ -425,10 +427,10 @@ bool wibo::Executable::resolveImports() { } while (dir->name) { - char *dllName = fromRVA(dir->name); + char *dllName = fromRVA(dir->name); DEBUG_LOG("DLL Name: %s\n", dllName); - uint32_t *lookupTable = fromRVA(dir->importLookupTable); - uint32_t *addressTable = fromRVA(dir->importAddressTable); + uint32_t *lookupTable = fromRVA(dir->importLookupTable); + uint32_t *addressTable = fromRVA(dir->importAddressTable); ModuleInfo *module = loadModule(dllName); if (!module && kernel32::getLastError() != ERROR_MOD_NOT_FOUND) { diff --git a/src/macros.S b/src/macros.S new file mode 100644 index 0000000..c4c60bc --- /dev/null +++ b/src/macros.S @@ -0,0 +1,40 @@ +.intel_syntax noprefix + +.equ TEB_SELF, 0x18 # Self +.equ TEB_FS_SEL, 0xf98 # CurrentFsSelector +.equ TEB_GS_SEL, 0xf9a # CurrentGsSelector + +#ifdef __i386__ + +.equ TEB_SP, 0xf9c # CurrentStackPointer + +#endif // __i386__ + +#ifdef __x86_64__ + +.equ TEB_SP, 0xfa0 # CurrentStackPointer +.equ TEB_FSBASE, 0xfa8 # CurrentFsBase + +.equ CS_32, 0x23 # 32-bit code segment (Linux) +.equ CS_64, 0x33 # 64-bit code segment (Linux) +.equ DS_32, 0x2b # 32-bit data segment (Linux) + +.macro LJMP32 + jmp fword ptr [rip] # far jump into 32-bit code + .long 1f # 32-bit code offset + .word CS_32 # 32-bit code segment (Linux) +.code32 +1: + endbr32 +.endm + +.macro LJMP64 + push CS_64 # 64-bit code segment (Linux) + push offset 1f # 64-bit code offset + retf # far jump into 64-bit code +.code64 +1: + endbr64 +.endm + +#endif // __x86_64__ diff --git a/src/main.cpp b/src/main.cpp index fc1ff64..9e2289c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,4 @@ #include "common.h" -#include "context.h" #include "entry.h" #include "entry_trampolines.h" #include "files.h" @@ -8,9 +7,15 @@ #include "processes.h" #include "strutil.h" #include "tls.h" +#include "types.h" #include "version_info.h" +#ifdef __x86_64__ +#include "setup.h" +#endif + #include +#include #include #include #include @@ -53,13 +58,13 @@ void wibo::debug_log(const char *fmt, ...) { } TEB *wibo::allocateTib() { - auto *newTib = static_cast(std::calloc(1, sizeof(TEB))); + auto *newTib = static_cast(wibo::heap::guestCalloc(1, sizeof(TEB))); if (!newTib) { return nullptr; } tls::initializeTib(newTib); - newTib->Tib.Self = &newTib->Tib; - newTib->Peb = processPeb; + newTib->Tib.Self = toGuestPtr(newTib); + newTib->Peb = toGuestPtr(processPeb); return newTib; } @@ -82,8 +87,8 @@ void wibo::initializeTibStackInfo(TEB *tibPtr) { fprintf(stderr, "Failed to reserve guest stack\n"); std::abort(); } - tibPtr->Tib.StackLimit = guestLimit; - tibPtr->Tib.StackBase = guestBase; + tibPtr->Tib.StackLimit = toGuestPtr(guestLimit); + tibPtr->Tib.StackBase = toGuestPtr(guestBase); tibPtr->CurrentStackPointer = guestBase; DEBUG_LOG("initializeTibStackInfo: using guest stack base=%p limit=%p\n", tibPtr->Tib.StackBase, tibPtr->Tib.StackLimit); @@ -94,10 +99,18 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) { return false; } + currentThreadTeb = tibPtr; +#ifdef __x86_64__ + tibEntryNumber = x86_64_thread_setup(tibEntryNumber, tibPtr); + if (tibEntryNumber == -1 || tibPtr->CurrentFsSelector == 0) { + perror("x86_64_thread_setup failed"); + return false; + } +#else struct user_desc desc; std::memset(&desc, 0, sizeof(desc)); desc.entry_number = tibEntryNumber; - desc.base_addr = reinterpret_cast(tibPtr); + desc.base_addr = reinterpret_cast(tibPtr); desc.limit = static_cast(sizeof(TEB) - 1); desc.seg_32bit = 1; desc.contents = 0; @@ -118,13 +131,10 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) { tibPtr->CurrentFsSelector = static_cast((desc.entry_number << 3) | 3); tibPtr->CurrentGsSelector = 0; - currentThreadTeb = tibPtr; +#endif return true; } -// Make this global to ease debugging -TEB tib; - static std::string getExeName(const char *argv0) { std::filesystem::path exePath(argv0 ? argv0 : "wibo"); return exePath.filename().string(); @@ -347,16 +357,18 @@ int main(int argc, char **argv) { files::init(); + // Create PEB + PEB *peb = reinterpret_cast(wibo::heap::guestCalloc(1, sizeof(PEB))); + peb->ProcessParameters = toGuestPtr(wibo::heap::guestCalloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS))); + // Create TIB - memset(&tib, 0, sizeof(tib)); - wibo::tls::initializeTib(&tib); - tib.Tib.Self = &tib.Tib; - tib.Peb = static_cast(calloc(1, sizeof(PEB))); - tib.Peb->ProcessParameters = - static_cast(calloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS))); - wibo::processPeb = tib.Peb; - wibo::initializeTibStackInfo(&tib); - if (!wibo::installTibForCurrentThread(&tib)) { + TEB *tib = reinterpret_cast(wibo::heap::guestCalloc(1, sizeof(TEB))); + wibo::tls::initializeTib(tib); + tib->Tib.Self = toGuestPtr(tib); + tib->Peb = toGuestPtr(peb); + wibo::processPeb = peb; + wibo::initializeTibStackInfo(tib); + if (!wibo::installTibForCurrentThread(tib)) { fprintf(stderr, "Failed to install TIB for main thread\n"); return 1; } @@ -506,7 +518,7 @@ int main(int argc, char **argv) { call_EntryProc(entryPoint); DEBUG_LOG("We came back\n"); wibo::shutdownModuleRegistry(); - wibo::tls::cleanupTib(&tib); + wibo::tls::cleanupTib(tib); return 1; } diff --git a/src/modules.cpp b/src/modules.cpp index df54342..3f133cd 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -6,9 +6,11 @@ #include "errors.h" #include "files.h" #include "heap.h" +#include "kernel32/errhandlingapi.h" #include "kernel32/internal.h" #include "strutil.h" #include "tls.h" +#include "types.h" #include #include @@ -38,8 +40,65 @@ extern const wibo::ModuleStub lib_user32; extern const wibo::ModuleStub lib_vcruntime; extern const wibo::ModuleStub lib_version; +// setup.S +template void stubThunk(); + +/* + apiset api-ms-win-core-crt-l1-1-0 = msvcrt.dll + apiset api-ms-win-core-crt-l2-1-0 = msvcrt.dll + apiset api-ms-win-crt-conio-l1-1-0 = msvcrt.dll + apiset api-ms-win-crt-convert-l1-1-0 = msvcrt.dll + apiset api-ms-win-crt-environment-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-filesystem-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-heap-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-locale-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-math-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-multibyte-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-private-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-process-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-runtime-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-stdio-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-string-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-time-l1-1-0 = ucrtbase.dll + apiset api-ms-win-crt-utility-l1-1-0 = ucrtbase.dll +*/ + namespace { +const std::array, 17> kApiSet = { + std::pair{"api-ms-win-core-crt-l1-1-0.dll", "msvcrt.dll"}, + std::pair{"api-ms-win-core-crt-l2-1-0.dll", "msvcrt.dll"}, + std::pair{"api-ms-win-crt-conio-l1-1-0.dll", "msvcrt.dll"}, + std::pair{"api-ms-win-crt-convert-l1-1-0.dll", "msvcrt.dll"}, + std::pair{"api-ms-win-crt-environment-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-filesystem-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-heap-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-locale-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-math-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-multibyte-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-private-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-process-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-runtime-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-stdio-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-string-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-time-l1-1-0.dll", "ucrtbase.dll"}, + std::pair{"api-ms-win-crt-utility-l1-1-0.dll", "ucrtbase.dll"}, +}; + +const std::array, 11> kFallbacks = { + std::pair{"ucrtbase.dll", "msvcrt.dll"}, + std::pair{"msvcrt40.dll", "msvcrt.dll"}, + std::pair{"msvcr70.dll", "msvcrt.dll"}, + std::pair{"msvcr71.dll", "msvcrt.dll"}, + std::pair{"msvcr80.dll", "msvcrt.dll"}, + std::pair{"msvcr90.dll", "msvcrt.dll"}, + std::pair{"msvcr100.dll", "msvcrt.dll"}, + std::pair{"msvcr110.dll", "msvcrt.dll"}, + std::pair{"msvcr120.dll", "msvcrt.dll"}, + std::pair{"msvcr130.dll", "msvcrt.dll"}, + std::pair{"msvcr140.dll", "msvcrt.dll"}, +}; + constexpr DWORD DLL_PROCESS_DETACH = 0; constexpr DWORD DLL_PROCESS_ATTACH = 1; constexpr DWORD DLL_THREAD_ATTACH = 2; @@ -69,6 +128,8 @@ size_t stubIndex = 0; std::array stubDlls; std::array stubFuncNames; std::unordered_map stubCache; +std::unordered_map> g_modules; +HANDLE g_nextStubHandle = 1; std::string makeStubKey(const char *dllName, const char *funcName) { std::string key; @@ -85,11 +146,6 @@ std::string makeStubKey(const char *dllName, const char *funcName) { return key; } -template void stubThunk() { - // Call the appropriate entry trampoline - thunk_entry_stubBase(Index); -} - template constexpr std::array makeStubTable(std::index_sequence) { return {{stubThunk...}}; @@ -162,8 +218,11 @@ LockedRegistry registry() { if (!reg.initialized) { reg.initialized = true; const wibo::ModuleStub *builtins[] = { - &lib_advapi32, &lib_bcrypt, &lib_crt, &lib_kernel32, &lib_lmgr, &lib_mscoree, &lib_msvcrt, - &lib_ntdll, &lib_ole32, &lib_rpcrt4, &lib_user32, &lib_vcruntime, &lib_version, nullptr, + &lib_advapi32, &lib_bcrypt, /*&lib_crt,*/ &lib_kernel32, + &lib_lmgr, &lib_mscoree, /*&lib_msvcrt,*/ + &lib_ntdll, &lib_ole32, &lib_rpcrt4, + &lib_user32, &lib_vcruntime, &lib_version, + nullptr, }; for (const wibo::ModuleStub **module = builtins; *module; ++module) { registerBuiltinModule(reg, *module); @@ -204,11 +263,11 @@ struct ParsedModuleName { bool endsWithDot = false; }; -ParsedModuleName parseModuleName(const std::string &name) { +ParsedModuleName parseModuleName(std::string_view name) { ParsedModuleName parsed; parsed.original = name; parsed.base = name; - std::string sanitized = name; + std::string sanitized{name}; std::replace(sanitized.begin(), sanitized.end(), '/', '\\'); auto sep = sanitized.find_last_of('\\'); if (sep != std::string::npos) { @@ -282,19 +341,20 @@ bool allocateModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) { if (info.threadAllocations.find(tib) != info.threadAllocations.end()) { return true; } - void *block = nullptr; + GUEST_PTR block = GUEST_NULL; const size_t allocationSize = info.allocationSize; if (allocationSize > 0) { - block = wibo::heap::guestMalloc(allocationSize); - if (!block) { + void *ptr = wibo::heap::guestMalloc(allocationSize); + if (!ptr) { DEBUG_LOG(" allocateModuleTlsForThread: failed to allocate %zu bytes for %s\n", allocationSize, module.originalName.c_str()); return false; } - std::memset(block, 0, allocationSize); + std::memset(ptr, 0, allocationSize); if (info.templateData && info.templateSize > 0) { - std::memcpy(block, info.templateData, info.templateSize); + std::memcpy(ptr, info.templateData, info.templateSize); } + block = toGuestPtr(ptr); } info.threadAllocations.emplace(tib, block); if (!wibo::tls::setValue(tib, info.index, block)) { @@ -322,10 +382,10 @@ void freeModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) { if (it == info.threadAllocations.end()) { return; } - void *block = it->second; + GUEST_PTR block = it->second; info.threadAllocations.erase(it); if (wibo::tls::getValue(tib, info.index) == block) { - if (!wibo::tls::setValue(tib, info.index, nullptr)) { + if (!wibo::tls::setValue(tib, info.index, GUEST_NULL)) { DEBUG_LOG(" freeModuleTlsForThread: failed to clear TLS pointer for %s (index %u)\n", module.originalName.c_str(), info.index); } @@ -334,7 +394,7 @@ void freeModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) { wibo::tls::clearModulePointer(tib, info.loaderIndex); } if (block) { - std::free(block); + wibo::heap::guestFree(fromGuestPtr(block)); } } @@ -346,7 +406,7 @@ void runModuleTlsCallbacks(wibo::ModuleInfo &module, DWORD reason) { if (!callback) { continue; } - call_PIMAGE_TLS_CALLBACK(callback, module.handle, reason, nullptr); + call_PIMAGE_TLS_CALLBACK(callback, reinterpret_cast(module.handle), reason, nullptr); } } @@ -502,7 +562,9 @@ void registerBuiltinModule(ModuleRegistry ®, const wibo::ModuleStub *module) return; } wibo::ModulePtr entry = std::make_shared(); - entry->handle = entry.get(); + HANDLE handle = g_nextStubHandle++; + g_modules[handle] = entry; + entry->handle = handle; entry->moduleStub = module; entry->refCount = UINT_MAX; entry->originalName = module->names[0] ? module->names[0] : ""; @@ -570,12 +632,10 @@ BOOL callDllMain(wibo::ModuleInfo &info, DWORD reason, LPVOID reserved) { } } - DEBUG_LOG(" callDllMain: invoking DllMain(%p, %u, %p) for %s\n", - reinterpret_cast(info.executable->imageBase), callReason, callReserved, - info.normalizedName.c_str()); + DEBUG_LOG(" callDllMain: invoking DllMain(%p, %u, %p) for %s\n", toGuestPtr(info.executable->imageBase), + callReason, callReserved, info.normalizedName.c_str()); - BOOL result = - call_DllEntryProc(dllMain, reinterpret_cast(info.executable->imageBase), callReason, callReserved); + BOOL result = call_DllEntryProc(dllMain, toGuestPtr(info.executable->imageBase), callReason, callReserved); DEBUG_LOG(" callDllMain: %s DllMain returned %d\n", info.normalizedName.c_str(), result); return result; }; @@ -739,7 +799,7 @@ ModuleInfo *registerProcessModule(std::unique_ptr executable, std::f std::string normalizedName = normalizedBaseKey(parsed); ModulePtr info = std::make_unique(); - info->handle = executable->imageBase; // Use image base as handle for main module + info->handle = toGuestPtr(executable->imageBase); // Use image base as handle for main module info->moduleStub = nullptr; info->originalName = std::move(originalName); info->normalizedName = std::move(normalizedName); @@ -825,7 +885,7 @@ ModuleInfo *moduleInfoFromHandle(HMODULE module) { if (info->handle == module) { return info; } - if (info->executable && info->executable->imageBase == module) { + if (info->executable && info->executable->imageBase == reinterpret_cast(module)) { return info; } } @@ -883,7 +943,7 @@ bool initializeModuleTls(ModuleInfo &module) { info.callbacks.clear(); uintptr_t callbacksArray = resolveModuleAddress(exec, tlsDirectory->AddressOfCallBacks); if (callbacksArray) { - auto callbackPtr = reinterpret_cast(callbacksArray); + auto callbackPtr = reinterpret_cast(callbacksArray); while (callbackPtr && *callbackPtr) { info.callbacks.push_back(reinterpret_cast(resolveModuleAddress(exec, *callbackPtr))); ++callbackPtr; @@ -937,13 +997,13 @@ bool initializeModuleTls(ModuleInfo &module) { if (!ctx.success) { for (auto &[thread, block] : info.threadAllocations) { if (block) { - std::free(block); + wibo::heap::guestFree(fromGuestPtr(block)); } if (info.loaderIndex != tls::kInvalidTlsIndex) { wibo::tls::clearModulePointer(thread, info.loaderIndex); } if (wibo::tls::getValue(thread, info.index) == block) { - wibo::tls::setValue(thread, info.index, nullptr); + wibo::tls::setValue(thread, info.index, GUEST_NULL); } } info.threadAllocations.clear(); @@ -971,14 +1031,14 @@ void releaseModuleTls(ModuleInfo &module) { for (auto &[tib, block] : info.threadAllocations) { if (tib) { if (wibo::tls::getValue(tib, info.index) == block) { - wibo::tls::setValue(tib, info.index, nullptr); + wibo::tls::setValue(tib, info.index, GUEST_NULL); } if (info.loaderIndex != tls::kInvalidTlsIndex) { wibo::tls::clearModulePointer(tib, info.loaderIndex); } } if (block) { - std::free(block); + wibo::heap::guestFree(fromGuestPtr(block)); } } info.threadAllocations.clear(); @@ -1068,18 +1128,9 @@ ModuleInfo *findLoadedModule(const char *name) { return info; } -ModuleInfo *loadModule(const char *dllName) { - if (!dllName || *dllName == '\0') { - kernel32::setLastError(ERROR_INVALID_PARAMETER); - return nullptr; - } - std::string requested(dllName); - DEBUG_LOG("loadModule(%s)\n", requested.c_str()); - +static ModuleInfo *loadModuleInternal(const std::string &dllName) { auto reg = registry(); - - ParsedModuleName parsed = parseModuleName(requested); - + ParsedModuleName parsed = parseModuleName(dllName); DWORD diskError = ERROR_SUCCESS; auto tryLoadExternal = [&](const std::filesystem::path &path) -> ModuleInfo * { @@ -1090,7 +1141,7 @@ ModuleInfo *loadModule(const char *dllName) { if (info->refCount != UINT_MAX) { info->refCount++; } - registerExternalModuleAliases(*reg, requested, files::canonicalPath(path), info); + registerExternalModuleAliases(*reg, dllName, files::canonicalPath(path), info); return info; } reg.lock.unlock(); @@ -1115,9 +1166,11 @@ ModuleInfo *loadModule(const char *dllName) { fclose(file); ModulePtr info = std::make_unique(); - info->handle = info.get(); + HANDLE handle = g_nextStubHandle++; + g_modules[handle] = info; + info->handle = handle; info->moduleStub = nullptr; - info->originalName = requested; + info->originalName = dllName; info->normalizedName = normalizedBaseKey(parsed); info->resolvedPath = files::canonicalPath(path); info->executable = std::move(executable); @@ -1126,7 +1179,7 @@ ModuleInfo *loadModule(const char *dllName) { reg.lock.lock(); ModuleInfo *raw = info.get(); reg->modulesByKey[key] = std::move(info); - registerExternalModuleAliases(*reg, requested, raw->resolvedPath, raw); + registerExternalModuleAliases(*reg, dllName, raw->resolvedPath, raw); reg.lock.unlock(); ensureExportsInitialized(*raw); if (!raw->executable->resolveImports()) { @@ -1165,7 +1218,7 @@ ModuleInfo *loadModule(const char *dllName) { }; auto resolveAndLoadExternal = [&]() -> ModuleInfo * { - auto resolvedPath = resolveModuleOnDisk(*reg, requested, false); + auto resolvedPath = resolveModuleOnDisk(*reg, dllName, false); if (!resolvedPath) { DEBUG_LOG(" module not found on disk\n"); diskError = ERROR_MOD_NOT_FOUND; @@ -1177,7 +1230,7 @@ ModuleInfo *loadModule(const char *dllName) { std::string alias = normalizedBaseKey(parsed); ModuleInfo *existing = findByAlias(*reg, alias); if (!existing) { - existing = findByAlias(*reg, normalizeAlias(requested)); + existing = findByAlias(*reg, normalizeAlias(dllName)); } if (existing) { DEBUG_LOG(" found existing module alias %s (builtin=%d)\n", alias.c_str(), existing->moduleStub != nullptr); @@ -1188,10 +1241,10 @@ ModuleInfo *loadModule(const char *dllName) { DEBUG_LOG(" returning existing external module %s\n", existing->originalName.c_str()); return existing; } - bool pinned = reg->pinnedModules.count(existing) != 0; + bool pinned = reg->pinnedModules.contains(existing); if (!pinned) { if (ModuleInfo *external = resolveAndLoadExternal()) { - DEBUG_LOG(" replaced builtin module %s with external copy\n", requested.c_str()); + DEBUG_LOG(" replaced builtin module %s with external copy\n", dllName.c_str()); return external; } else if (diskError != ERROR_MOD_NOT_FOUND) { kernel32::setLastError(diskError); @@ -1203,7 +1256,7 @@ ModuleInfo *loadModule(const char *dllName) { } if (ModuleInfo *external = resolveAndLoadExternal()) { - DEBUG_LOG(" loaded external module %s\n", requested.c_str()); + DEBUG_LOG(" loaded external module %s\n", dllName.c_str()); return external; } else if (diskError != ERROR_MOD_NOT_FOUND) { kernel32::setLastError(diskError); @@ -1217,7 +1270,7 @@ ModuleInfo *loadModule(const char *dllName) { builtin = builtinIt->second; } if (!builtin) { - builtinIt = reg->builtinAliasMap.find(normalizeAlias(requested)); + builtinIt = reg->builtinAliasMap.find(normalizeAlias(dllName)); if (builtinIt != reg->builtinAliasMap.end()) { builtin = builtinIt->second; } @@ -1231,6 +1284,46 @@ ModuleInfo *loadModule(const char *dllName) { return nullptr; } +ModuleInfo *loadModule(const char* dllName) { + if (!dllName || *dllName == '\0') { + kernel32::setLastError(ERROR_INVALID_PARAMETER); + return nullptr; + } + DEBUG_LOG("loadModule(%s)\n", dllName); + std::string_view requested{dllName}; + + const auto parsed = parseModuleName(requested); + std::string normalized = normalizedBaseKey(parsed); + + for (auto& [alias, module] : kApiSet) { + if (alias == normalized) { + DEBUG_LOG(" resolved api set %s -> %s\n", alias.data(), module.data()); + requested = module; + normalized = module; + break; + } + } + + DWORD lastError = kernel32::getLastError(); + if (auto* info = loadModuleInternal(std::string{requested})) { + return info; + } + if (kernel32::getLastError() != ERROR_MOD_NOT_FOUND) { + return nullptr; + } + + kernel32::setLastError(lastError); + for (auto& [module, fallback] : kFallbacks) { + if (module == normalized) { + DEBUG_LOG(" trying fallback %s -> %s\n", module.data(), fallback.data()); + return loadModuleInternal(std::string{fallback}); + } + } + + kernel32::setLastError(ERROR_MOD_NOT_FOUND); + return nullptr; +} + void freeModule(ModuleInfo *info) { auto reg = registry(); if (!info || info->refCount == UINT_MAX) { diff --git a/src/modules.h b/src/modules.h index 51a7ef9..fae0290 100644 --- a/src/modules.h +++ b/src/modules.h @@ -4,6 +4,7 @@ #include "entry.h" #include "msvcrt.h" #include "tls.h" +#include "types.h" #include #include @@ -39,8 +40,7 @@ class Executable { bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional language, ResourceLocation &out) const; - template T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); } - template T *fromRVA(T *rva) const { return fromRVA((uintptr_t)rva); } + template T *fromRVA(uint32_t rva) const { return (T *)(rva + (uint8_t *)imageBase); } void *imageBase = nullptr; size_t imageSize = 0; @@ -77,7 +77,7 @@ struct ModuleTlsInfo { uint32_t characteristics = 0; size_t allocationSize = 0; std::vector callbacks; - std::unordered_map threadAllocations; + std::unordered_map threadAllocations; }; struct ModuleInfo { @@ -140,8 +140,8 @@ ModuleInfo *moduleInfoFromAddress(void *addr); * otherwise it will be a pointer to a `wibo::ModuleInfo`. */ inline bool isMainModule(HMODULE hModule) { - return hModule == nullptr || hModule == reinterpret_cast(mainModule) || - (mainModule && mainModule->executable && hModule == mainModule->executable->imageBase); + return hModule == NO_HANDLE || (mainModule && mainModule->executable && + reinterpret_cast(hModule) == mainModule->executable->imageBase); } } // namespace wibo diff --git a/src/setup.S b/src/setup.S new file mode 100644 index 0000000..c98ee13 --- /dev/null +++ b/src/setup.S @@ -0,0 +1,74 @@ +#include "macros.S" +.section .note.GNU-stack, "", @progbits +.text + +#ifdef __x86_64__ + +# int x86_64_thread_setup(int entry_number, void *teb) +.globl x86_64_thread_setup +.type x86_64_thread_setup, @function +x86_64_thread_setup: + push rbx # save rbx + mov r8, rsp # save host stack + rdfsbase r9 # read host FS base + mov rdx, qword ptr [rsi+TEB_SP] # fetch guest stack + LJMP32 # far jump into 32-bit code + mov ax, 0x2b # user data segment (Linux) + mov ds, ax # setup data segment + mov es, ax # setup extra segment + mov esp, edx # switch to guest stack + sub esp, 0x10 # sizeof(user_desc) + mov dword ptr [esp], edi # entry_number (arg 0) + mov dword ptr [esp+4], esi # base_addr (arg 1) + mov dword ptr [esp+8], 0xffff # limit + mov dword ptr [esp+12], 0x41 # seg_32bit | usable + mov ebx, esp # &user_desc + mov eax, 0xf3 # SYS_set_thread_area + int 0x80 # syscall + test eax, eax # check for error + jnz 1f # skip selector setup + mov eax, dword ptr [esp] # entry_number + cmp eax, -1 # check for invalid entry_number + jz 2f # skip selector setup + lea ebx, [eax*8+3] # create selector + mov fs, bx # setup fs segment + mov word ptr [esi+TEB_FS_SEL], bx # save selector + jmp 2f # skip error handling +1: + mov eax, -1 # return -1 +2: + add esp, 0x10 # cleanup stack + LJMP64 # far jump into 64-bit code + cdqe # sign-extend eax to rax + mov rsp, r8 # switch to host stack + wrfsbase r9 # restore host FS base + pop rbx # restore rbx + ret +.size x86_64_thread_setup, .-x86_64_thread_setup + +#endif // __x86_64__ + +.altmacro +.code32 + +.macro stubThunkX number +#ifdef __x86_64__ +.globl _Z9stubThunkILm\()\number\()EEvv +.type _Z9stubThunkILm\()\number\()EEvv, @function +_Z9stubThunkILm\()\number\()EEvv: +#else +.globl _Z9stubThunkILj\()\number\()EEvv +.type _Z9stubThunkILj\()\number\()EEvv, @function +_Z9stubThunkILj\()\number\()EEvv: +#endif + pop eax + push \number + push eax + jmp thunk_entry_stubBase +.endm + +.set i, 0 +.rept 256 + stubThunkX %i + .set i, i+1 +.endr diff --git a/src/setup.h b/src/setup.h new file mode 100644 index 0000000..1f926d1 --- /dev/null +++ b/src/setup.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __x86_64__ +int x86_64_thread_setup(int entry_number, void *teb); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/src/tls.cpp b/src/tls.cpp index 131ed9b..67246f3 100644 --- a/src/tls.cpp +++ b/src/tls.cpp @@ -1,5 +1,7 @@ #include "tls.h" #include "common.h" +#include "heap.h" +#include "types.h" #include #include @@ -20,7 +22,7 @@ size_t g_expansionCapacity = 0; struct TlsArray { size_t capacity; - void *slots[]; + GUEST_PTR slots[]; }; std::unordered_map g_moduleArrays; @@ -31,8 +33,8 @@ TlsArray *allocateTlsArray(size_t capacity) { if (capacity == 0 || capacity > kMaxExpansionSlots) { return nullptr; } - const size_t bytes = sizeof(TlsArray) + capacity * sizeof(void *); - auto *arr = static_cast(std::calloc(1, bytes)); + const size_t bytes = sizeof(TlsArray) + capacity * sizeof(GUEST_PTR); + auto *arr = static_cast(wibo::heap::guestCalloc(1, bytes)); if (!arr) { return nullptr; } @@ -40,7 +42,7 @@ TlsArray *allocateTlsArray(size_t capacity) { return arr; } -inline TlsArray *arrayFromSlots(void *slots) { +inline TlsArray *arrayFromSlots(GUEST_PTR slots) { return slots ? reinterpret_cast(reinterpret_cast(slots) - offsetof(TlsArray, slots)) : nullptr; } @@ -56,7 +58,7 @@ void setExpansionArray(TEB *tib, TlsArray *arr) { if (!tib) { return; } - tib->TlsExpansionSlots = arr ? arr->slots : nullptr; + tib->TlsExpansionSlots = arr ? toGuestPtr(arr->slots) : GUEST_NULL; } size_t chooseCapacity(size_t current, size_t required) { @@ -202,7 +204,7 @@ bool ensureModuleArrayCapacityLocked(size_t required) { } for (auto &entry : pending) { g_moduleArrays[entry.tib] = entry.newArray; - entry.tib->ThreadLocalStoragePointer = entry.newArray->slots; + entry.tib->ThreadLocalStoragePointer = toGuestPtr(entry.newArray->slots); if (entry.oldArray) { queueOldModuleArray(entry.tib, entry.oldArray); } @@ -214,7 +216,7 @@ bool ensureModuleArrayCapacityLocked(size_t required) { void zeroSlotForAllTibs(size_t index) { if (index < kTlsSlotCount) { for (TEB *tib : g_activeTibs) { - tib->TlsSlots[index] = nullptr; + tib->TlsSlots[index] = GUEST_NULL; } return; } @@ -224,7 +226,7 @@ void zeroSlotForAllTibs(size_t index) { if (!arr || expansionIndex >= arr->capacity) { continue; } - arr->slots[expansionIndex] = nullptr; + arr->slots[expansionIndex] = GUEST_NULL; } } @@ -272,7 +274,7 @@ void cleanupTib(TEB *tib) { } g_moduleGarbage.erase(garbageIt); } - tib->ThreadLocalStoragePointer = nullptr; + tib->ThreadLocalStoragePointer = GUEST_NULL; auto it = std::find(g_activeTibs.begin(), g_activeTibs.end(), tib); if (it != g_activeTibs.end()) { g_activeTibs.erase(it); @@ -316,9 +318,9 @@ bool isSlotAllocated(DWORD index) { return index < wibo::tls::kTlsMaxSlotCount && g_slotUsed[index]; } -void *getValue(TEB *tib, DWORD index) { +GUEST_PTR getValue(TEB *tib, DWORD index) { if (!tib || index >= static_cast(wibo::tls::kTlsMaxSlotCount)) { - return nullptr; + return GUEST_NULL; } if (index < static_cast(kTlsSlotCount)) { return tib->TlsSlots[index]; @@ -326,16 +328,16 @@ void *getValue(TEB *tib, DWORD index) { std::lock_guard lock(g_tlsMutex); auto *arr = getExpansionArray(tib); if (!arr) { - return nullptr; + return GUEST_NULL; } size_t expansionIndex = static_cast(index) - kTlsSlotCount; if (expansionIndex >= arr->capacity) { - return nullptr; + return GUEST_NULL; } return arr->slots[expansionIndex]; } -bool setValue(TEB *tib, DWORD index, void *value) { +bool setValue(TEB *tib, DWORD index, GUEST_PTR value) { if (!tib || index >= static_cast(wibo::tls::kTlsMaxSlotCount)) { return false; } @@ -357,9 +359,9 @@ bool setValue(TEB *tib, DWORD index, void *value) { return true; } -void *getValue(DWORD index) { return getValue(currentThreadTeb, index); } +GUEST_PTR getValue(DWORD index) { return getValue(currentThreadTeb, index); } -bool setValue(DWORD index, void *value) { return setValue(currentThreadTeb, index, value); } +bool setValue(DWORD index, GUEST_PTR value) { return setValue(currentThreadTeb, index, value); } void forEachTib(void (*callback)(TEB *, void *), void *context) { if (!callback) { @@ -380,7 +382,7 @@ bool ensureModulePointerCapacity(size_t capacity) { return ensureModuleArrayCapacityLocked(capacity); } -bool setModulePointer(TEB *tib, size_t index, void *value) { +bool setModulePointer(TEB *tib, size_t index, GUEST_PTR value) { if (!tib) { return false; } @@ -393,7 +395,7 @@ bool setModulePointer(TEB *tib, size_t index, void *value) { return false; } array->slots[index] = value; - tib->ThreadLocalStoragePointer = array->slots; + tib->ThreadLocalStoragePointer = toGuestPtr(array->slots); return true; } @@ -406,7 +408,7 @@ void clearModulePointer(TEB *tib, size_t index) { if (!array || index >= array->capacity) { return; } - array->slots[index] = nullptr; + array->slots[index] = GUEST_NULL; } } // namespace wibo::tls diff --git a/src/tls.h b/src/tls.h index 2b0479f..5e995f7 100644 --- a/src/tls.h +++ b/src/tls.h @@ -13,17 +13,17 @@ void cleanupTib(TEB *tib); void forEachTib(void (*callback)(TEB *, void *), void *context); bool ensureModulePointerCapacity(size_t capacity); -bool setModulePointer(TEB *tib, size_t index, void *value); +bool setModulePointer(TEB *tib, size_t index, GUEST_PTR value); void clearModulePointer(TEB *tib, size_t index); DWORD reserveSlot(); bool releaseSlot(DWORD index); bool isSlotAllocated(DWORD index); -void *getValue(TEB *tib, DWORD index); -bool setValue(TEB *tib, DWORD index, void *value); +GUEST_PTR getValue(TEB *tib, DWORD index); +bool setValue(TEB *tib, DWORD index, GUEST_PTR value); -void *getValue(DWORD index); -bool setValue(DWORD index, void *value); +GUEST_PTR getValue(DWORD index); +bool setValue(DWORD index, GUEST_PTR value); } // namespace wibo::tls diff --git a/src/types.h b/src/types.h index d5e6bd5..d9e0343 100644 --- a/src/types.h +++ b/src/types.h @@ -4,11 +4,6 @@ #define va_list __builtin_va_list #endif -// On Windows, the incoming stack is aligned to a 4 byte boundary. -// force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment. -#define WIN_ENTRY __attribute__((cdecl, force_align_arg_pointer)) -#define WIN_FUNC __attribute__((stdcall, force_align_arg_pointer)) - // Annotation macros for code generation #ifdef WIBO_CODEGEN #define WIBO_ANNOTATE(x) __attribute__((annotate(x))) @@ -32,19 +27,41 @@ #define _CC_STDCALL WIBO_ANNOTATE("CC:stdcall") // Instructs codegen to convert between calling conventions +#ifdef __x86_64__ +#define WINAPI _CC_STDCALL +#define CDECL _CC_CDECL +#define CDECL_NO_CONV _CC_CDECL __attribute__((force_align_arg_pointer)) +#else #define WINAPI _CC_STDCALL __attribute__((fastcall)) #define CDECL _CC_CDECL __attribute__((fastcall)) #define CDECL_NO_CONV _CC_CDECL __attribute__((cdecl, force_align_arg_pointer)) +#endif // Used for host-to-guest calls #define GUEST_STDCALL __attribute__((stdcall)) +typedef unsigned int GUEST_PTR; +constexpr GUEST_PTR GUEST_NULL = 0; + +#ifdef __x86_64__ +inline GUEST_PTR toGuestPtr(const void *addr) { + unsigned long long addr64 = reinterpret_cast(addr); + if (addr64 > 0xFFFFFFFF) + __builtin_unreachable(); + return static_cast(addr64); +} +inline void *fromGuestPtr(GUEST_PTR addr) { return reinterpret_cast(addr); } +#else +inline GUEST_PTR toGuestPtr(const void *addr) { return static_cast(reinterpret_cast(addr)); } +inline void *fromGuestPtr(GUEST_PTR addr) { return reinterpret_cast(addr); } +#endif + using VOID = void; -using HANDLE = VOID *; -using HMODULE = VOID *; -using HGLOBAL = HANDLE; -using HLOCAL = HANDLE; -using HRSRC = HANDLE; +using HANDLE = int; +using HMODULE = HANDLE; +using HGLOBAL = GUEST_PTR; +using HLOCAL = GUEST_PTR; +using HRSRC = GUEST_PTR; using HINSTANCE = HANDLE; using LPHANDLE = HANDLE *; using PHANDLE = HANDLE *; @@ -66,12 +83,9 @@ using ULONG = unsigned int; using PULONG = ULONG *; using LONGLONG = long long; using ULONGLONG = unsigned long long; -using LONG_PTR = long; -static_assert(sizeof(LONG_PTR) == sizeof(void *), "LONG_PTR must be pointer-sized"); -using ULONG_PTR = unsigned long; -static_assert(sizeof(ULONG_PTR) == sizeof(void *), "ULONG_PTR must be pointer-sized"); -using UINT_PTR = unsigned long; -static_assert(sizeof(UINT_PTR) == sizeof(void *), "UINT_PTR must be pointer-sized"); +using LONG_PTR = int; +using ULONG_PTR = unsigned int; +using UINT_PTR = unsigned int; using DWORD_PTR = ULONG_PTR; using PDWORD_PTR = DWORD_PTR *; using SHORT = short; @@ -97,7 +111,7 @@ using BYTE = unsigned char; using BOOLEAN = unsigned char; using UINT = unsigned int; using PUINT = UINT *; -using HKEY = VOID *; +using HKEY = HANDLE; using PHKEY = HKEY *; using PSID = VOID *; using REGSAM = DWORD; @@ -110,6 +124,8 @@ using PBYTE = BYTE *; using LPBYTE = BYTE *; using PWSTR = WCHAR *; +constexpr HANDLE NO_HANDLE = 0; + using NTSTATUS = LONG; using HRESULT = LONG; @@ -271,20 +287,23 @@ constexpr SIZE_T kTlsSlotCount = 64; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; + GUEST_PTR Buffer; +} UNICODE_STRING; +typedef GUEST_PTR PUNICODE_STRING; typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; - PVOID Reserved2[10]; + GUEST_PTR Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; typedef struct _LIST_ENTRY { - struct _LIST_ENTRY *Flink; - struct _LIST_ENTRY *Blink; -} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY; + GUEST_PTR Flink; + GUEST_PTR Blink; +} LIST_ENTRY; +typedef GUEST_PTR PLIST_ENTRY; +typedef GUEST_PTR PRLIST_ENTRY; typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; @@ -299,23 +318,24 @@ typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; - PVOID Reserved3[2]; - PPEB_LDR_DATA Ldr; - PRTL_USER_PROCESS_PARAMETERS ProcessParameters; - PVOID Reserved4[3]; - PVOID AtlThunkSListPtr; - PVOID Reserved5; + GUEST_PTR Reserved3[2]; + GUEST_PTR Ldr; + GUEST_PTR ProcessParameters; + GUEST_PTR Reserved4[3]; + GUEST_PTR AtlThunkSListPtr; + GUEST_PTR Reserved5; ULONG Reserved6; - PVOID Reserved7; + GUEST_PTR Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; - PVOID Reserved9[45]; + GUEST_PTR Reserved9[45]; BYTE Reserved10[96]; - PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; + GUEST_PTR PostProcessInitRoutine; BYTE Reserved11[128]; - PVOID Reserved12[1]; + GUEST_PTR Reserved12[1]; ULONG SessionId; -} PEB, *PPEB; +} PEB; +typedef GUEST_PTR PPEB; struct CLIENT_ID { HANDLE UniqueProcess; @@ -325,7 +345,7 @@ struct CLIENT_ID { struct _ACTIVATION_CONTEXT; typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME { - struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME *Previous; + GUEST_PTR Previous; _ACTIVATION_CONTEXT *ActivationContext; ULONG Flags; } RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME; @@ -339,6 +359,7 @@ typedef struct _ACTIVATION_CONTEXT_STACK { } ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; #define GDI_BATCH_BUFFER_SIZE 0x136 + typedef struct _GDI_TEB_BATCH { ULONG Offset; HANDLE HDC; @@ -346,83 +367,86 @@ typedef struct _GDI_TEB_BATCH { } GDI_TEB_BATCH, *PGDI_TEB_BATCH; typedef struct _NT_TIB { - struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; - PVOID StackBase; - PVOID StackLimit; - PVOID SubSystemTib; + GUEST_PTR ExceptionList; + GUEST_PTR StackBase; + GUEST_PTR StackLimit; + GUEST_PTR SubSystemTib; union { - PVOID FiberData; + GUEST_PTR FiberData; DWORD Version; } DUMMYUNIONNAME; - PVOID ArbitraryUserPointer; - struct _NT_TIB *Self; + GUEST_PTR ArbitraryUserPointer; + GUEST_PTR Self; } NT_TIB, *PNT_TIB; typedef struct _TEB { NT_TIB Tib; - PVOID EnvironmentPointer; + GUEST_PTR EnvironmentPointer; CLIENT_ID ClientId; - PVOID ActiveRpcHandle; - PVOID ThreadLocalStoragePointer; + GUEST_PTR ActiveRpcHandle; + GUEST_PTR ThreadLocalStoragePointer; PPEB Peb; ULONG LastErrorValue; ULONG CountOfOwnedCriticalSections; - PVOID CsrClientThread; - PVOID Win32ThreadInfo; + GUEST_PTR CsrClientThread; + GUEST_PTR Win32ThreadInfo; ULONG Win32ClientInfo[31]; /* used for user32 private data in Wine */ - PVOID WOW32Reserved; + GUEST_PTR WOW32Reserved; ULONG CurrentLocale; ULONG FpSoftwareStatusRegister; - PVOID SystemReserved1[54]; /* used for kernel32 private data in Wine */ - PVOID Spare1; + GUEST_PTR SystemReserved1[54]; /* used for kernel32 private data in Wine */ + GUEST_PTR Spare1; LONG ExceptionCode; - PVOID ActivationContextStackPointer; + GUEST_PTR ActivationContextStackPointer; BYTE SpareBytes1[36]; - PVOID SystemReserved2[10]; /* used for ntdll private data in Wine */ + GUEST_PTR SystemReserved2[10]; /* used for ntdll private data in Wine */ GDI_TEB_BATCH GdiTebBatch; ULONG gdiRgn; ULONG gdiPen; ULONG gdiBrush; CLIENT_ID RealClientId; - HANDLE GdiCachedProcessHandle; + GUEST_PTR GdiCachedProcessHandle; ULONG GdiClientPID; ULONG GdiClientTID; - PVOID GdiThreadLocaleInfo; - PVOID UserReserved[5]; - PVOID glDispatchTable[280]; + GUEST_PTR GdiThreadLocaleInfo; + GUEST_PTR UserReserved[5]; + GUEST_PTR glDispatchTable[280]; ULONG glReserved1[26]; - PVOID glReserved2; - PVOID glSectionInfo; - PVOID glSection; - PVOID glTable; - PVOID glCurrentRC; - PVOID glContext; + GUEST_PTR glReserved2; + GUEST_PTR glSectionInfo; + GUEST_PTR glSection; + GUEST_PTR glTable; + GUEST_PTR glCurrentRC; + GUEST_PTR glContext; ULONG LastStatusValue; UNICODE_STRING StaticUnicodeString; WCHAR StaticUnicodeBuffer[261]; - PVOID DeallocationStack; - PVOID TlsSlots[64]; + GUEST_PTR DeallocationStack; + GUEST_PTR TlsSlots[64]; LIST_ENTRY TlsLinks; - PVOID Vdm; - PVOID ReservedForNtRpc; - PVOID DbgSsReserved[2]; + GUEST_PTR Vdm; + GUEST_PTR ReservedForNtRpc; + GUEST_PTR DbgSsReserved[2]; ULONG HardErrorDisabled; - PVOID Instrumentation[16]; - PVOID WinSockData; + GUEST_PTR Instrumentation[16]; + GUEST_PTR WinSockData; ULONG GdiBatchCount; ULONG Spare2; ULONG Spare3; ULONG Spare4; - PVOID ReservedForOle; + GUEST_PTR ReservedForOle; ULONG WaitingOnLoaderLock; - PVOID Reserved5[3]; - PVOID *TlsExpansionSlots; + GUEST_PTR Reserved5[3]; + GUEST_PTR TlsExpansionSlots; // wibo WORD CurrentFsSelector; WORD CurrentGsSelector; - PVOID CurrentStackPointer; -} TEB, *PTEB; - + void *CurrentStackPointer; +#ifdef __x86_64__ + void *CurrentFsBase; +#endif +} TEB; +typedef GUEST_PTR PTEB; #ifndef offsetof #define offsetof(type, member) __builtin_offsetof(type, member) #endif @@ -436,8 +460,8 @@ static_assert(offsetof(TEB, DeallocationStack) == 0xE0C, "DeallocationStack offs static_assert(offsetof(TEB, TlsSlots) == 0xE10, "TLS slots offset mismatch"); typedef struct _MEMORY_BASIC_INFORMATION { - PVOID BaseAddress; - PVOID AllocationBase; + GUEST_PTR BaseAddress; + GUEST_PTR AllocationBase; DWORD AllocationProtect; SIZE_T RegionSize; DWORD State; @@ -451,12 +475,12 @@ typedef struct _iobuf { _iobuf() : _file(-1) {} explicit _iobuf(int file) : _file(file) {} - char *_ptr = nullptr; + GUEST_PTR _ptr = GUEST_NULL; int _cnt = 0; - char *_base = nullptr; + GUEST_PTR _base = GUEST_NULL; int _flag = 0; int _file; int _charbuf = 0; int _bufsiz = 0; - char *_tmpfname = nullptr; + GUEST_PTR _tmpfname = GUEST_NULL; } _FILE; diff --git a/tools/gen_trampolines.py b/tools/gen_trampolines.py index bc46a74..6288027 100644 --- a/tools/gen_trampolines.py +++ b/tools/gen_trampolines.py @@ -20,7 +20,7 @@ import os import sys import tempfile from dataclasses import dataclass, field -from enum import IntEnum +from enum import Enum, IntEnum from pathlib import Path from typing import Iterable, List, Optional @@ -50,6 +50,11 @@ if "LIBCLANG_PATH" in os.environ: ) +class Arch(str, Enum): + X86 = "x86" + X86_64 = "x86_64" + + class CallingConv(IntEnum): """CXCallingConv enum values from clang-c/Index.h""" @@ -91,13 +96,30 @@ def _get_function_calling_conv(func_type: CXType) -> CallingConv: return CallingConv(_get_calling_conv(func_type)) +class ArgClass(str, Enum): + INT = "int" + MEMORY = "memory" + + @dataclass class ArgInfo: + type: Type + arg_class: ArgClass + sign_extended: bool + + +@dataclass +class ArgPlacement: size: int slot_size: int - primitive: bool - sign_extended: bool - type: Type + stack_offset: Optional[int] = None + register: Optional[str] = None + + def __init__(self, arg: ArgInfo, arch: Arch): + self.size = arg.type.get_canonical().get_size() + self.slot_size = _slot_size_for_arch(arg, arch) + self.register = None + self.stack_offset = None @dataclass @@ -108,7 +130,7 @@ class FuncInfo: source_cc: CallingConv target_cc: CallingConv variadic: bool - return_type: Type + return_type: ArgInfo args: List[ArgInfo] = field(default_factory=list) @@ -118,7 +140,7 @@ class TypedefInfo: source_cc: CallingConv target_cc: CallingConv variadic: bool - return_type: Type + return_type: ArgInfo args: List[ArgInfo] = field(default_factory=list) @@ -210,43 +232,146 @@ SIGNED_KINDS = [ ] +def _calculate_arg_info(t: Type) -> ArgInfo: + canonical = t.get_canonical() + + # if canonical.kind == TypeKind.RECORD: + # arg_class = ArgClass.MEMORY + # else: + arg_class = ArgClass.INT + + if canonical.kind == TypeKind.POINTER: + pointee = canonical.get_pointee() + if pointee.kind == TypeKind.POINTER: + print(f"Bugprone: Pointer to pointer ({_type_to_string(t)})") + + # Sign-extend signed integers and HANDLE-like typedefs + is_sign_extended = canonical.kind in SIGNED_KINDS or _is_handle_typedef(t) + + return ArgInfo( + arg_class=arg_class, + sign_extended=is_sign_extended, + type=t, + ) + + def _collect_args(func_type: CXType) -> List[ArgInfo]: """Collect argument information for a function.""" args: List[ArgInfo] = [] for t in func_type.argument_types(): - size = t.get_size() - canonical = t.get_canonical() - - # Determine if primitive (not struct/union) - is_primitive = canonical.kind != TypeKind.RECORD - - # Determine if sign-extended - # Sign-extend signed integers and HANDLE-like typedefs - is_sign_extended = canonical in SIGNED_KINDS or _is_handle_typedef(t) - - # Calculate stack slot size - if size <= 4: - slot_size = 4 - elif size <= 8: - slot_size = 8 - else: - raise NotImplementedError( - f"Argument size {size} not supported for function {func_type.spelling}" - ) - - args.append( - ArgInfo( - size=size, - slot_size=slot_size, - primitive=is_primitive, - sign_extended=is_sign_extended, - type=t, - ) - ) + args.append(_calculate_arg_info(t)) return args -def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[FuncInfo]: +def _slot_size_for_arch(arg: ArgInfo, arch: Arch) -> int: + """Return the slot size (in bytes) used to pass an argument on the given architecture.""" + canonical = arg.type.get_canonical() + if canonical.kind == TypeKind.POINTER: + return 8 if arch == Arch.X86_64 else 4 + size = canonical.get_size() + if arch == Arch.X86: + if size <= 4: + return 4 + if size <= 8: + return 8 + elif arch == Arch.X86_64: + if size <= 8: + return 8 + raise NotImplementedError( + f"Argument size {size} not supported for architecture {arch.value}" + ) + + +@dataclass +class ArgLayout: + args: List[ArgPlacement] + stack_size: int + + +def compute_arg_layout( + args: List[ArgInfo], + cc: CallingConv, + arch: Arch, + stack_offset: int = 0, + skip_args: int = 0, +) -> ArgLayout: + """Compute how each argument is passed for the given calling convention and arch.""" + + placements: List[ArgPlacement] = [] + stack_size = 0 + gpr_order: List[str] = [] + gpr_index = skip_args + + if arch == Arch.X86 and cc == CallingConv.X86_FASTCALL: + gpr_order = ["ecx", "edx"] + elif arch == Arch.X86_64 and cc == CallingConv.C: + gpr_order = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"] + + # Offset our stack based on number of extra arguments + # We assume that every arg represented by skip_args fits in a register + register_size = 8 if arch == Arch.X86_64 else 4 + consumed_stack = max(0, skip_args - len(gpr_order)) * register_size + stack_offset += consumed_stack + stack_size += consumed_stack + + def _push_stack(arg: ArgInfo) -> None: + nonlocal stack_offset + nonlocal stack_size + placement = ArgPlacement(arg, arch) + placement.stack_offset = stack_offset + placements.append(placement) + stack_offset += placement.slot_size + stack_size += placement.slot_size + + def _push_register(arg: ArgInfo) -> None: + nonlocal gpr_index + placement = ArgPlacement(arg, arch) + placement.register = gpr_order[gpr_index] + placements.append(placement) + gpr_index += 1 + + # Special case for x86 fastcall: stop using registers if any spill onto the stack + if arch == Arch.X86 and cc == CallingConv.X86_FASTCALL: + stack_args_start = 0 + for i in range(min(len(gpr_order), len(args))): + if gpr_index >= len(gpr_order): + break + arg = args[i] + slot_size = _slot_size_for_arch(arg, arch) + if arg.arg_class == ArgClass.INT and slot_size == 4: + _push_register(arg) + stack_args_start += 1 + else: + break + + for i in range(stack_args_start, len(args)): + _push_stack(args[i]) + else: + for arg in args: + slot_size = _slot_size_for_arch(arg, arch) + if ( + arg.arg_class == ArgClass.INT + and slot_size <= register_size + and gpr_index < len(gpr_order) + ): + _push_register(arg) + else: + _push_stack(arg) + + return ArgLayout(args=placements, stack_size=stack_size) + + +def describe_arg_placement(placement: ArgPlacement) -> str: + if placement.register is not None: + return f"{placement.register}[{placement.slot_size}]" + if placement.stack_offset is not None: + return f"stack+{placement.stack_offset}[{placement.slot_size}]" + raise ValueError(f"Unassigned placement {placement}") + + +def collect_functions( + tu: TranslationUnit, ns_filter: Optional[str], arch: Arch +) -> List[FuncInfo]: want_ns = ns_filter.split("::") if ns_filter else None out: dict[str, FuncInfo] = {} @@ -268,7 +393,7 @@ def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Fun source_cc=source_cc, target_cc=_get_function_calling_conv(node.type), variadic=node.type.is_function_variadic(), - return_type=node.type.get_result(), + return_type=_calculate_arg_info(node.type.get_result()), args=_collect_args(node.type), ) @@ -292,7 +417,7 @@ def _type_to_string(t: CXType) -> str: return spelling -def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]: +def collect_typedefs(tu: TranslationUnit, arch: Arch) -> List[TypedefInfo]: """Collect function pointer typedefs and type aliases from the translation unit.""" out: dict[str, TypedefInfo] = {} @@ -309,17 +434,13 @@ def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]: if target_cc == CallingConv.DEFAULT: return # No CC annotation; skip - variadic = func_type.is_function_variadic() - args = _collect_args(func_type) - return_type = func_type.get_result() - out[name] = TypedefInfo( name=name, source_cc=source_cc, target_cc=target_cc, - variadic=variadic, - return_type=return_type, - args=args, + variadic=func_type.is_function_variadic(), + return_type=_calculate_arg_info(func_type.get_result()), + args=_collect_args(func_type), ) def visit(node: Cursor) -> None: @@ -372,17 +493,15 @@ def collect_variables(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Var return sorted(out.values(), key=lambda v: v.name) -def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): +def emit_cc_thunk32(f: FuncInfo | TypedefInfo, lines: List[str]): if isinstance(f, TypedefInfo): # Host-to-guest - target = "[eax+4]" - arg_off = 8 + call_target = "[eax+4]" align = 0 host_to_guest = True elif isinstance(f, FuncInfo): # Guest-to-host - target = f.mangled - arg_off = 4 + call_target = f.mangled align = 16 host_to_guest = False @@ -391,49 +510,32 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, ( "Variadic functions must be cdecl" ) - lines.append(f"\tjmp {target}") + lines.append(f"\tjmp {call_target}") return - # Compute argument stack offsets - offsets: List[int] = [] - for arg in f.args: - offsets.append(arg_off) - arg_off += arg.slot_size - - reg_indices: List[int] = [] - if f.target_cc == CallingConv.X86_FASTCALL: - # Store the first two non-record 4-byte args in ECX/EDX for GCC/Clang x86 fastcall - if len(f.args) >= 1 and f.args[0].primitive and f.args[0].slot_size == 4: - reg_indices.append(0) # ECX - if len(f.args) >= 2 and f.args[1].primitive and f.args[1].slot_size == 4: - reg_indices.append(1) # EDX - elif f.target_cc == CallingConv.C or f.target_cc == CallingConv.X86_STDCALL: - # No register args for cdecl or stdcall - pass - else: - raise NotImplementedError( - f"Unsupported target calling convention {f.target_cc.name} for function {f.name}" - ) - - # Bytes we will push for the call (exclude args passed in registers) - stack_bytes = sum( - arg.slot_size for i, arg in enumerate(f.args) if i not in reg_indices + source_layout = compute_arg_layout( + f.args, + f.source_cc, + Arch.X86, + stack_offset=4, + skip_args=1 if host_to_guest else 0, ) + target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86) - # Get current TIB + # Get current TEB if host_to_guest: lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]") else: - lines.append("\tmov ecx, fs:[0x18]") + lines.append("\tmov ecx, fs:[TEB_SELF]") # Swap fs and gs lines.append("\tmov ax, fs") - lines.append("\tmov dx, word ptr [ecx+0xf98]") - lines.append("\tmov word ptr [ecx+0xf98], ax") + lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]") + lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax") lines.append("\tmov fs, dx") lines.append("\tmov ax, gs") - lines.append("\tmov dx, word ptr [ecx+0xf9a]") - lines.append("\tmov word ptr [ecx+0xf9a], ax") + lines.append("\tmov dx, word ptr [ecx+TEB_GS_SEL]") + lines.append("\tmov word ptr [ecx+TEB_GS_SEL], ax") lines.append("\tmov gs, dx") # Store guest stack pointer in eax for arg access @@ -442,48 +544,60 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): # Swap stack pointer lines.append("\tpush ebp") - lines.append("\tmov ebp, dword ptr [ecx+0xf9c]") - lines.append("\tmov dword ptr [ecx+0xf9c], esp") + lines.append("\tmov ebp, dword ptr [ecx+TEB_SP]") + lines.append("\tmov dword ptr [ecx+TEB_SP], esp") lines.append("\tmov esp, ebp") # Allocate stack space for arguments - if stack_bytes > 0: - lines.append(f"\tsub esp, {stack_bytes}") + if target_layout.stack_size > 0: + lines.append(f"\tsub esp, {target_layout.stack_size}") # Align stack if needed (must be done after allocating args) if align > 0: lines.append(f"\tand esp, ~{align - 1}") - # Copy args onto stack - cur_off = 0 - for i, arg in enumerate(f.args): - if i in reg_indices: + # Copy args onto stack for the callee + for idx, target in enumerate(target_layout.args): + if target.stack_offset is None: continue - base = offsets[i] - for part_off in range(0, arg.slot_size, 4): - lines.append(f"\tmov ecx, [eax+{base + part_off}]") - lines.append(f"\tmov [esp+{cur_off + part_off}], ecx") - cur_off += arg.slot_size + + source = source_layout.args[idx] + if source.stack_offset is None: + raise NotImplementedError( + f"Source calling convention {f.source_cc.name} requires register argument {idx}; not implemented" + ) + + if source.slot_size != target.slot_size: + raise NotImplementedError( + f"Argument {idx} requires size conversion {source.slot_size}->{target.slot_size}; not implemented" + ) + + for off in range(0, target.slot_size, 4): + lines.append(f"\tmov ecx, [eax+{source.stack_offset + off}]") + lines.append(f"\tmov [esp+{target.stack_offset + off}], ecx") # Load args into registers as needed - if len(reg_indices) > 0: - i = reg_indices[0] - offset = offsets[i] - lines.append(f"\tmov ecx, [eax+{offset}]") - if len(reg_indices) > 1: - i = reg_indices[1] - offset = offsets[i] - lines.append(f"\tmov edx, [eax+{offset}]") + for idx, target in enumerate(target_layout.args): + if target.register is None: + continue + + source = source_layout.args[idx] + if source.stack_offset is None: + raise NotImplementedError( + f"Source calling convention {f.source_cc.name} requires register argument {idx}; not implemented" + ) + + lines.append(f"\tmov {target.register}, [eax+{source.stack_offset}]") # Call into target - lines.append(f"\tcall {target}") + lines.append(f"\tcall {call_target}") # Determine if we can clobber eax/edx - if f.return_type.kind == TypeKind.RECORD: + if f.return_type.arg_class != ArgClass.INT: raise NotImplementedError( - f"Struct return type not supported for function {f.name}" + f"Unsupported return type class {f.return_type.arg_class.value} for function {f.name}" ) - return_size = f.return_type.get_size() + return_size = f.return_type.type.get_size() save_eax = return_size > 0 save_edx = return_size > 4 if return_size > 8: @@ -497,16 +611,16 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): if save_edx: lines.append("\tpush edx") if host_to_guest: - lines.append("\tmov ecx, fs:[0x18]") + lines.append("\tmov ecx, fs:[TEB_SELF]") else: lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]") lines.append("\tmov ax, fs") - lines.append("\tmov dx, word ptr [ecx+0xf98]") - lines.append("\tmov word ptr [ecx+0xf98], ax") + lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]") + lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax") lines.append("\tmov fs, dx") lines.append("\tmov ax, gs") - lines.append("\tmov dx, word ptr [ecx+0xf9a]") - lines.append("\tmov word ptr [ecx+0xf9a], ax") + lines.append("\tmov dx, word ptr [ecx+TEB_GS_SEL]") + lines.append("\tmov word ptr [ecx+TEB_GS_SEL], ax") lines.append("\tmov gs, dx") if save_edx: lines.append("\tpop edx") @@ -515,29 +629,293 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]): # Swap stack pointer lines.append("\tmov esp, ebp") # Clean up arg space - lines.append("\tmov ebp, dword ptr [ecx+0xf9c]") - lines.append("\tmov dword ptr [ecx+0xf9c], esp") + lines.append("\tmov ebp, dword ptr [ecx+TEB_SP]") + lines.append("\tmov dword ptr [ecx+TEB_SP], esp") # Restore stack and frame pointer lines.append("\tleave") # Return to guest - if f.source_cc == CallingConv.X86_STDCALL: - ret_bytes = sum(arg.slot_size for arg in f.args) - elif f.source_cc == CallingConv.C: - ret_bytes = 0 - else: - raise NotImplementedError( - f"Unsupported source calling convention {f.source_cc.name} for function {f.name}" - ) - if ret_bytes > 0: - lines.append(f"\tret {ret_bytes}") + if f.source_cc == CallingConv.X86_STDCALL and source_layout.stack_size > 0: + lines.append(f"\tret {source_layout.stack_size}") else: lines.append("\tret") +def _x64_register_by_slot_size(reg: str, slot_size: int) -> str: + if slot_size == 8: + return reg + if reg in ["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp"]: + if slot_size == 4: + return f"e{reg[1:]}" + elif slot_size == 2: + return reg[1:] + elif slot_size == 1: + if reg in ["rax", "rbx", "rcx", "rdx"]: + return f"{reg[1]}l" + elif reg in ["rsi", "rdi"]: + return f"{reg[1]}il" + else: + return f"{reg[1]}pl" + if slot_size == 4: + return f"{reg}d" + if slot_size == 2: + return f"{reg}w" + if slot_size == 1: + return f"{reg}b" + raise NotImplementedError(f"Unsupported register {reg} for slot size {slot_size}") + + +def _x64_ptr_type_by_slot_size(slot_size) -> str: + if slot_size == 4: + return "dword ptr" + elif slot_size == 8: + return "qword ptr" + else: + raise ValueError(f"Unsupported slot size {slot_size}") + + +def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]): + if isinstance(f, TypedefInfo): + # Host-to-guest + call_target = "edi" + align = 0 + host_to_guest = True + elif isinstance(f, FuncInfo): + # Guest-to-host + call_target = f.mangled + align = 16 + host_to_guest = False + + if f.variadic: + # Variadic functions are not yet supported for calling convention conversion. + assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, ( + "Variadic functions must be cdecl" + ) + lines.append(f"\tjmp {call_target}") + return + + source_layout = compute_arg_layout( + f.args, + f.source_cc, + Arch.X86_64 if host_to_guest else Arch.X86, + stack_offset=24 if host_to_guest else 16, + skip_args=1 if host_to_guest else 0, + ) + target_layout = compute_arg_layout( + f.args, f.target_cc, Arch.X86 if host_to_guest else Arch.X86_64 + ) + + if host_to_guest: + lines.append(".code64") + + # Save rbx and rbp + lines.append("\tpush rbx") + lines.append("\tpush rbp") + + # Stash host stack in r10 + lines.append("\tmov r10, rsp") + + # Get current TEB + lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]") + + # Save FS base + lines.append("\trdfsbase r9") + lines.append("\tmov qword ptr [rcx+TEB_FSBASE], r9") + + # Save RSP and load guest stack + lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]") + lines.append("\tmov qword ptr [rcx+TEB_SP], rsp") + lines.append("\tmov rsp, rbp") + + # Allocate stack space for arguments + if target_layout.stack_size > 0: + lines.append(f"\tsub rsp, {target_layout.stack_size}") + + # Align stack if needed (must be done after allocating args) + if align > 0: + lines.append(f"\tand rsp, ~{align - 1}") + + # Transfer arguments + for i, target in enumerate(target_layout.args): + if target.stack_offset is None: + raise NotImplementedError(f"Unexpected register argument {target}") + + source = source_layout.args[i] + if source.stack_offset is not None: + ptr_type = _x64_ptr_type_by_slot_size(source.slot_size) + register = _x64_register_by_slot_size("rax", target.slot_size) + lines.append( + f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]" + ) + ptr_type = _x64_ptr_type_by_slot_size(target.slot_size) + register = _x64_register_by_slot_size("rax", target.slot_size) + elif source.register is not None: + ptr_type = _x64_ptr_type_by_slot_size(target.slot_size) + register = _x64_register_by_slot_size(source.register, target.slot_size) + else: + raise ValueError(f"Argument {i} is not a register or stack offset") + lines.append(f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}") + + # Jump to 32-bit mode + lines.append("\tLJMP32") + + # Setup FS selector + lines.append("\tmov ax, word ptr [ecx+TEB_FS_SEL]") + lines.append("\tmov fs, ax") + + # Call into target + lines.append(f"\tcall {call_target}") + + # Get current TEB + lines.append("\tmov ecx, fs:[TEB_SELF]") + + # Jump back to 64-bit + lines.append("\tLJMP64") + + # Sign extend return value if necessary + if f.return_type.sign_extended: + lines.append("\tcdqe") + + # Restore FS base + lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]") + lines.append("\twrfsbase r9") + + # Restore host stack + lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]") + lines.append("\tmov qword ptr [rcx+TEB_SP], rbp") + + # Restore rbp, rbx and return + lines.append("\tpop rbp") + lines.append("\tpop rbx") + lines.append("\tret") + else: + lines.append(".code32") + + # Save registers + lines.append("\tpush ebp") + lines.append("\tpush esi") + lines.append("\tpush edi") + + # Get current TEB + lines.append("\tmov ecx, fs:[TEB_SELF]") + + # Save fs segment + lines.append("\tmov di, fs") + lines.append("\tmov word ptr [ecx+TEB_FS_SEL], di") + + # Jump back to 64-bit + lines.append("\tLJMP64") + + # Restore FS base + lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]") + lines.append("\twrfsbase r9") + + # Stash guest stack in r10 + lines.append("\tmov r10, rsp") + + # Restore host stack + lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]") + lines.append("\tmov qword ptr [rcx+TEB_SP], rsp") + lines.append("\tmov rsp, rbp") + + # Allocate stack space for arguments + if target_layout.stack_size > 0: + lines.append(f"\tsub rsp, {target_layout.stack_size}") + + # Align stack if needed (must be done after allocating args) + if align > 0: + lines.append(f"\tand rsp, ~{align - 1}") + + # Transfer args + for i, target in enumerate(target_layout.args): + arg = f.args[i] + source = source_layout.args[i] + + if target.stack_offset is not None: + if source.stack_offset is not None: + ptr_type = _x64_ptr_type_by_slot_size(source.slot_size) + register = _x64_register_by_slot_size("rax", source.slot_size) + lines.append( + f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]" + ) + ptr_type = _x64_ptr_type_by_slot_size(target.slot_size) + register = _x64_register_by_slot_size("rax", target.slot_size) + elif source.register is not None: + ptr_type = _x64_ptr_type_by_slot_size(target.slot_size) + register = _x64_register_by_slot_size( + source.register, target.slot_size + ) + else: + raise ValueError(f"Argument {i} is not a register or stack offset") + lines.append( + f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}" + ) + elif target.register is not None: + ptr_type = _x64_ptr_type_by_slot_size(source.slot_size) + if source.slot_size == 4 and target.slot_size == 8: + if arg.sign_extended: + register = _x64_register_by_slot_size( + target.register, source.slot_size + ) + lines.append( + f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]" + ) + lines.append(f"\tmovsxd {target.register}, {register}") + else: + register = _x64_register_by_slot_size( + target.register, source.slot_size + ) + lines.append( + f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]" + ) + elif source.slot_size == 8 and target.slot_size == 8: + lines.append( + f"\tmov {target.register}, {ptr_type} [r10+{source.stack_offset}]" + ) + else: + raise NotImplementedError( + f"Unsupported conversion from {source.slot_size} to {target.slot_size}" + ) + + # Call into target + lines.append(f"\tcall {call_target}") + + # Get current TEB + lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]") + + # Restore host stack + lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]") + lines.append("\tmov qword ptr [rcx+TEB_SP], rbp") + + # Jump to 32-bit mode + lines.append("\tLJMP32") + + # Setup FS selector + lines.append("\tmov di, word ptr [ecx+TEB_FS_SEL]") + lines.append("\tmov fs, di") + + # Restore registers + lines.append("\tpop edi") + lines.append("\tpop esi") + lines.append("\tpop ebp") + + # Return to guest + if f.source_cc == CallingConv.X86_STDCALL and source_layout.stack_size > 0: + lines.append(f"\tret {source_layout.stack_size}") + else: + lines.append("\tret") + + +def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str], arch: Arch): + if arch == Arch.X86_64: + return emit_cc_thunk64(f, lines) + elif arch == Arch.X86: + return emit_cc_thunk32(f, lines) + + def emit_guest_to_host_thunks( - lines: List[str], dll: str, funcs: Iterable[FuncInfo] + lines: List[str], dll: str, funcs: Iterable[FuncInfo], arch: Arch ) -> None: for f in funcs: thunk = f"thunk_{dll}_{f.name}" @@ -545,19 +923,24 @@ def emit_guest_to_host_thunks( lines.append( f"# {f.qualified_ns}::{f.name} (source_cc={f.source_cc.name}, target_cc={f.target_cc.name}, variadic={f.variadic})" ) + source_layout = compute_arg_layout(f.args, f.source_cc, Arch.X86) + target_layout = compute_arg_layout(f.args, f.target_cc, arch) for i, arg in enumerate(f.args): - lines.append( - f"\t# Arg {i} (slot_size={arg.slot_size}, primitive={arg.primitive}, sign_extended={arg.sign_extended})" - ) + details: List[str] = [] + details.append(f"src={describe_arg_placement(source_layout.args[i])}") + details.append(f"dst={describe_arg_placement(target_layout.args[i])}") + details.append(f"class={arg.arg_class.value}") + details.append(f"sign_extended={arg.sign_extended}") + lines.append(f"\t# Arg {i} ({', '.join(details)})") lines.append(f".globl {thunk}") lines.append(f".type {thunk}, @function") lines.append(f"{thunk}:") - emit_cc_thunk(f, lines) + emit_cc_thunk(f, lines, arch) lines.append(f".size {thunk}, .-{thunk}") def emit_host_to_guest_thunks( - lines: List[str], typedefs: Iterable[TypedefInfo] + lines: List[str], typedefs: Iterable[TypedefInfo], arch: Arch ) -> None: for f in typedefs: thunk = f"call_{f.name}" @@ -565,14 +948,23 @@ def emit_host_to_guest_thunks( lines.append( f"# {f.name} (target_cc={f.target_cc.name}, variadic={f.variadic})" ) + source_layout = compute_arg_layout(f.args, f.source_cc, arch, skip_args=1) + target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86) for i, arg in enumerate(f.args): - lines.append( - f"\t# Arg {i} (slot_size={arg.slot_size}, primitive={arg.primitive}, sign_extended={arg.sign_extended})" - ) + details: List[str] = [] + details.append(f"src={describe_arg_placement(source_layout.args[i])}") + details.append(f"dst={describe_arg_placement(target_layout.args[i])}") + details.append(f"class={arg.arg_class.value}") + details.append(f"sign_extended={arg.sign_extended}") + lines.append(f"\t# Arg {i} ({', '.join(details)})") + # details = [] + # details.append(f"class={f.return_type.arg_class.value}") + # details.append(f"sign_extended={f.return_type.sign_extended}") + # lines.append(f"\t# Ret ({', '.join(details)})") lines.append(f".weak {thunk}") lines.append(f".type {thunk}, @function") lines.append(f"{thunk}:") - emit_cc_thunk(f, lines) + emit_cc_thunk(f, lines, arch) lines.append(f".size {thunk}, .-{thunk}") @@ -581,6 +973,7 @@ def emit_header_mapping( funcs: Iterable[FuncInfo], typedefs: Iterable[TypedefInfo], variables: Iterable[VarInfo], + arch: Arch, ) -> str: guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H" lines: List[str] = [] @@ -619,16 +1012,18 @@ def emit_header_mapping( type_str = _canonical_type_str(arg.type) args.append(f"{type_str} arg{i}") param_list = ", ".join(args) - return_type = _canonical_type_str(f.return_type) - if f.source_cc == CallingConv.X86_STDCALL: - cc_attr = "__attribute__((stdcall))" + return_type = _canonical_type_str(f.return_type.type) + if arch == Arch.X86_64: + cc_attr = "" + elif f.source_cc == CallingConv.X86_STDCALL: + cc_attr = "__attribute__((stdcall)) " elif f.source_cc == CallingConv.C: - cc_attr = "__attribute__((cdecl))" + cc_attr = "__attribute__((cdecl)) " else: raise NotImplementedError( f"Unsupported calling convention {f.source_cc.name} for function {f.name}" ) - lines.append(f"{cc_attr} {return_type} {thunk}({param_list});") + lines.append(f"{cc_attr}{return_type} {thunk}({param_list});") # Host-to-guest thunk functions for td in typedefs: @@ -642,7 +1037,7 @@ def emit_header_mapping( params.append(f"{type_str} arg{i}") param_list = ", ".join(params) - return_type = _type_to_string(td.return_type) + return_type = _type_to_string(td.return_type.type) lines.append(f"{return_type} {thunk}({param_list});") lines.append("#ifdef __cplusplus\n}\n#endif") @@ -672,7 +1067,7 @@ def main() -> int: ap.add_argument( "--namespace", dest="ns", default=None, help="Namespace filter, e.g. kernel32" ) - ap.add_argument("--arch", choices=["x86"], default="x86") + ap.add_argument("--arch", choices=["x86", "x86_64"], default="x86") ap.add_argument( "--out-asm", type=Path, required=True, help="Output assembly file (.S)" ) @@ -682,10 +1077,17 @@ def main() -> int: ap.add_argument("-I", dest="incs", action="append", default=[]) args = ap.parse_args() + if args.arch == "x86": + arch = Arch.X86 + elif args.arch == "x86_64": + arch = Arch.X86_64 + else: + raise ValueError(f"Unsupported architecture: {args.arch}") + target = "i686-pc-linux-gnu" if args.arch == "x86" else "x86_64-pc-linux-gnu" tu = parse_tu(args.headers, args.incs, target) - funcs = collect_functions(tu, args.ns) - typedefs = collect_typedefs(tu) + funcs = collect_functions(tu, args.ns, arch) + typedefs = collect_typedefs(tu, arch) variables = collect_variables(tu, args.ns) if not funcs and not typedefs and not variables: @@ -694,15 +1096,15 @@ def main() -> int: lines: List[str] = [] lines.append("# Auto-generated thunks; DO NOT EDIT.") - lines.append(".intel_syntax noprefix") + lines.append('#include "macros.S"') lines.append('.section .note.GNU-stack, "", @progbits') lines.append(".text") - emit_guest_to_host_thunks(lines, args.dll, funcs) - emit_host_to_guest_thunks(lines, typedefs) + emit_guest_to_host_thunks(lines, args.dll, funcs, arch) + emit_host_to_guest_thunks(lines, typedefs, arch) asm = "\n".join(lines) + "\n" - hdr = emit_header_mapping(args.dll, funcs, typedefs, variables) + hdr = emit_header_mapping(args.dll, funcs, typedefs, variables, arch) args.out_asm.parent.mkdir(parents=True, exist_ok=True) args.out_hdr.parent.mkdir(parents=True, exist_ok=True)