Fully functional guest<->host trampolines

This commit is contained in:
2025-10-31 00:45:32 -06:00
parent 55a62a27c9
commit 52cdd7c811
56 changed files with 1683 additions and 1488 deletions

View File

@@ -170,7 +170,6 @@ add_executable(wibo
src/access.cpp
src/async_io.cpp
src/async_io_epoll.cpp
src/context.cpp
src/errors.cpp
src/files.cpp
src/handles.cpp
@@ -260,6 +259,17 @@ wibo_codegen_module(NAME advapi32 HEADERS
dll/advapi32/winreg.h
)
wibo_codegen_module(NAME bcrypt HEADERS dll/bcrypt.h)
wibo_codegen_module(NAME entry HEADERS src/entry.h)
wibo_codegen_module(NAME crt HEADERS dll/crt.h)
wibo_codegen_module(NAME mscoree HEADERS dll/mscoree.h)
wibo_codegen_module(NAME msvcrt HEADERS dll/msvcrt.h)
wibo_codegen_module(NAME version HEADERS dll/version.h)
wibo_codegen_module(NAME rpcrt4 HEADERS dll/rpcrt4.h)
wibo_codegen_module(NAME vcruntime HEADERS dll/vcruntime.h)
wibo_codegen_module(NAME lmgr HEADERS dll/lmgr.h)
wibo_codegen_module(NAME ole32 HEADERS dll/ole32.h)
wibo_codegen_module(NAME user32 HEADERS dll/user32.h)
wibo_codegen_module(NAME ntdll HEADERS dll/ntdll.h)
wibo_codegen_module(NAME kernel32 HEADERS
dll/kernel32/debugapi.h
dll/kernel32/errhandlingapi.h

View File

@@ -7,6 +7,6 @@ extern const wibo::ModuleStub lib_advapi32 = {
"advapi32",
nullptr,
},
advapi32_trampoline_by_name,
advapi32ThunkByName,
nullptr,
};

View File

@@ -10,7 +10,7 @@
namespace advapi32 {
BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle) {
BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle);
if (!TokenHandle) {

View File

@@ -4,6 +4,6 @@
namespace advapi32 {
BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
} // namespace advapi32

View File

@@ -103,7 +103,7 @@ bool writeLocalSystemSid(Sid *sid) {
namespace advapi32 {
BOOL WIN_FUNC InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision) {
BOOL WINAPI InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("InitializeAcl(%p, %u, %u)\n", pAcl, nAclLength, dwAclRevision);
if (!pAcl) {
@@ -133,7 +133,7 @@ BOOL WIN_FUNC InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision) {
return TRUE;
}
BOOL WIN_FUNC AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid) {
BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("AddAccessAllowedAce(%p, %u, 0x%x, %p)\n", pAcl, dwAceRevision, AccessMask, pSid);
if (!pAcl || !pSid) {
@@ -202,7 +202,7 @@ BOOL WIN_FUNC AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMa
return TRUE;
}
BOOL WIN_FUNC FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce);
if (!pAce) {
@@ -225,7 +225,7 @@ BOOL WIN_FUNC FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
return TRUE;
}
BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
LPBOOL lpbDaclDefaulted) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl,
@@ -262,7 +262,7 @@ BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor
return TRUE;
}
PSID_IDENTIFIER_AUTHORITY WIN_FUNC GetSidIdentifierAuthority(PSID pSid) {
PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetSidIdentifierAuthority(%p)\n", pSid);
if (!pSid) {
@@ -277,7 +277,7 @@ PSID_IDENTIFIER_AUTHORITY WIN_FUNC GetSidIdentifierAuthority(PSID pSid) {
return reinterpret_cast<PSID_IDENTIFIER_AUTHORITY>(&sid->IdentifierAuthority);
}
PUCHAR WIN_FUNC GetSidSubAuthorityCount(PSID pSid) {
PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetSidSubAuthorityCount(%p)\n", pSid);
if (!pSid) {
@@ -292,7 +292,7 @@ PUCHAR WIN_FUNC GetSidSubAuthorityCount(PSID pSid) {
return &sid->SubAuthorityCount;
}
PDWORD WIN_FUNC GetSidSubAuthority(PSID pSid, DWORD nSubAuthority) {
PDWORD WINAPI GetSidSubAuthority(PSID pSid, DWORD nSubAuthority) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetSidSubAuthority(%p, %u)\n", pSid, nSubAuthority);
if (!pSid) {
@@ -307,14 +307,14 @@ PDWORD WIN_FUNC GetSidSubAuthority(PSID pSid, DWORD nSubAuthority) {
return &sid->SubAuthority[nSubAuthority];
}
BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken) {
BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: ImpersonateLoggedOnUser(%p)\n", hToken);
(void)hToken;
return TRUE;
}
BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("DuplicateTokenEx(%p, 0x%x, %p, %u, %u, %p)\n", hExistingToken, dwDesiredAccess, lpTokenAttributes,
@@ -337,7 +337,7 @@ BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, voi
return TRUE;
}
BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid) {
BOOL WINAPI CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CopySid(%u, %p, %p)\n", nDestinationSidLength, pDestinationSid, pSourceSid);
if (!pDestinationSid || !pSourceSid) {
@@ -354,7 +354,7 @@ BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pS
return TRUE;
}
BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount) {
BOOL WINAPI InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("InitializeSid(%p, %p, %u)\n", sid, pIdentifierAuthority, nSubAuthorityCount);
if (!sid || !pIdentifierAuthority) {
@@ -375,7 +375,7 @@ BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAutho
return TRUE;
}
BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2) {
BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("EqualSid(%p, %p)\n", pSid1, pSid2);
if (!pSid1 || !pSid2) {
@@ -398,7 +398,7 @@ BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2) {
return equal ? TRUE : FALSE;
}
BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor);
@@ -415,7 +415,7 @@ BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION Securi
return TRUE;
}
BOOL WIN_FUNC InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision) {
BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("InitializeSecurityDescriptor(%p, %u)\n", pSecurityDescriptor, dwRevision);
if (!pSecurityDescriptor || dwRevision != SECURITY_DESCRIPTOR_REVISION) {
@@ -432,7 +432,7 @@ BOOL WIN_FUNC InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescrip
return TRUE;
}
BOOL WIN_FUNC SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
BOOL bDaclDefaulted) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted);
@@ -454,7 +454,7 @@ BOOL WIN_FUNC SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor
return TRUE;
}
BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation,
@@ -534,7 +534,7 @@ BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS To
return FALSE;
}
BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("AdjustTokenPrivileges(%p, %u, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, NewState,
@@ -548,7 +548,7 @@ BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivilege
return TRUE;
}
BOOL WIN_FUNC SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation,

View File

@@ -83,30 +83,30 @@ enum TOKEN_INFORMATION_CLASS : DWORD {
namespace advapi32 {
BOOL WIN_FUNC InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision);
BOOL WIN_FUNC AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid);
BOOL WIN_FUNC FindFirstFreeAce(PACL pAcl, LPVOID *pAce);
PSID_IDENTIFIER_AUTHORITY WIN_FUNC GetSidIdentifierAuthority(PSID pSid);
PUCHAR WIN_FUNC GetSidSubAuthorityCount(PSID pSid);
PDWORD WIN_FUNC GetSidSubAuthority(PSID pSid, DWORD nSubAuthority);
BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken);
BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
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);
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);
BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid);
BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount);
BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2);
BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
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 WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor);
BOOL WIN_FUNC InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision);
BOOL WIN_FUNC SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision);
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
BOOL bDaclDefaulted);
BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength);
BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength);
BOOL WIN_FUNC SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength);
} // namespace advapi32

View File

@@ -84,7 +84,7 @@ LUID lookupOrGeneratePrivilegeLuid(const std::string &normalizedName) {
namespace advapi32 {
BOOL WIN_FUNC LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse) {
HOST_CONTEXT_GUARD();
std::string systemName = lpSystemName ? wideStringToString(lpSystemName) : std::string("(null)");
@@ -115,7 +115,7 @@ BOOL WIN_FUNC LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPD
return TRUE;
}
BOOL WIN_FUNC LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid) {
BOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("LookupPrivilegeValueA(%s, %s, %p)\n", lpSystemName ? lpSystemName : "(null)", lpName ? lpName : "(null)",
lpLuid);
@@ -130,7 +130,7 @@ BOOL WIN_FUNC LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lp
return TRUE;
}
BOOL WIN_FUNC LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid) {
BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("LookupPrivilegeValueW(%p, %p, %p)\n", lpSystemName, lpName, lpLuid);
(void)lpSystemName; // only local lookup supported
@@ -145,7 +145,7 @@ BOOL WIN_FUNC LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID
return TRUE;
}
BOOL WIN_FUNC GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer) {
BOOL WINAPI GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetUserNameA(%p, %p)\n", lpBuffer, pcbBuffer);
if (!pcbBuffer) {
@@ -164,7 +164,7 @@ BOOL WIN_FUNC GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer) {
return TRUE;
}
BOOL WIN_FUNC GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) {
BOOL WINAPI GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetUserNameW(%p, %p)\n", lpBuffer, pcbBuffer);
if (!pcbBuffer) {

View File

@@ -17,11 +17,11 @@ enum SID_NAME_USE : DWORD {
namespace advapi32 {
BOOL WIN_FUNC LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse);
BOOL WIN_FUNC LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid);
BOOL WIN_FUNC LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid);
BOOL WIN_FUNC GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer);
BOOL WIN_FUNC GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
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);
BOOL WINAPI GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
} // namespace advapi32

View File

@@ -60,7 +60,7 @@ DWORD hashSizeForAlgid(ALG_ID algid) {
namespace advapi32 {
BOOL WIN_FUNC CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) {
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: CryptReleaseContext(%p, %u)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(hProv)), dwFlags);
(void)hProv;
@@ -68,7 +68,7 @@ BOOL WIN_FUNC CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) {
return TRUE;
}
BOOL WIN_FUNC CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType,
BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType,
DWORD dwFlags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: CryptAcquireContextW(%p, %p, %p, %u, %u)\n", phProv, pszContainer, pszProvider, dwProvType,
@@ -83,7 +83,7 @@ BOOL WIN_FUNC CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPC
return TRUE;
}
BOOL WIN_FUNC CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) {
BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CryptGenRandom(%p)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(hProv)));
(void)hProv;
@@ -101,7 +101,7 @@ BOOL WIN_FUNC CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) {
return TRUE;
}
BOOL WIN_FUNC CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) {
BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CryptCreateHash(%p, %u, %p, %u, %p)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(hProv)), Algid,
reinterpret_cast<void *>(static_cast<uintptr_t>(hKey)), dwFlags, phHash);
@@ -133,7 +133,7 @@ BOOL WIN_FUNC CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DW
return TRUE;
}
BOOL WIN_FUNC CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags) {
BOOL WINAPI CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CryptHashData(%p, %p, %u, %u)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(hHash)), pbData,
dwDataLen, dwFlags);
@@ -156,7 +156,7 @@ BOOL WIN_FUNC CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLe
return TRUE;
}
BOOL WIN_FUNC CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags) {
BOOL WINAPI CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CryptGetHashParam(%p, %u, %p, %p, %u)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(hHash)),
dwParam, pbData, pdwDataLen, dwFlags);
@@ -234,7 +234,7 @@ BOOL WIN_FUNC CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, D
}
}
BOOL WIN_FUNC CryptDestroyHash(HCRYPTHASH hHash) {
BOOL WINAPI CryptDestroyHash(HCRYPTHASH hHash) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CryptDestroyHash(%p)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(hHash)));
auto *hash = hashObjectFromHandle(hHash);

View File

@@ -16,13 +16,13 @@ constexpr DWORD HP_HASHSIZE = 0x00000004;
namespace advapi32 {
BOOL WIN_FUNC CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags);
BOOL WIN_FUNC CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType,
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags);
BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType,
DWORD dwFlags);
BOOL WIN_FUNC CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
BOOL WIN_FUNC CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash);
BOOL WIN_FUNC CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags);
BOOL WIN_FUNC CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
BOOL WIN_FUNC CryptDestroyHash(HCRYPTHASH hHash);
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);
BOOL WINAPI CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
BOOL WINAPI CryptDestroyHash(HCRYPTHASH hHash);
} // namespace advapi32

View File

@@ -125,7 +125,7 @@ bool isPredefinedKeyHandle(HKEY hKey) {
namespace advapi32 {
LSTATUS WIN_FUNC RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition) {
HOST_CONTEXT_GUARD();
@@ -192,7 +192,7 @@ LSTATUS WIN_FUNC RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LP
return ERROR_SUCCESS;
}
LSTATUS WIN_FUNC RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
LSTATUS WINAPI RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition) {
HOST_CONTEXT_GUARD();
@@ -212,7 +212,7 @@ LSTATUS WIN_FUNC RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPS
lpSecurityAttributes, phkResult, lpdwDisposition);
}
LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) {
LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) {
HOST_CONTEXT_GUARD();
std::string subKeyString = lpSubKey ? wideStringToString(lpSubKey) : std::string("(null)");
DEBUG_LOG("RegOpenKeyExW(%p, %s, %u, 0x%x, %p)\n", hKey, subKeyString.c_str(), ulOptions, samDesired, phkResult);
@@ -269,7 +269,7 @@ LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REG
return ERROR_SUCCESS;
}
LSTATUS WIN_FUNC RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) {
LSTATUS WINAPI RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("RegOpenKeyExA(%p, %s, %u, 0x%x, %p)\n", hKey, lpSubKey ? lpSubKey : "(null)", ulOptions, samDesired,
phkResult);
@@ -282,7 +282,7 @@ LSTATUS WIN_FUNC RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGS
return RegOpenKeyExW(hKey, widePtr, ulOptions, samDesired, phkResult);
}
LSTATUS WIN_FUNC RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LSTATUS WINAPI RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData) {
HOST_CONTEXT_GUARD();
std::string valueName = lpValueName ? wideStringToString(lpValueName) : std::string("(default)");
@@ -304,7 +304,7 @@ LSTATUS WIN_FUNC RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpRese
return ERROR_FILE_NOT_FOUND;
}
LSTATUS WIN_FUNC RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LSTATUS WINAPI RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("RegQueryValueExA(%p, %s, %p, %p, %p, %p)\n", hKey, lpValueName ? lpValueName : "(null)", lpReserved,
@@ -317,7 +317,7 @@ LSTATUS WIN_FUNC RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReser
lpReserved, lpType, lpData, lpcbData);
}
LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LSTATUS WINAPI RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("RegEnumKeyExW(%p, %u, %p, %p, %p, %p, %p, %p)\n", hKey, dwIndex, lpName, lpcchName, lpReserved, lpClass,
@@ -345,7 +345,7 @@ LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD
return ERROR_NO_MORE_ITEMS;
}
LSTATUS WIN_FUNC RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LSTATUS WINAPI RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("RegEnumKeyExA(%p, %u, %p, %p, %p, %p, %p, %p)\n", hKey, dwIndex, lpName, lpcchName, lpReserved, lpClass,
@@ -373,7 +373,7 @@ LSTATUS WIN_FUNC RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD l
return ERROR_NO_MORE_ITEMS;
}
LSTATUS WIN_FUNC RegCloseKey(HKEY hKey) {
LSTATUS WINAPI RegCloseKey(HKEY hKey) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("RegCloseKey(%p)\n", hKey);
if (isPredefinedKeyHandle(hKey)) {

View File

@@ -33,22 +33,22 @@ constexpr REGSAM KEY_WOW64_32KEY = 0x00000200;
namespace advapi32 {
LSTATUS WIN_FUNC RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
LSTATUS WINAPI RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition);
LSTATUS WIN_FUNC RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition);
LSTATUS WIN_FUNC RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
LSTATUS WIN_FUNC RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
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);
LSTATUS WIN_FUNC RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LSTATUS WINAPI RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData);
LSTATUS WIN_FUNC RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LSTATUS WINAPI RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LSTATUS WINAPI RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
LSTATUS WIN_FUNC RegCloseKey(HKEY hKey);
LSTATUS WINAPI RegCloseKey(HKEY hKey);
} // namespace advapi32

View File

@@ -85,6 +85,6 @@ extern const wibo::ModuleStub lib_bcrypt = {
"bcryptprimitives",
nullptr,
},
bcrypt_trampoline_by_name,
bcryptThunkByName,
nullptr,
};

View File

@@ -1,5 +1,8 @@
#include "crt.h"
#include "common.h"
#include "context.h"
#include "crt_trampolines.h"
#include "kernel32/internal.h"
#include "modules.h"
@@ -11,29 +14,6 @@
#include <unistd.h>
#include <vector>
typedef void (*_PVFV)();
typedef int (*_PIFV)();
typedef void (*_invalid_parameter_handler)(const uint16_t *, const uint16_t *, const uint16_t *, unsigned int,
uintptr_t);
extern char **environ;
namespace msvcrt {
int WIN_ENTRY puts(const char *str);
}
typedef enum _crt_app_type {
_crt_unknown_app,
_crt_console_app,
_crt_gui_app,
} _crt_app_type;
typedef enum _crt_argv_mode {
_crt_argv_no_arguments,
_crt_argv_unexpanded_arguments,
_crt_argv_expanded_arguments,
} _crt_argv_mode;
namespace crt {
int _commode = 0;
@@ -42,33 +22,24 @@ int _fmode = 0;
std::vector<_PVFV> atexitFuncs;
_invalid_parameter_handler invalidParameterHandler = nullptr;
void WIN_ENTRY _initterm(const _PVFV *ppfn, const _PVFV *end) {
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
auto *tib = wibo::getThreadTibForHost();
do {
if (_PVFV pfn = *++ppfn) {
DEBUG_LOG("-> calling %p\n", pfn);
{
GUEST_CONTEXT_GUARD(tib);
pfn();
}
call__PVFV(pfn);
}
} while (ppfn < end);
}
int WIN_ENTRY _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
auto *tib = wibo::getThreadTibForHost();
do {
if (_PIFV pfn = *++ppfn) {
DEBUG_LOG("-> calling %p\n", pfn);
int err = 0;
{
GUEST_CONTEXT_GUARD(tib);
err = pfn();
}
int err = call__PIFV(pfn);
if (err)
return err;
}
@@ -77,44 +48,44 @@ int WIN_ENTRY _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
return 0;
}
void WIN_ENTRY _set_app_type(_crt_app_type type) {
void CDECL _set_app_type(_crt_app_type type) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _set_app_type(%i)\n", type);
}
int WIN_ENTRY _set_fmode(int mode) {
int CDECL _set_fmode(int mode) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_set_fmode(%i)\n", mode);
_fmode = mode;
return 0;
}
int *WIN_ENTRY __p__commode() {
int *CDECL __p__commode() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__commode()\n");
return &_commode;
}
int *WIN_ENTRY __p__fmode() {
int *CDECL __p__fmode() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__fmode()\n");
return &_fmode;
}
int WIN_ENTRY _crt_atexit(void (*func)()) {
int CDECL _crt_atexit(void (*func)()) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_crt_atexit(%p)\n", func);
atexitFuncs.push_back(func);
return 0;
}
int WIN_ENTRY _configure_narrow_argv(_crt_argv_mode mode) {
int CDECL _configure_narrow_argv(_crt_argv_mode mode) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _configure_narrow_argv(%i)\n", mode);
return 0;
}
_invalid_parameter_handler WIN_ENTRY _set_invalid_parameter_handler(_invalid_parameter_handler newHandler) {
_invalid_parameter_handler CDECL _set_invalid_parameter_handler(_invalid_parameter_handler newHandler) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _set_invalid_parameter_handler(%p)\n", newHandler);
_invalid_parameter_handler oldHandler = invalidParameterHandler;
@@ -122,213 +93,203 @@ _invalid_parameter_handler WIN_ENTRY _set_invalid_parameter_handler(_invalid_par
return oldHandler;
}
int WIN_ENTRY _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask) {
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _controlfp_s(%p, %u, %u)\n", currentControl, newControl, mask);
return 0;
}
int WIN_ENTRY _configthreadlocale(int per_thread_locale_type) {
int CDECL _configthreadlocale(int per_thread_locale_type) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _configthreadlocale(%i)\n", per_thread_locale_type);
return 0;
}
int WIN_ENTRY _initialize_narrow_environment() {
int CDECL _initialize_narrow_environment() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _initialize_narrow_environment()\n");
return 0;
}
int WIN_ENTRY _set_new_mode(int newhandlermode) {
int CDECL _set_new_mode(int newhandlermode) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _set_new_mode(%i)\n", newhandlermode);
return 0;
}
char **WIN_ENTRY _get_initial_narrow_environment() {
char **CDECL _get_initial_narrow_environment() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_get_initial_narrow_environment()\n");
return environ;
}
char ***WIN_ENTRY __p__environ() {
char ***CDECL __p__environ() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p__environ()\n");
return &environ;
}
char ***WIN_ENTRY __p___argv() {
char ***CDECL __p___argv() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p___argv()\n");
return &wibo::argv;
}
int *WIN_ENTRY __p___argc() {
int *CDECL __p___argc() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__p___argc()\n");
return &wibo::argc;
}
size_t WIN_ENTRY strlen(const char *str) {
SIZE_T CDECL strlen(const char *str) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strlen(%p)\n", str);
return ::strlen(str);
}
int WIN_ENTRY strcmp(const char *lhs, const char *rhs) {
int CDECL strcmp(const char *lhs, const char *rhs) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strcmp(%p, %p)\n", lhs, rhs);
return ::strcmp(lhs, rhs);
}
int WIN_ENTRY strncmp(const char *lhs, const char *rhs, size_t count) {
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strncmp(%p, %p, %zu)\n", lhs, rhs, count);
return ::strncmp(lhs, rhs, count);
}
char *WIN_ENTRY strcpy(char *dest, const char *src) {
char *CDECL strcpy(char *dest, const char *src) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strcpy(%p, %p)\n", dest, src);
return ::strcpy(dest, src);
}
char *WIN_ENTRY strncpy(char *dest, const char *src, size_t count) {
char *CDECL strncpy(char *dest, const char *src, SIZE_T count) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strncpy(%p, %p, %zu)\n", dest, src, count);
return ::strncpy(dest, src, count);
}
const char *WIN_ENTRY strrchr(const char *str, int ch) {
const char *CDECL strrchr(const char *str, int ch) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("strrchr(%p, %i)\n", str, ch);
return ::strrchr(str, ch);
}
void *WIN_ENTRY malloc(size_t size) {
void *CDECL malloc(SIZE_T size) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("malloc(%zu)\n", size);
return ::malloc(size);
}
void *WIN_ENTRY calloc(size_t count, size_t size) {
void *CDECL calloc(SIZE_T count, SIZE_T size) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("calloc(%zu, %zu)\n", count, size);
return ::calloc(count, size);
}
void *WIN_ENTRY realloc(void *ptr, size_t newSize) {
void *CDECL realloc(void *ptr, SIZE_T newSize) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("realloc(%p, %zu)\n", ptr, newSize);
return ::realloc(ptr, newSize);
}
void WIN_ENTRY free(void *ptr) {
void CDECL free(void *ptr) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("free(%p)\n", ptr);
::free(ptr);
}
void *WIN_ENTRY memcpy(void *dest, const void *src, size_t count) {
void *CDECL memcpy(void *dest, const void *src, SIZE_T count) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("memcpy(%p, %p, %zu)\n", dest, src, count);
return std::memcpy(dest, src, count);
}
void *WIN_ENTRY memmove(void *dest, const void *src, size_t count) {
void *CDECL memmove(void *dest, const void *src, SIZE_T count) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("memmove(%p, %p, %zu)\n", dest, src, count);
return std::memmove(dest, src, count);
}
void *WIN_ENTRY memset(void *dest, int ch, size_t count) {
void *CDECL memset(void *dest, int ch, SIZE_T count) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("memset(%p, %i, %zu)\n", dest, ch, count);
return std::memset(dest, ch, count);
}
int WIN_ENTRY memcmp(const void *lhs, const void *rhs, size_t count) {
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count) {
HOST_CONTEXT_GUARD();
VERBOSE_LOG("memcmp(%p, %p, %zu)\n", lhs, rhs, count);
return std::memcmp(lhs, rhs, count);
}
int WIN_ENTRY __setusermatherr(void *handler) {
int CDECL __setusermatherr(void *handler) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: __setusermatherr(%p)\n", handler);
return 0;
}
int WIN_ENTRY _initialize_onexit_table(void *table) {
int CDECL _initialize_onexit_table(void *table) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _initialize_onexit_table(%p)\n", table);
wibo::registerOnExitTable(table);
return 0;
}
int WIN_ENTRY _register_onexit_function(void *table, void (*func)()) {
int CDECL _register_onexit_function(void *table, void (*func)()) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _register_onexit_function(%p, %p)\n", table, func);
wibo::addOnExitFunction(table, func);
return 0;
}
int WIN_ENTRY _execute_onexit_table(void *table) {
int CDECL _execute_onexit_table(void *table) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: _execute_onexit_table(%p)\n", table);
wibo::executeOnExitTable(table);
return 0;
}
void WIN_ENTRY exit(int status) {
void CDECL exit(int status) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("exit(%i)\n", status);
auto *tib = wibo::getThreadTibForHost();
for (auto it = atexitFuncs.rbegin(); it != atexitFuncs.rend(); ++it) {
DEBUG_LOG("Calling atexit function %p\n", *it);
{
GUEST_CONTEXT_GUARD(tib);
(*it)();
}
call__PVFV(*it);
}
kernel32::exitInternal(status);
}
void WIN_ENTRY _cexit() {
void CDECL _cexit() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_cexit()\n");
auto *tib = wibo::getThreadTibForHost();
for (auto it = atexitFuncs.rbegin(); it != atexitFuncs.rend(); ++it) {
DEBUG_LOG("Calling atexit function %p\n", *it);
{
GUEST_CONTEXT_GUARD(tib);
(*it)();
}
call__PVFV(*it);
}
}
void WIN_ENTRY _exit(int status) {
void CDECL _exit(int status) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("_exit(%i)\n", status);
kernel32::exitInternal(status);
}
void WIN_ENTRY abort(void) {
void CDECL abort() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("abort()\n");
std::abort();
}
using signal_handler = void (*)(int);
signal_handler WIN_ENTRY signal(int signum, signal_handler handler) {
signal_handler CDECL signal(int signum, signal_handler handler) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("signal(%i, %p)\n", signum, handler);
return std::signal(signum, handler);
}
void *WIN_ENTRY __acrt_iob_func(unsigned int index) {
void *CDECL __acrt_iob_func(unsigned int index) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("__acrt_iob_func(%u)\n", index);
if (index == 0)
@@ -340,14 +301,14 @@ void *WIN_ENTRY __acrt_iob_func(unsigned int index) {
return nullptr;
}
int WIN_ENTRY __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale,
int CDECL __stdio_common_vfprintf(unsigned long long 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);
return vfprintf(stream, format, args);
}
int WIN_ENTRY __stdio_common_vsprintf(unsigned long long options, char *buffer, size_t len, const char *format,
int CDECL __stdio_common_vsprintf(unsigned long long 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);
@@ -356,113 +317,38 @@ int WIN_ENTRY __stdio_common_vsprintf(unsigned long long options, char *buffer,
int result = vsnprintf(buffer, len, format, args);
if (result < 0)
return -1;
if (len > 0 && static_cast<size_t>(result) >= len)
if (len > 0 && static_cast<SIZE_T>(result) >= len)
return -1;
return result;
}
int WIN_ENTRY qsort(void *base, size_t num, size_t size, int (*compar)(const void *, const void *)) {
static thread_local sort_compare currentCompare = nullptr;
static int doCompare(const void *a, const void *b) { return call_sort_compare(currentCompare, a, b); }
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compar);
::qsort(base, num, size, compar);
DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compare);
currentCompare = compare;
::qsort(base, num, size, doCompare);
}
int CDECL puts(const char *str) {
HOST_CONTEXT_GUARD();
if (!str) {
str = "(null)";
}
DEBUG_LOG("puts(%s)\n", str);
if (std::fputs(str, stdout) < 0)
return EOF;
if (std::fputc('\n', stdout) == EOF)
return EOF;
return 0;
}
} // namespace crt
static void *resolveByName(const char *name) {
if (strcmp(name, "_initterm") == 0)
return (void *)crt::_initterm;
if (strcmp(name, "_initterm_e") == 0)
return (void *)crt::_initterm_e;
if (strcmp(name, "_set_app_type") == 0)
return (void *)crt::_set_app_type;
if (strcmp(name, "_set_fmode") == 0)
return (void *)crt::_set_fmode;
if (strcmp(name, "__p__commode") == 0)
return (void *)crt::__p__commode;
if (strcmp(name, "__p__fmode") == 0)
return (void *)crt::__p__fmode;
if (strcmp(name, "_crt_atexit") == 0)
return (void *)crt::_crt_atexit;
if (strcmp(name, "_configure_narrow_argv") == 0)
return (void *)crt::_configure_narrow_argv;
if (strcmp(name, "_set_invalid_parameter_handler") == 0)
return (void *)crt::_set_invalid_parameter_handler;
if (strcmp(name, "_controlfp_s") == 0)
return (void *)crt::_controlfp_s;
if (strcmp(name, "_configthreadlocale") == 0)
return (void *)crt::_configthreadlocale;
if (strcmp(name, "_initialize_narrow_environment") == 0)
return (void *)crt::_initialize_narrow_environment;
if (strcmp(name, "_set_new_mode") == 0)
return (void *)crt::_set_new_mode;
if (strcmp(name, "_get_initial_narrow_environment") == 0)
return (void *)crt::_get_initial_narrow_environment;
if (strcmp(name, "__p__environ") == 0)
return (void *)crt::__p__environ;
if (strcmp(name, "__p___argv") == 0)
return (void *)crt::__p___argv;
if (strcmp(name, "__p___argc") == 0)
return (void *)crt::__p___argc;
if (strcmp(name, "strlen") == 0)
return (void *)crt::strlen;
if (strcmp(name, "strcmp") == 0)
return (void *)crt::strcmp;
if (strcmp(name, "strncmp") == 0)
return (void *)crt::strncmp;
if (strcmp(name, "strcpy") == 0)
return (void *)crt::strcpy;
if (strcmp(name, "strncpy") == 0)
return (void *)crt::strncpy;
if (strcmp(name, "strrchr") == 0)
return (void *)crt::strrchr;
if (strcmp(name, "malloc") == 0)
return (void *)crt::malloc;
if (strcmp(name, "calloc") == 0)
return (void *)crt::calloc;
if (strcmp(name, "realloc") == 0)
return (void *)crt::realloc;
if (strcmp(name, "free") == 0)
return (void *)crt::free;
if (strcmp(name, "memcpy") == 0)
return (void *)crt::memcpy;
if (strcmp(name, "memmove") == 0)
return (void *)crt::memmove;
if (strcmp(name, "memset") == 0)
return (void *)crt::memset;
if (strcmp(name, "memcmp") == 0)
return (void *)crt::memcmp;
if (strcmp(name, "exit") == 0)
return (void *)crt::exit;
if (strcmp(name, "_cexit") == 0)
return (void *)crt::_cexit;
if (strcmp(name, "_exit") == 0)
return (void *)crt::_exit;
if (strcmp(name, "abort") == 0)
return (void *)crt::abort;
if (strcmp(name, "signal") == 0)
return (void *)crt::signal;
if (strcmp(name, "__acrt_iob_func") == 0)
return (void *)crt::__acrt_iob_func;
if (strcmp(name, "__stdio_common_vfprintf") == 0)
return (void *)crt::__stdio_common_vfprintf;
if (strcmp(name, "__stdio_common_vsprintf") == 0)
return (void *)crt::__stdio_common_vsprintf;
if (strcmp(name, "puts") == 0)
return (void *)msvcrt::puts;
if (strcmp(name, "__setusermatherr") == 0)
return (void *)crt::__setusermatherr;
if (strcmp(name, "_initialize_onexit_table") == 0)
return (void *)crt::_initialize_onexit_table;
if (strcmp(name, "_register_onexit_function") == 0)
return (void *)crt::_register_onexit_function;
if (strcmp(name, "_execute_onexit_table") == 0)
return (void *)crt::_execute_onexit_table;
if (strcmp(name, "qsort") == 0)
return (void *)crt::qsort;
return nullptr;
}
#include "crt_trampolines.h"
extern const wibo::ModuleStub lib_crt = {
(const char *[]){
@@ -477,6 +363,6 @@ extern const wibo::ModuleStub lib_crt = {
"api-ms-win-crt-utility-l1-1-0",
nullptr,
},
resolveByName,
crtThunkByName,
nullptr,
};

76
dll/crt.h Normal file
View File

@@ -0,0 +1,76 @@
#pragma once
#include "types.h"
#include <cstdint>
typedef void (_CC_CDECL *_PVFV)();
typedef int (_CC_CDECL *_PIFV)();
typedef void (_CC_CDECL *_invalid_parameter_handler)(const WCHAR *, const WCHAR *, const WCHAR *, unsigned int, uintptr_t);
typedef enum _crt_app_type {
_crt_unknown_app,
_crt_console_app,
_crt_gui_app,
} _crt_app_type;
typedef enum _crt_argv_mode {
_crt_argv_no_arguments,
_crt_argv_unexpanded_arguments,
_crt_argv_expanded_arguments,
} _crt_argv_mode;
typedef void (_CC_CDECL *signal_handler)(int);
typedef int (_CC_CDECL *sort_compare)(const void *, const void *);
using FILE = struct _IO_FILE;
namespace crt {
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *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)());
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();
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);
char *CDECL strcpy(char *dest, const char *src);
char *CDECL strncpy(char *dest, const char *src, SIZE_T count);
const char *CDECL strrchr(const char *str, int ch);
void *CDECL malloc(SIZE_T size);
void *CDECL calloc(SIZE_T count, SIZE_T size);
void *CDECL realloc(void *ptr, SIZE_T newSize);
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);
void *CDECL memset(void *dest, int ch, SIZE_T count);
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count);
int CDECL __setusermatherr(void *handler);
int CDECL _initialize_onexit_table(void *table);
int CDECL _register_onexit_function(void *table, void (*func)());
int CDECL _execute_onexit_table(void *table);
void CDECL exit(int status);
void CDECL _cexit();
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 __stdio_common_vfprintf(unsigned long long options, FILE *stream, const char *format, void *locale,
va_list args);
int CDECL __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
void *locale, va_list args);
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
int CDECL puts(const char *str);
} // namespace crt

View File

@@ -1,12 +1,12 @@
#include "modules.h"
#include "kernel32.h"
#include "kernel32_trampolines.h"
#include "modules.h"
extern const wibo::ModuleStub lib_kernel32 = {
(const char *[]){
"kernel32",
nullptr,
},
kernel32_trampoline_by_name,
kernel32ThunkByName,
nullptr,
};

29
dll/kernel32.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include "kernel32/debugapi.h" // IWYU pragma: export
#include "kernel32/errhandlingapi.h" // IWYU pragma: export
#include "kernel32/fibersapi.h" // IWYU pragma: export
#include "kernel32/fileapi.h" // IWYU pragma: export
#include "kernel32/handleapi.h" // IWYU pragma: export
#include "kernel32/heapapi.h" // IWYU pragma: export
#include "kernel32/interlockedapi.h" // IWYU pragma: export
#include "kernel32/ioapiset.h" // IWYU pragma: export
#include "kernel32/libloaderapi.h" // IWYU pragma: export
#include "kernel32/memoryapi.h" // IWYU pragma: export
#include "kernel32/namedpipeapi.h" // IWYU pragma: export
#include "kernel32/processenv.h" // IWYU pragma: export
#include "kernel32/processthreadsapi.h" // IWYU pragma: export
#include "kernel32/profileapi.h" // IWYU pragma: export
#include "kernel32/stringapiset.h" // IWYU pragma: export
#include "kernel32/synchapi.h" // IWYU pragma: export
#include "kernel32/sysinfoapi.h" // IWYU pragma: export
#include "kernel32/timezoneapi.h" // IWYU pragma: export
#include "kernel32/winbase.h" // IWYU pragma: export
#include "kernel32/wincon.h" // IWYU pragma: export
#include "kernel32/winnls.h" // IWYU pragma: export
#include "kernel32/winnt.h" // IWYU pragma: export
#include "kernel32/wow64apiset.h" // IWYU pragma: export
#ifndef WIBO_CODEGEN
#include "kernel32_trampolines.h" // IWYU pragma: export
#endif

View File

@@ -14,34 +14,22 @@ UINT g_processErrorMode = 0;
namespace kernel32 {
DWORD getLastError() { return wibo::getThreadTibForHost()->LastErrorValue; }
DWORD getLastError() { return currentThreadTeb->LastErrorValue; }
void setLastError(DWORD error) { wibo::getThreadTibForHost()->LastErrorValue = error; }
void setLastError(DWORD error) { currentThreadTeb->LastErrorValue = error; }
void setLastErrorFromErrno() { setLastError(wibo::winErrorFromErrno(errno)); }
DWORD WINAPI GetLastError() {
#ifndef NDEBUG
{
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetLastError() -> %u\n", getLastError());
}
#endif
// In guest context, fetch via TIB
DWORD err;
__asm__ __volatile__("movl %%fs:%c1, %0" : "=r"(err) : "i"(offsetof(TEB, LastErrorValue)));
return err;
return currentThreadTeb->LastErrorValue;
}
void WINAPI SetLastError(DWORD dwErrCode) {
#ifndef NDEBUG
{
HOST_CONTEXT_GUARD();
DEBUG_LOG("SetLastError(%u)\n", dwErrCode);
}
#endif
// In guest context, store via TIB
__asm__ __volatile__("movl %0, %%fs:%c1" : : "r"(dwErrCode), "i"(offsetof(TEB, LastErrorValue)) : "memory");
currentThreadTeb->LastErrorValue = dwErrCode;
}
void WINAPI RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,

View File

@@ -22,8 +22,8 @@ struct EXCEPTION_POINTERS {
};
using PEXCEPTION_POINTERS = EXCEPTION_POINTERS *;
using PVECTORED_EXCEPTION_HANDLER = LONG(WIN_FUNC *)(PEXCEPTION_POINTERS ExceptionInfo);
using LPTOP_LEVEL_EXCEPTION_FILTER = LONG(WIN_FUNC *)(PEXCEPTION_POINTERS ExceptionInfo);
typedef LONG (_CC_STDCALL *PVECTORED_EXCEPTION_HANDLER)(PEXCEPTION_POINTERS ExceptionInfo);
typedef LONG (_CC_STDCALL *LPTOP_LEVEL_EXCEPTION_FILTER)(PEXCEPTION_POINTERS ExceptionInfo);
constexpr LONG EXCEPTION_CONTINUE_EXECUTION = static_cast<LONG>(-1);
constexpr LONG EXCEPTION_CONTINUE_SEARCH = 0;

View File

@@ -2,7 +2,7 @@
#include "types.h"
using PFLS_CALLBACK_FUNCTION = void (*)(void *);
typedef void (_CC_STDCALL *PFLS_CALLBACK_FUNCTION)(void *);
constexpr DWORD FLS_OUT_OF_INDEXES = 0xFFFFFFFF;
namespace kernel32 {

View File

@@ -614,8 +614,7 @@ UINT WINAPI GetDriveTypeW(LPCWSTR lpRootPathName) {
BOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize) {
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: GetVolumeInformationA(%s)\n", lpRootPathName ? lpRootPathName : "(null)");
if (lpVolumeNameBuffer && nVolumeNameSize > 0) {
@@ -643,8 +642,7 @@ BOOL WINAPI GetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffe
BOOL WINAPI GetVolumeInformationW(LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize) {
LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: GetVolumeInformationW(%p)\n", lpRootPathName);
if (lpVolumeNameBuffer && nVolumeNameSize > 0) {
@@ -1239,7 +1237,7 @@ BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARG
// TODO access check
std::lock_guard lk(file->m);
off_t position = 0;
off_t offset = static_cast<off_t>(liDistanceToMove);
off_t offset = static_cast<off_t>(liDistanceToMove.QuadPart);
if (dwMoveMethod == FILE_BEGIN) {
position = offset;
} else if (dwMoveMethod == FILE_CURRENT) {
@@ -1265,7 +1263,7 @@ BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARG
return FALSE;
}
if (lpNewFilePointer) {
*lpNewFilePointer = static_cast<LARGE_INTEGER>(position);
lpNewFilePointer->QuadPart = position;
}
return TRUE;
}

View File

@@ -6,6 +6,8 @@
#include "files.h"
#include "handles.h"
#include "internal.h"
#include "kernel32.h"
#include "kernel32_trampolines.h"
#include "modules.h"
#include "processes.h"
#include "strutil.h"
@@ -107,7 +109,7 @@ void threadCleanup(void *param) {
}
g_currentThreadObject = nullptr;
wibo::notifyDllThreadDetach();
wibo::setThreadTibForHost(nullptr);
currentThreadTeb = nullptr;
// TODO: mark mutexes owned by this thread as abandoned
obj->cv.notify_all();
obj->notifyWaiters(false);
@@ -124,27 +126,13 @@ void *threadTrampoline(void *param) {
g_currentThreadObject = data.obj;
// Install TIB
TEB *threadTib = nullptr;
uint16_t previousFs = 0;
uint16_t previousGs = 0;
if (wibo::tibSelector) {
asm volatile("mov %%fs, %0" : "=r"(previousFs));
asm volatile("mov %%gs, %0" : "=r"(previousGs));
threadTib = wibo::allocateTib();
if (threadTib) {
TEB *threadTib = wibo::allocateTib();
wibo::initializeTibStackInfo(threadTib);
if (wibo::installTibForCurrentThread(threadTib)) {
threadTib->hostFsSelector = previousFs;
threadTib->hostGsSelector = previousGs;
threadTib->hostSegmentsValid = 1;
wibo::setThreadTibForHost(threadTib);
} else {
if (!wibo::installTibForCurrentThread(threadTib)) {
fprintf(stderr, "!!! Failed to install TIB for new thread\n");
wibo::destroyTib(threadTib);
threadTib = nullptr;
}
}
}
// Wait until resumed (if suspended at start)
{
@@ -161,7 +149,7 @@ void *threadTrampoline(void *param) {
DWORD result = 0;
if (data.entry) {
GUEST_CONTEXT_GUARD(threadTib);
result = data.entry(data.userData);
result = call_LPTHREAD_START_ROUTINE(data.entry, data.userData);
}
DEBUG_LOG("Thread exiting with code %u\n", result);
{
@@ -220,8 +208,7 @@ HANDLE WINAPI GetCurrentThread() {
return pseudoHandle;
}
BOOL WINAPI GetProcessAffinityMask(HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask,
PDWORD_PTR lpSystemAffinityMask) {
BOOL WINAPI GetProcessAffinityMask(HANDLE hProcess, PDWORD_PTR lpProcessAffinityMask, PDWORD_PTR lpSystemAffinityMask) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetProcessAffinityMask(%p, %p, %p)\n", hProcess, lpProcessAffinityMask, lpSystemAffinityMask);
if (!lpProcessAffinityMask || !lpSystemAffinityMask) {

View File

@@ -62,7 +62,7 @@ using LPSTARTUPINFOW = STARTUPINFOW *;
constexpr DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFFu;
constexpr DWORD NORMAL_PRIORITY_CLASS = 0x00000020;
typedef DWORD(WIN_FUNC *LPTHREAD_START_ROUTINE)(LPVOID);
typedef DWORD(_CC_STDCALL *LPTHREAD_START_ROUTINE)(LPVOID);
namespace kernel32 {

View File

@@ -14,7 +14,7 @@ BOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount) {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*lpPerformanceCount = 0;
lpPerformanceCount->QuadPart = 0;
return TRUE;
}
@@ -25,7 +25,7 @@ BOOL WINAPI QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency) {
kernel32::setLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*lpFrequency = 1;
lpFrequency->QuadPart = 1;
return TRUE;
}

View File

@@ -7,6 +7,7 @@
#include "internal.h"
#include "modules.h"
#include "strutil.h"
#include "types.h"
#include <algorithm>
#include <cassert>
@@ -1141,8 +1142,8 @@ BOOL WINAPI GetDiskFreeSpaceW(LPCWSTR lpRootPathName, LPDWORD lpSectorsPerCluste
lpNumberOfFreeClusters, lpTotalNumberOfClusters);
}
BOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName, uint64_t *lpFreeBytesAvailableToCaller,
uint64_t *lpTotalNumberOfBytes, uint64_t *lpTotalNumberOfFreeBytes) {
BOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetDiskFreeSpaceExA(%s)\n", lpDirectoryName ? lpDirectoryName : "(null)");
struct statvfs buf{};
@@ -1161,13 +1162,13 @@ BOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName, uint64_t *lpFreeBytesAva
uint64_t totalFree = static_cast<uint64_t>(buf.f_bfree) * blockSize;
if (lpFreeBytesAvailableToCaller) {
*lpFreeBytesAvailableToCaller = freeToCaller;
lpFreeBytesAvailableToCaller->QuadPart = freeToCaller;
}
if (lpTotalNumberOfBytes) {
*lpTotalNumberOfBytes = totalBytes;
lpTotalNumberOfBytes->QuadPart = totalBytes;
}
if (lpTotalNumberOfFreeBytes) {
*lpTotalNumberOfFreeBytes = totalFree;
lpTotalNumberOfFreeBytes->QuadPart = totalFree;
}
DEBUG_LOG("\t-> host %s, free %llu, total %llu, total free %llu\n", resolvedPath.c_str(),
@@ -1176,8 +1177,8 @@ BOOL WINAPI GetDiskFreeSpaceExA(LPCSTR lpDirectoryName, uint64_t *lpFreeBytesAva
return TRUE;
}
BOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName, uint64_t *lpFreeBytesAvailableToCaller,
uint64_t *lpTotalNumberOfBytes, uint64_t *lpTotalNumberOfFreeBytes) {
BOOL WINAPI GetDiskFreeSpaceExW(LPCWSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetDiskFreeSpaceExW -> ");
std::string directoryName = wideStringToString(lpDirectoryName);

View File

@@ -24,7 +24,7 @@ struct CONSOLE_SCREEN_BUFFER_INFO {
struct INPUT_RECORD;
using PHANDLER_ROUTINE = BOOL(WIN_FUNC *)(DWORD CtrlType);
typedef BOOL (_CC_STDCALL *PHANDLER_ROUTINE)(DWORD CtrlType);
namespace kernel32 {

View File

@@ -12,7 +12,7 @@ struct CPINFO {
};
using LPCPINFO = CPINFO *;
using LOCALE_ENUMPROCA = BOOL(WIN_FUNC *)(LPSTR);
typedef BOOL (_CC_STDCALL *LOCALE_ENUMPROCA)(LPSTR);
namespace kernel32 {

View File

@@ -1,28 +1,34 @@
#include "lmgr.h"
#include "common.h"
#include "context.h"
#include "modules.h"
namespace lmgr {
int WIN_ENTRY lp_checkout(int a, int b, const char* c, const char* d, int e, const char* f, int* out) {
int CDECL lp_checkout(int a, int b, LPCSTR c, LPCSTR d, int e, LPCSTR f, int *out) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("lp_checkout(%d, %d, %s, %s, %d, %s)\n", a, b, c, d, e, f);
*out = 1234;
return 0;
}
}
int WIN_ENTRY lp_checkin() {
int CDECL lp_checkin() {
HOST_CONTEXT_GUARD();
DEBUG_LOG("lp_checkin()\n");
return 0;
}
}
} // namespace lmgr
#include "lmgr_trampolines.h"
static void *resolveByOrdinal(uint16_t ordinal) {
switch (ordinal) {
case 189:
return (void*)lmgr::lp_checkin;
return (void *)thunk_lmgr_lp_checkin;
case 190:
return (void*)lmgr::lp_checkout;
return (void *)thunk_lmgr_lp_checkout;
}
return 0;
}

10
dll/lmgr.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "types.h"
namespace lmgr {
int CDECL lp_checkout(int a, int b, LPCSTR c, LPCSTR d, int e, LPCSTR f, int *out);
int CDECL lp_checkin();
} // namespace lmgr

View File

@@ -1,13 +1,13 @@
#include "mscoree.h"
#include "common.h"
#include "context.h"
#include "kernel32/internal.h"
#include "modules.h"
#include <cstring>
namespace mscoree {
void WIN_FUNC CorExitProcess(int exitCode) {
VOID WINAPI CorExitProcess(int exitCode) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("CorExitProcess(%i)\n", exitCode);
kernel32::exitInternal(exitCode);
@@ -15,17 +15,13 @@ void WIN_FUNC CorExitProcess(int exitCode) {
} // namespace mscoree
static void *resolveByName(const char *name) {
if (strcmp(name, "CorExitProcess") == 0)
return (void *)mscoree::CorExitProcess;
return nullptr;
}
#include "mscoree_trampolines.h"
extern const wibo::ModuleStub lib_mscoree = {
(const char *[]){
"mscoree",
nullptr,
},
resolveByName,
mscoreeThunkByName,
nullptr,
};

9
dll/mscoree.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include "types.h"
namespace mscoree {
VOID WINAPI CorExitProcess(int exitCode);
} // namespace mscoree

File diff suppressed because it is too large Load Diff

234
dll/msvcrt.h Normal file
View File

@@ -0,0 +1,234 @@
#pragma once
#include "types.h"
#include <cstdint>
using TIME_T = int;
using WINT_T = unsigned short;
typedef void (_CC_CDECL *_PVFV)();
typedef int (_CC_CDECL *_PIFV)();
using _onexit_t = _PIFV;
struct _utimbuf {
long actime;
long modtime;
};
struct _timeb {
TIME_T time;
unsigned short millitm;
short timezone;
short dstflag;
};
typedef void (_CC_CDECL *signal_handler)(int);
using FILE = struct _IO_FILE;
struct IOBProxy {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
struct lconv;
namespace msvcrt {
IOBProxy *CDECL __iob_func();
IOBProxy *CDECL __p__iob();
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();
unsigned int *CDECL __p___mb_cur_max();
int CDECL _setmbcp(int codepage);
unsigned char *CDECL __p__mbctype();
unsigned short **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);
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
_PIFV CDECL _onexit(_PIFV func);
int CDECL __wgetmainargs(int *wargc, uint16_t ***wargv, uint16_t ***wenv, int doWildcard, int *startInfo);
int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo);
char *CDECL getenv(const char *varname);
char ***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);
int CDECL _ismbblead(unsigned int c);
int CDECL _ismbbtrail(unsigned int c);
int CDECL _ismbcspace(unsigned int c);
void CDECL _mbccpy(unsigned char *dest, const unsigned char *src);
unsigned char *CDECL _mbsinc(const unsigned char *str);
unsigned char *CDECL _mbsdec(const unsigned char *start, const unsigned char *current);
unsigned int CDECL _mbclen(const unsigned char *str);
int CDECL _mbscmp(const unsigned char *lhs, const unsigned char *rhs);
int CDECL _mbsicmp(const unsigned char *lhs, const unsigned char *rhs);
unsigned char *CDECL _mbsstr(const unsigned char *haystack, const unsigned char *needle);
unsigned char *CDECL _mbschr(const unsigned char *str, unsigned int ch);
unsigned char *CDECL _mbsrchr(const unsigned char *str, unsigned int ch);
unsigned char *CDECL _mbslwr(unsigned char *str);
unsigned char *CDECL _mbsupr(unsigned char *str);
unsigned char *CDECL _mbsinc_l(const unsigned char *str, void *);
unsigned char *CDECL _mbsdec_l(const unsigned char *start, const unsigned char *current, void *locale);
int CDECL _mbsncmp(const unsigned char *lhs, const unsigned char *rhs, SIZE_T count);
SIZE_T CDECL _mbsspn(const unsigned char *str, const unsigned char *set);
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);
int CDECL _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, ...);
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);
int CDECL _unlink(const char *path);
int CDECL _utime(const char *path, const _utimbuf *times);
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);
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);
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);
char *CDECL _mktemp(char *templateName);
int CDECL _except_handler3(void *record, void *frame, void *context, void *dispatch);
int CDECL getchar();
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(uint16_t **buffer, SIZE_T *numberOfElements, const uint16_t *varname);
int CDECL _wgetenv_s(SIZE_T *pReturnValue, uint16_t *buffer, SIZE_T numberOfElements, const uint16_t *varname);
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);
void CDECL _exit(int status);
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);
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, _PVFV **pbegin, _PVFV **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, int (*compar)(const void *, const void *));
int CDECL fflush(FILE *stream);
int CDECL vfwprintf(FILE *stream, const uint16_t *format, va_list args);
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 feof(FILE *stream);
int CDECL fputws(const uint16_t *str, FILE *stream);
int CDECL _cputws(const uint16_t *string);
uint16_t *CDECL fgetws(uint16_t *buffer, int size, FILE *stream);
WINT_T CDECL fgetwc(FILE *stream);
int CDECL _wfopen_s(FILE **stream, const uint16_t *filename, const uint16_t *mode);
int CDECL _wcsicmp(const uint16_t *lhs, const uint16_t *rhs);
int CDECL _wmakepath_s(uint16_t *path, SIZE_T sizeInWords, const uint16_t *drive, const uint16_t *dir,
const uint16_t *fname, const uint16_t *ext);
int CDECL _wputenv_s(const uint16_t *varname, const uint16_t *value);
unsigned long CDECL wcsspn(const uint16_t *str1, const uint16_t *str2);
long CDECL _wtol(const uint16_t *str);
int CDECL _wcsupr_s(uint16_t *str, SIZE_T size);
int CDECL _wcslwr_s(uint16_t *str, SIZE_T size);
WINT_T CDECL towlower(WINT_T ch);
unsigned int CDECL _mbctolower(unsigned int ch);
int CDECL toupper(int ch);
int CDECL tolower(int ch);
int CDECL _ftime64_s(void *timeb);
int CDECL _crt_debugger_hook(int value);
int CDECL _configthreadlocale(int mode);
void CDECL __setusermatherr(void *handler);
void CDECL _cexit();
int CDECL vfprintf(FILE *stream, const char *format, va_list args);
int CDECL_NO_CONV fprintf(FILE *stream, const char *format, ...);
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);
char *CDECL strchr(const char *str, int character);
struct lconv *CDECL localeconv();
signal_handler CDECL signal(int sig, signal_handler handler);
SIZE_T CDECL wcslen(const uint16_t *str);
void CDECL abort();
int CDECL atoi(const char *str);
int CDECL _amsg_exit(int reason);
void CDECL _invoke_watson(const uint16_t *, const uint16_t *, const uint16_t *, unsigned int, uintptr_t);
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(uint16_t **pValue);
char **CDECL __p__pgmptr();
int CDECL _wsplitpath_s(const uint16_t *path, uint16_t *drive, SIZE_T driveNumberOfElements, uint16_t *dir,
SIZE_T dirNumberOfElements, uint16_t *fname, SIZE_T nameNumberOfElements, uint16_t *ext,
SIZE_T extNumberOfElements);
int CDECL wcscat_s(uint16_t *strDestination, SIZE_T numberOfElements, const uint16_t *strSource);
uint16_t *CDECL _wcsdup(const uint16_t *strSource);
int CDECL _waccess_s(const uint16_t *path, int mode);
void *CDECL memset(void *s, int c, SIZE_T n);
int CDECL wcsncpy_s(uint16_t *strDest, SIZE_T numberOfElements, const uint16_t *strSource, SIZE_T count);
int CDECL wcsncat_s(uint16_t *strDest, SIZE_T numberOfElements, const uint16_t *strSource, SIZE_T count);
int CDECL _itow_s(int value, uint16_t *buffer, SIZE_T size, int radix);
int CDECL _wtoi(const uint16_t *str);
int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix);
int CDECL wcscpy_s(uint16_t *dest, SIZE_T dest_size, const uint16_t *src);
int CDECL_NO_CONV swprintf_s(uint16_t *buffer, SIZE_T sizeOfBuffer, const uint16_t *format, ...);
int CDECL_NO_CONV swscanf_s(const uint16_t *buffer, const uint16_t *format, ...);
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 uint16_t *string1, const uint16_t *string2, SIZE_T count);
int CDECL_NO_CONV _vswprintf_c_l(uint16_t *buffer, SIZE_T size, const uint16_t *format, ...);
const uint16_t *CDECL wcsstr(const uint16_t *dest, const uint16_t *src);
int CDECL iswspace(uint32_t w);
int CDECL iswdigit(uint32_t w);
const uint16_t *CDECL wcschr(const uint16_t *str, uint16_t c);
const uint16_t *CDECL wcsrchr(const uint16_t *str, uint16_t c);
unsigned long CDECL wcstoul(const uint16_t *strSource, uint16_t **endptr, int base);
FILE *CDECL _wfsopen(const uint16_t *filename, const uint16_t *mode, int shflag);
int CDECL puts(const char *str);
int CDECL fclose(FILE *stream);
int CDECL _flushall();
int *CDECL _errno();
intptr_t CDECL _wspawnvp(int mode, const uint16_t *cmdname, const uint16_t *const *argv);
intptr_t CDECL _spawnvp(int mode, const char *cmdname, const char *const *argv);
int CDECL _wunlink(const uint16_t *filename);
uint16_t *CDECL _wfullpath(uint16_t *absPath, const uint16_t *relPath, SIZE_T maxLength);
} // namespace msvcrt

View File

@@ -1,3 +1,5 @@
#include "ntdll.h"
#include "common.h"
#include "context.h"
#include "errors.h"
@@ -8,6 +10,7 @@
#include "modules.h"
#include "processes.h"
#include "strutil.h"
#include "types.h"
#include <cerrno>
#include <cstring>
@@ -17,24 +20,8 @@
#include <optional>
using PIO_APC_ROUTINE = void *;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
namespace {
enum PROCESSINFOCLASS {
ProcessBasicInformation = 0,
ProcessWow64Information = 26,
ProcessImageFileName = 27,
};
struct PROCESS_BASIC_INFORMATION {
NTSTATUS ExitStatus;
PEB *PebBaseAddress;
@@ -53,17 +40,6 @@ struct ProcessHandleDetails {
constexpr LONG kDefaultBasePriority = 8;
struct RTL_OSVERSIONINFOW {
ULONG dwOSVersionInfoSize;
ULONG dwMajorVersion;
ULONG dwMinorVersion;
ULONG dwBuildNumber;
ULONG dwPlatformId;
WCHAR szCSDVersion[128];
};
using PRTL_OSVERSIONINFOW = RTL_OSVERSIONINFOW *;
struct RTL_OSVERSIONINFOEXW : RTL_OSVERSIONINFOW {
WORD wServicePackMajor;
WORD wServicePackMinor;
@@ -124,15 +100,15 @@ BOOL WIN_FUNC ResetEvent(HANDLE hEvent);
namespace ntdll {
constexpr LARGE_INTEGER FILE_WRITE_TO_END_OF_FILE = static_cast<LARGE_INTEGER>(-1);
constexpr LARGE_INTEGER FILE_USE_FILE_POINTER_POSITION = static_cast<LARGE_INTEGER>(-2);
constexpr LARGE_INTEGER FILE_WRITE_TO_END_OF_FILE = {.QuadPart = -1};
constexpr LARGE_INTEGER FILE_USE_FILE_POINTER_POSITION = {.QuadPart = -2};
void *WIN_ENTRY memset(void *dest, int ch, size_t count) {
PVOID CDECL memset(PVOID dest, int ch, SIZE_T count) {
VERBOSE_LOG("ntdll::memset(%p, %i, %zu)\n", dest, ch, count);
return std::memset(dest, ch, count);
}
NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
NTSTATUS WINAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset,
PULONG Key) {
HOST_CONTEXT_GUARD();
@@ -156,13 +132,13 @@ NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Ap
bool useOverlapped = file->overlapped;
bool useCurrentFilePosition = (ByteOffset == nullptr);
if (!useCurrentFilePosition && *ByteOffset == FILE_USE_FILE_POINTER_POSITION) {
if (!useCurrentFilePosition && ByteOffset->QuadPart == FILE_USE_FILE_POINTER_POSITION.QuadPart) {
useCurrentFilePosition = true;
}
std::optional<off_t> offset;
if (!useCurrentFilePosition) {
offset = static_cast<off_t>(*ByteOffset);
offset = static_cast<off_t>(ByteOffset->QuadPart);
}
if (useOverlapped && useCurrentFilePosition) {
@@ -202,7 +178,7 @@ NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Ap
return status;
}
NTSTATUS WIN_FUNC NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
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) {
HOST_CONTEXT_GUARD();
@@ -227,16 +203,16 @@ NTSTATUS WIN_FUNC NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE A
bool useCurrentFilePosition = (ByteOffset == nullptr);
bool writeToEndOfFile = false;
if (ByteOffset) {
if (*ByteOffset == FILE_USE_FILE_POINTER_POSITION) {
if (ByteOffset->QuadPart == FILE_USE_FILE_POINTER_POSITION.QuadPart) {
useCurrentFilePosition = true;
} else if (*ByteOffset == FILE_WRITE_TO_END_OF_FILE) {
} else if (ByteOffset->QuadPart == FILE_WRITE_TO_END_OF_FILE.QuadPart) {
writeToEndOfFile = true;
}
}
std::optional<off_t> offset;
if (!useCurrentFilePosition && !writeToEndOfFile) {
offset = static_cast<off_t>(*ByteOffset);
offset = static_cast<off_t>(ByteOffset->QuadPart);
}
if (useOverlapped && useCurrentFilePosition) {
@@ -286,7 +262,7 @@ NTSTATUS WIN_FUNC NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE A
return status;
}
NTSTATUS WIN_FUNC NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits,
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *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,
@@ -325,7 +301,7 @@ NTSTATUS WIN_FUNC NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddre
return STATUS_SUCCESS;
}
NTSTATUS WIN_FUNC NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
ULONG NewAccessProtection, PULONG OldAccessProtection) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("NtProtectVirtualMemory(%p, %p, %p, %lu, %p) ", ProcessHandle, BaseAddress, NumberOfBytesToProtect,
@@ -366,7 +342,7 @@ NTSTATUS WIN_FUNC NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddres
return STATUS_SUCCESS;
}
NTSTATUS WIN_FUNC RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation) {
NTSTATUS WINAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("RtlGetVersion(%p) ", lpVersionInformation);
if (!lpVersionInformation) {
@@ -396,7 +372,7 @@ NTSTATUS WIN_FUNC RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation) {
return STATUS_SUCCESS;
}
NTSTATUS WIN_FUNC NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation, ULONG ProcessInformationLength,
PULONG ReturnLength) {
HOST_CONTEXT_GUARD();
@@ -501,29 +477,13 @@ NTSTATUS WIN_FUNC NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLA
} // namespace ntdll
static void *resolveByName(const char *name) {
if (strcmp(name, "NtReadFile") == 0)
return (void *)ntdll::NtReadFile;
if (strcmp(name, "NtWriteFile") == 0)
return (void *)ntdll::NtWriteFile;
if (strcmp(name, "NtAllocateVirtualMemory") == 0)
return (void *)ntdll::NtAllocateVirtualMemory;
if (strcmp(name, "NtProtectVirtualMemory") == 0)
return (void *)ntdll::NtProtectVirtualMemory;
if (strcmp(name, "RtlGetVersion") == 0)
return (void *)ntdll::RtlGetVersion;
if (strcmp(name, "NtQueryInformationProcess") == 0)
return (void *)ntdll::NtQueryInformationProcess;
if (strcmp(name, "memset") == 0)
return (void *)ntdll::memset;
return nullptr;
}
#include "ntdll_trampolines.h"
extern const wibo::ModuleStub lib_ntdll = {
(const char *[]){
"ntdll",
nullptr,
},
resolveByName,
ntdllThunkByName,
nullptr,
};

49
dll/ntdll.h Normal file
View File

@@ -0,0 +1,49 @@
#pragma once
#include "types.h"
using PIO_APC_ROUTINE = PVOID;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
enum PROCESSINFOCLASS {
ProcessBasicInformation = 0,
ProcessWow64Information = 26,
ProcessImageFileName = 27,
};
struct RTL_OSVERSIONINFOW {
ULONG dwOSVersionInfoSize;
ULONG dwMajorVersion;
ULONG dwMinorVersion;
ULONG dwBuildNumber;
ULONG dwPlatformId;
WCHAR szCSDVersion[128];
};
using PRTL_OSVERSIONINFOW = RTL_OSVERSIONINFOW *;
namespace ntdll {
PVOID CDECL memset(PVOID dest, int ch, SIZE_T count);
NTSTATUS WINAPI NtReadFile(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 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,
ULONG NewAccessProtection, PULONG OldAccessProtection);
NTSTATUS WINAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
} // namespace ntdll

View File

@@ -1,3 +1,5 @@
#include "ole32.h"
#include "common.h"
#include "context.h"
#include "errors.h"
@@ -108,15 +110,16 @@ HRESULT parseGuidString(const uint16_t *first, const uint16_t *last, GUID &out)
} // namespace
namespace ole32 {
int WIN_FUNC CoInitialize(void *pvReserved) {
HRESULT WINAPI CoInitialize(LPVOID pvReserved) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: CoInitialize(%p)\n", pvReserved);
(void)pvReserved;
return 0; // S_OK
}
int WIN_FUNC CoCreateInstance(const GUID *rclsid, void *pUnkOuter, unsigned int dwClsContext, const GUID *riid,
void **ppv) {
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid,
LPVOID *ppv) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: CoCreateInstance(0x%x, %p, %d, 0x%x, %p)\n", rclsid->Data1, pUnkOuter, dwClsContext, riid->Data1,
*ppv);
@@ -126,7 +129,7 @@ int WIN_FUNC CoCreateInstance(const GUID *rclsid, void *pUnkOuter, unsigned int
return 0x80004003; // E_POINTER
}
int WIN_FUNC CLSIDFromString(const uint16_t *lpsz, GUID *pclsid) {
HRESULT WINAPI CLSIDFromString(LPCWSTR lpsz, GUID *pclsid) {
HOST_CONTEXT_GUARD();
if (pclsid == nullptr) {
@@ -150,23 +153,16 @@ int WIN_FUNC CLSIDFromString(const uint16_t *lpsz, GUID *pclsid) {
return parseGuidString(begin, end, *pclsid);
}
} // namespace ole32
static void *resolveByName(const char *name) {
if (strcmp(name, "CoInitialize") == 0)
return (void *)ole32::CoInitialize;
if (strcmp(name, "CoCreateInstance") == 0)
return (void *)ole32::CoCreateInstance;
if (strcmp(name, "CLSIDFromString") == 0)
return (void *)ole32::CLSIDFromString;
return nullptr;
}
#include "ole32_trampolines.h"
extern const wibo::ModuleStub lib_ole32 = {
(const char *[]){
"ole32",
nullptr,
},
resolveByName,
ole32ThunkByName,
nullptr,
};

11
dll/ole32.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include "types.h"
namespace ole32 {
HRESULT WINAPI CoInitialize(LPVOID pvReserved);
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, LPVOID *ppv);
HRESULT WINAPI CLSIDFromString(LPCWSTR lpsz, GUID *pclsid);
} // namespace ole32

View File

@@ -1,3 +1,5 @@
#include "rpcrt4.h"
#include "common.h"
#include "context.h"
#include "modules.h"
@@ -11,15 +13,6 @@
namespace {
using RPC_STATUS = unsigned long;
using RPC_WSTR = uint16_t *;
using RPC_BINDING_HANDLE = void *;
using RPC_AUTH_IDENTITY_HANDLE = void *;
using LONG_PTR = intptr_t;
using PMIDL_STUB_DESC = void *;
using PFORMAT_STRING = unsigned char *;
using PRPC_MESSAGE = void *;
constexpr RPC_STATUS RPC_S_OK = 0;
constexpr RPC_STATUS RPC_S_INVALID_STRING_BINDING = 1700;
constexpr RPC_STATUS RPC_S_INVALID_BINDING = 1702;
@@ -27,14 +20,6 @@ constexpr RPC_STATUS RPC_S_SERVER_UNAVAILABLE = 1722;
constexpr RPC_STATUS RPC_S_INVALID_ARG = 87;
constexpr RPC_STATUS RPC_S_OUT_OF_MEMORY = 14;
struct RPC_SECURITY_QOS {
unsigned long Version = 0;
unsigned long Capabilities = 0;
unsigned long IdentityTracking = 0;
unsigned long ImpersonationType = 0;
void *AdditionalSecurityInfo = nullptr;
};
struct BindingComponents {
std::u16string objectUuid;
std::u16string protocolSequence;
@@ -57,11 +42,6 @@ struct BindingHandleData {
bool serverReachable = false;
};
union CLIENT_CALL_RETURN {
void *Pointer;
LONG_PTR Simple;
};
std::unordered_map<RPC_WSTR, BindingComponents> g_stringBindings;
std::unordered_map<RPC_BINDING_HANDLE, std::unique_ptr<BindingHandleData>> g_bindingHandles;
@@ -128,10 +108,10 @@ BindingHandleData *getBinding(RPC_BINDING_HANDLE handle) {
} // namespace
extern "C" {
namespace rpcrt4 {
RPC_STATUS WIN_FUNC RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr,
RPC_WSTR endpoint, RPC_WSTR options, RPC_WSTR *stringBinding) {
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
RPC_WSTR options, RPC_WSTR *stringBinding) {
HOST_CONTEXT_GUARD();
BindingComponents components;
components.objectUuid = toU16(objUuid);
@@ -161,7 +141,7 @@ RPC_STATUS WIN_FUNC RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq,
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding) {
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding) {
HOST_CONTEXT_GUARD();
if (!binding) {
return RPC_S_INVALID_ARG;
@@ -185,9 +165,8 @@ RPC_STATUS WIN_FUNC RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BIN
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR serverPrincName,
unsigned long authnLevel, unsigned long authnSvc,
RPC_AUTH_IDENTITY_HANDLE authIdentity, unsigned long authzSvc,
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) {
HOST_CONTEXT_GUARD();
BindingHandleData *data = getBinding(binding);
@@ -210,7 +189,7 @@ RPC_STATUS WIN_FUNC RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WST
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcBindingFree(RPC_BINDING_HANDLE *binding) {
RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) {
HOST_CONTEXT_GUARD();
if (!binding) {
return RPC_S_INVALID_ARG;
@@ -229,7 +208,7 @@ RPC_STATUS WIN_FUNC RpcBindingFree(RPC_BINDING_HANDLE *binding) {
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcStringFreeW(RPC_WSTR *string) {
RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) {
HOST_CONTEXT_GUARD();
if (!string) {
return RPC_S_INVALID_ARG;
@@ -247,7 +226,7 @@ RPC_STATUS WIN_FUNC RpcStringFreeW(RPC_WSTR *string) {
return RPC_S_OK;
}
CLIENT_CALL_RETURN WIN_ENTRY NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...) {
CLIENT_CALL_RETURN CDECL_NO_CONV NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...) {
DEBUG_LOG("STUB: NdrClientCall2 stubDescriptor=%p format=%p\n", stubDescriptor, format);
CLIENT_CALL_RETURN result = {};
result.Simple = RPC_S_SERVER_UNAVAILABLE;
@@ -255,37 +234,17 @@ CLIENT_CALL_RETURN WIN_ENTRY NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFOR
return result;
}
void WIN_FUNC NdrServerCall2(PRPC_MESSAGE message) {
VOID WINAPI NdrServerCall2(PRPC_MESSAGE message) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("STUB: NdrServerCall2 message=%p\n", message);
}
} // extern "C"
} // namespace rpcrt4
namespace {
void *resolveByName(const char *name) {
if (std::strcmp(name, "RpcStringBindingComposeW") == 0)
return (void *)RpcStringBindingComposeW;
if (std::strcmp(name, "RpcBindingFromStringBindingW") == 0)
return (void *)RpcBindingFromStringBindingW;
if (std::strcmp(name, "RpcStringFreeW") == 0)
return (void *)RpcStringFreeW;
if (std::strcmp(name, "RpcBindingFree") == 0)
return (void *)RpcBindingFree;
if (std::strcmp(name, "RpcBindingSetAuthInfoExW") == 0)
return (void *)RpcBindingSetAuthInfoExW;
if (std::strcmp(name, "NdrClientCall2") == 0)
return (void *)NdrClientCall2;
if (std::strcmp(name, "NdrServerCall2") == 0)
return (void *)NdrServerCall2;
return nullptr;
}
} // namespace
#include "rpcrt4_trampolines.h"
extern const wibo::ModuleStub lib_rpcrt4 = {
(const char *[]){"rpcrt4", nullptr},
resolveByName,
rpcrt4ThunkByName,
nullptr,
};

39
dll/rpcrt4.h Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#include "types.h"
using RPC_STATUS = ULONG;
using RPC_WSTR = LPWSTR;
using RPC_BINDING_HANDLE = PVOID;
using RPC_AUTH_IDENTITY_HANDLE = PVOID;
using PMIDL_STUB_DESC = PVOID;
using PFORMAT_STRING = PUCHAR;
using PRPC_MESSAGE = PVOID;
struct RPC_SECURITY_QOS {
ULONG Version;
ULONG Capabilities;
ULONG IdentityTracking;
ULONG ImpersonationType;
PVOID AdditionalSecurityInfo;
};
union CLIENT_CALL_RETURN {
PVOID 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_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);
CLIENT_CALL_RETURN CDECL_NO_CONV NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...);
VOID WINAPI NdrServerCall2(PRPC_MESSAGE message);
} // namespace rpcrt4

View File

@@ -1,3 +1,5 @@
#include "user32.h"
#include "common.h"
#include "context.h"
#include "errors.h"
@@ -20,7 +22,7 @@ struct USEROBJECTFLAGS {
DWORD dwFlags;
};
int WIN_FUNC LoadStringA(void *hInstance, unsigned int uID, char *lpBuffer, int cchBufferMax) {
int WINAPI LoadStringA(HMODULE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("LoadStringA(%p, %u, %p, %d)\n", hInstance, uID, lpBuffer, cchBufferMax);
if (!lpBuffer || cchBufferMax <= 0) {
@@ -68,7 +70,7 @@ int WIN_FUNC LoadStringA(void *hInstance, unsigned int uID, char *lpBuffer, int
return copyLength;
}
int WIN_FUNC LoadStringW(void *hInstance, unsigned int uID, uint16_t *lpBuffer, int cchBufferMax) {
int WINAPI LoadStringW(HMODULE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("LoadStringW(%p, %u, %p, %d)\n", hInstance, uID, lpBuffer, cchBufferMax);
wibo::Executable *mod = wibo::executableFromModule((HMODULE)hInstance);
@@ -122,7 +124,7 @@ int WIN_FUNC LoadStringW(void *hInstance, unsigned int uID, uint16_t *lpBuffer,
return copyLength;
}
int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption, unsigned int uType) {
int WINAPI MessageBoxA(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
HOST_CONTEXT_GUARD();
(void)hwnd;
(void)uType;
@@ -131,20 +133,20 @@ int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption,
return 1;
}
HKL WIN_FUNC GetKeyboardLayout(DWORD idThread) {
HKL WINAPI GetKeyboardLayout(DWORD idThread) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetKeyboardLayout(%u)\n", idThread);
(void)idThread;
return reinterpret_cast<HKL>(kDefaultKeyboardLayout);
}
HWINSTA WIN_FUNC GetProcessWindowStation() {
HWINSTA WINAPI GetProcessWindowStation() {
DEBUG_LOG("GetProcessWindowStation()\n");
static int kWindowStationStub;
return reinterpret_cast<HWINSTA>(&kWindowStationStub);
}
BOOL WIN_FUNC GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) {
BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) {
DEBUG_LOG("GetUserObjectInformationA(%p, %d, %p, %u, %p)\n", hObj, nIndex, pvInfo, nLength, lpnLengthNeeded);
(void)hObj;
@@ -169,36 +171,20 @@ BOOL WIN_FUNC GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, D
return TRUE;
}
HWND WIN_FUNC GetActiveWindow() {
HWND WINAPI GetActiveWindow() {
DEBUG_LOG("GetActiveWindow()\n");
return nullptr;
}
} // namespace user32
static void *resolveByName(const char *name) {
if (strcmp(name, "LoadStringA") == 0)
return (void *)user32::LoadStringA;
if (strcmp(name, "LoadStringW") == 0)
return (void *)user32::LoadStringW;
if (strcmp(name, "MessageBoxA") == 0)
return (void *)user32::MessageBoxA;
if (strcmp(name, "GetKeyboardLayout") == 0)
return (void *)user32::GetKeyboardLayout;
if (strcmp(name, "GetProcessWindowStation") == 0)
return (void *)user32::GetProcessWindowStation;
if (strcmp(name, "GetUserObjectInformationA") == 0)
return (void *)user32::GetUserObjectInformationA;
if (strcmp(name, "GetActiveWindow") == 0)
return (void *)user32::GetActiveWindow;
return nullptr;
}
#include "user32_trampolines.h"
extern const wibo::ModuleStub lib_user32 = {
(const char *[]){
"user32",
nullptr,
},
resolveByName,
user32ThunkByName,
nullptr,
};

15
dll/user32.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include "types.h"
namespace user32 {
int WINAPI LoadStringA(HMODULE hInstance, UINT uID, LPSTR lpBuffer, int cchBufferMax);
int WINAPI LoadStringW(HMODULE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax);
int WINAPI MessageBoxA(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
HKL WINAPI GetKeyboardLayout(DWORD idThread);
HWINSTA WINAPI GetProcessWindowStation();
BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded);
HWND WINAPI GetActiveWindow();
} // namespace user32

View File

@@ -1,3 +1,5 @@
#include "vcruntime.h"
#include "common.h"
#include "context.h"
#include "modules.h"
@@ -6,45 +8,35 @@
namespace vcruntime {
void *WIN_ENTRY memcpy(void *dest, const void *src, size_t count) {
PVOID CDECL memcpy(PVOID dest, LPCVOID src, SIZE_T count) {
HOST_CONTEXT_GUARD();
return ::memcpy(dest, src, count);
}
void *WIN_ENTRY memset(void *dest, int ch, size_t count) {
PVOID CDECL memset(PVOID dest, int ch, SIZE_T count) {
HOST_CONTEXT_GUARD();
return ::memset(dest, ch, count);
}
int WIN_ENTRY memcmp(const void *buf1, const void *buf2, size_t count) {
int CDECL memcmp(LPCVOID buf1, LPCVOID buf2, SIZE_T count) {
HOST_CONTEXT_GUARD();
return ::memcmp(buf1, buf2, count);
}
void *WIN_ENTRY memmove(void *dest, const void *src, size_t count) {
PVOID CDECL memmove(PVOID dest, LPCVOID src, SIZE_T count) {
HOST_CONTEXT_GUARD();
return ::memmove(dest, src, count);
}
} // namespace vcruntime
static void *resolveByName(const char *name) {
if (strcmp(name, "memcpy") == 0)
return (void *)vcruntime::memcpy;
if (strcmp(name, "memset") == 0)
return (void *)vcruntime::memset;
if (strcmp(name, "memcmp") == 0)
return (void *)vcruntime::memcmp;
if (strcmp(name, "memmove") == 0)
return (void *)vcruntime::memmove;
return nullptr;
}
#include "vcruntime_trampolines.h"
extern const wibo::ModuleStub lib_vcruntime = {
(const char *[]){
"vcruntime140",
nullptr,
},
resolveByName,
vcruntimeThunkByName,
nullptr,
};

12
dll/vcruntime.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include "types.h"
namespace vcruntime {
PVOID CDECL memcpy(PVOID dest, LPCVOID src, SIZE_T count);
PVOID CDECL memset(PVOID dest, int ch, SIZE_T count);
int CDECL memcmp(LPCVOID buf1, LPCVOID buf2, SIZE_T count);
PVOID CDECL memmove(PVOID dest, LPCVOID src, SIZE_T count);
} // namespace vcruntime

View File

@@ -1,3 +1,5 @@
#include "version.h"
#include "common.h"
#include "context.h"
#include "errors.h"
@@ -200,7 +202,7 @@ bool loadVersionResource(const char *fileName, std::vector<uint8_t> &buffer) {
namespace version {
unsigned int WIN_FUNC GetFileVersionInfoSizeA(const char *lptstrFilename, unsigned int *lpdwHandle) {
UINT WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetFileVersionInfoSizeA(%s, %p)\n", lptstrFilename, lpdwHandle);
if (lpdwHandle)
@@ -212,8 +214,7 @@ unsigned int WIN_FUNC GetFileVersionInfoSizeA(const char *lptstrFilename, unsign
return static_cast<unsigned int>(buffer.size());
}
unsigned int WIN_FUNC GetFileVersionInfoA(const char *lptstrFilename, unsigned int dwHandle, unsigned int dwLen,
void *lpData) {
UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) {
HOST_CONTEXT_GUARD();
(void)dwHandle;
DEBUG_LOG("GetFileVersionInfoA(%s, %u, %p)\n", lptstrFilename, dwLen, lpData);
@@ -276,8 +277,7 @@ static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &sub
return 1;
}
unsigned int WIN_FUNC VerQueryValueA(const void *pBlock, const char *lpSubBlock, void **lplpBuffer,
unsigned int *puLen) {
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("VerQueryValueA(%p, %s, %p, %p)\n", pBlock, lpSubBlock ? lpSubBlock : "(null)", lplpBuffer, puLen);
if (!lpSubBlock)
@@ -285,23 +285,21 @@ unsigned int WIN_FUNC VerQueryValueA(const void *pBlock, const char *lpSubBlock,
return VerQueryValueImpl(pBlock, lpSubBlock, lplpBuffer, puLen);
}
unsigned int WIN_FUNC GetFileVersionInfoSizeW(const uint16_t *lptstrFilename, unsigned int *lpdwHandle) {
UINT WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetFileVersionInfoSizeW -> ");
auto narrow = wideStringToString(lptstrFilename);
return GetFileVersionInfoSizeA(narrow.c_str(), lpdwHandle);
}
unsigned int WIN_FUNC GetFileVersionInfoW(const uint16_t *lptstrFilename, unsigned int dwHandle, unsigned int dwLen,
void *lpData) {
UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData) {
HOST_CONTEXT_GUARD();
DEBUG_LOG("GetFileVersionInfoW -> ");
auto narrow = wideStringToString(lptstrFilename);
return GetFileVersionInfoA(narrow.c_str(), dwHandle, dwLen, lpData);
}
unsigned int WIN_FUNC VerQueryValueW(const void *pBlock, const uint16_t *lpSubBlock, void **lplpBuffer,
unsigned int *puLen) {
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) {
HOST_CONTEXT_GUARD();
if (!lpSubBlock)
return 0;
@@ -312,27 +310,13 @@ unsigned int WIN_FUNC VerQueryValueW(const void *pBlock, const uint16_t *lpSubBl
} // namespace version
static void *resolveByName(const char *name) {
if (strcmp(name, "GetFileVersionInfoSizeA") == 0)
return (void *)version::GetFileVersionInfoSizeA;
if (strcmp(name, "GetFileVersionInfoA") == 0)
return (void *)version::GetFileVersionInfoA;
if (strcmp(name, "VerQueryValueA") == 0)
return (void *)version::VerQueryValueA;
if (strcmp(name, "GetFileVersionInfoSizeW") == 0)
return (void *)version::GetFileVersionInfoSizeW;
if (strcmp(name, "GetFileVersionInfoW") == 0)
return (void *)version::GetFileVersionInfoW;
if (strcmp(name, "VerQueryValueW") == 0)
return (void *)version::VerQueryValueW;
return nullptr;
}
#include "version_trampolines.h"
extern const wibo::ModuleStub lib_version = {
(const char *[]){
"version",
nullptr,
},
resolveByName,
versionThunkByName,
nullptr,
};

14
dll/version.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include "types.h"
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 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);
} // namespace version

View File

@@ -22,6 +22,8 @@
#define VERBOSE_LOG(...) ((void)0)
#endif
extern "C" thread_local TEB *currentThreadTeb;
namespace wibo {
extern char **argv;
@@ -32,7 +34,6 @@ extern std::string commandLine;
extern std::vector<uint16_t> commandLineW;
extern bool debugEnabled;
extern unsigned int debugIndent;
extern uint16_t tibSelector;
extern int tibEntryNumber;
extern PEB *processPeb;
@@ -40,8 +41,6 @@ TEB *allocateTib();
void destroyTib(TEB *tib);
void initializeTibStackInfo(TEB *tib);
bool installTibForCurrentThread(TEB *tib);
void setThreadTibForHost(TEB *tib);
TEB *getThreadTibForHost();
void debug_log(const char *fmt, ...);

View File

@@ -1,65 +0,0 @@
#include "context.h"
#include <cstddef>
namespace {
constexpr size_t kHostFsOffset = offsetof(TEB, hostFsSelector);
constexpr size_t kHostGsOffset = offsetof(TEB, hostGsSelector);
constexpr size_t kHostValidOffset = offsetof(TEB, hostSegmentsValid);
thread_local TEB *g_threadTibForHost = nullptr;
} // namespace
namespace wibo {
void setThreadTibForHost(TEB *tib) { g_threadTibForHost = tib; }
TEB *getThreadTibForHost() { return g_threadTibForHost; }
HostContextGuard::HostContextGuard() : previousFs_(0), previousGs_(0), restore_(false) {
asm volatile("mov %%fs, %0" : "=r"(previousFs_));
asm volatile("mov %%gs, %0" : "=r"(previousGs_));
if (previousFs_ == wibo::tibSelector) {
unsigned char hostValid = 0;
asm volatile("movb %%fs:%c1, %0" : "=r"(hostValid) : "i"(kHostValidOffset));
if (hostValid) {
uint16_t hostFs = 0;
uint16_t hostGs = 0;
asm volatile("movw %%fs:%c1, %0" : "=r"(hostFs) : "i"(kHostFsOffset));
asm volatile("movw %%fs:%c1, %0" : "=r"(hostGs) : "i"(kHostGsOffset));
asm volatile("movw %0, %%fs" : : "r"(hostFs) : "memory");
asm volatile("movw %0, %%gs" : : "r"(hostGs) : "memory");
restore_ = true;
}
}
}
HostContextGuard::~HostContextGuard() {
if (restore_) {
asm volatile("movw %0, %%fs" : : "r"(previousFs_) : "memory");
asm volatile("movw %0, %%gs" : : "r"(previousGs_) : "memory");
}
}
GuestContextGuard::GuestContextGuard(TEB *tib) : previousFs_(0), previousGs_(0), applied_(false) {
if (!tib || !wibo::tibSelector) {
return;
}
asm volatile("mov %%fs, %0" : "=r"(previousFs_));
asm volatile("mov %%gs, %0" : "=r"(previousGs_));
tib->hostFsSelector = previousFs_;
tib->hostGsSelector = previousGs_;
tib->hostSegmentsValid = 1;
asm volatile("movw %0, %%fs" : : "r"(wibo::tibSelector) : "memory");
applied_ = true;
}
GuestContextGuard::~GuestContextGuard() {
if (applied_) {
asm volatile("movw %0, %%fs" : : "r"(previousFs_) : "memory");
asm volatile("movw %0, %%gs" : : "r"(previousGs_) : "memory");
}
}
} // namespace wibo

View File

@@ -1,36 +1,4 @@
#pragma once
#include "common.h"
namespace wibo {
class HostContextGuard {
public:
HostContextGuard();
~HostContextGuard();
HostContextGuard(const HostContextGuard &) = delete;
HostContextGuard &operator=(const HostContextGuard &) = delete;
private:
uint16_t previousFs_;
uint16_t previousGs_;
bool restore_;
};
class GuestContextGuard {
public:
explicit GuestContextGuard(TEB *tib);
~GuestContextGuard();
GuestContextGuard(const GuestContextGuard &) = delete;
GuestContextGuard &operator=(const GuestContextGuard &) = delete;
private:
uint16_t previousFs_;
uint16_t previousGs_;
bool applied_;
};
} // namespace wibo
#define HOST_CONTEXT_GUARD() wibo::HostContextGuard _wiboHostContextGuard
#define GUEST_CONTEXT_GUARD(tibPtr) wibo::GuestContextGuard _wiboGuestContextGuard(tibPtr)
#define HOST_CONTEXT_GUARD()
#define GUEST_CONTEXT_GUARD(tibPtr)

7
src/entry.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "types.h"
typedef VOID(_CC_CDECL *EntryProc)();
typedef BOOL(_CC_STDCALL *DllEntryProc)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved);
typedef VOID(_CC_STDCALL *PIMAGE_TLS_CALLBACK)(PVOID DllHandle, DWORD Reason, PVOID Reserved);

View File

@@ -1,5 +1,7 @@
#include "common.h"
#include "context.h"
#include "entry.h"
#include "entry_trampolines.h"
#include "files.h"
#include "modules.h"
#include "processes.h"
@@ -8,7 +10,6 @@
#include "version_info.h"
#include <asm/ldt.h>
#include <charconv>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
@@ -19,7 +20,6 @@
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <system_error>
#include <threads.h>
#include <unistd.h>
#include <vector>
@@ -32,9 +32,9 @@ std::vector<uint16_t> wibo::commandLineW;
wibo::ModuleInfo *wibo::mainModule = nullptr;
bool wibo::debugEnabled = false;
unsigned int wibo::debugIndent = 0;
uint16_t wibo::tibSelector = 0;
int wibo::tibEntryNumber = -1;
PEB *wibo::processPeb = nullptr;
thread_local TEB *currentThreadTeb = nullptr;
void wibo::debug_log(const char *fmt, ...) {
va_list args;
@@ -74,27 +74,24 @@ void wibo::initializeTibStackInfo(TEB *tibPtr) {
if (!tibPtr) {
return;
}
pthread_attr_t attr;
if (pthread_getattr_np(pthread_self(), &attr) != 0) {
perror("Failed to get thread attributes");
return;
// Allocate a stack for the thread in the guest address space (below 2GB)
void *guestLimit = nullptr;
void *guestBase = nullptr;
if (!wibo::heap::reserveGuestStack(1 * 1024 * 1024, &guestLimit, &guestBase)) {
fprintf(stderr, "Failed to reserve guest stack\n");
std::abort();
}
void *stackAddr = nullptr;
size_t stackSize = 0;
if (pthread_attr_getstack(&attr, &stackAddr, &stackSize) == 0 && stackAddr && stackSize > 0) {
tibPtr->Tib.StackLimit = stackAddr;
tibPtr->Tib.StackBase = static_cast<char *>(stackAddr) + stackSize;
} else {
perror("Failed to get thread stack info");
}
DEBUG_LOG("initializeTibStackInfo: stackBase=%p stackLimit=%p\n", tibPtr->Tib.StackBase, tibPtr->Tib.StackLimit);
pthread_attr_destroy(&attr);
tibPtr->Tib.StackLimit = guestLimit;
tibPtr->Tib.StackBase = guestBase;
DEBUG_LOG("initializeTibStackInfo: using guest stack base=%p limit=%p\n", tibPtr->Tib.StackBase,
tibPtr->Tib.StackLimit);
}
bool wibo::installTibForCurrentThread(TEB *tibPtr) {
if (!tibPtr) {
return false;
}
struct user_desc desc;
std::memset(&desc, 0, sizeof(desc));
desc.entry_number = tibEntryNumber;
@@ -110,21 +107,22 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) {
perror("set_thread_area failed");
return false;
}
if (tibSelector == 0) {
if (tibEntryNumber != static_cast<int>(desc.entry_number)) {
tibEntryNumber = static_cast<int>(desc.entry_number);
tibSelector = static_cast<uint16_t>((desc.entry_number << 3) | 3);
DEBUG_LOG("set_thread_area: allocated selector=0x%x entry=%d base=%p\n", tibSelector, tibEntryNumber, tibPtr);
DEBUG_LOG("set_thread_area: allocated entry=%d base=%p\n", tibEntryNumber, tibPtr);
} else {
DEBUG_LOG("set_thread_area: reused selector=0x%x entry=%d base=%p\n", tibSelector, tibEntryNumber, tibPtr);
DEBUG_LOG("set_thread_area: reused entry=%d base=%p\n", tibEntryNumber, tibPtr);
}
tibPtr->HostFsSelector = static_cast<uint16_t>((desc.entry_number << 3) | 3);
tibPtr->HostGsSelector = 0;
currentThreadTeb = tibPtr;
return true;
}
// Make this global to ease debugging
TEB tib;
const size_t MAPS_BUFFER_SIZE = 0x10000;
static std::string getExeName(const char *argv0) {
std::filesystem::path exePath(argv0 ? argv0 : "wibo");
return exePath.filename().string();
@@ -248,108 +246,6 @@ static int handlePathCommand(int argc, char **argv, const char *argv0) {
return 0;
}
/**
* Read /proc/self/maps into a buffer.
*
* While reading /proc/self/maps, we need to be extremely careful not to allocate any memory,
* as that could cause libc to modify memory mappings while we're attempting to fill them.
* To accomplish this, we use Linux syscalls directly.
*
* @param buffer The buffer to read into.
* @return The number of bytes read.
*/
static size_t readMaps(char *buffer) {
int fd = open("/proc/self/maps", O_RDONLY);
if (fd == -1) {
perror("Failed to open /proc/self/maps");
exit(1);
}
char *cur = buffer;
char *bufferEnd = buffer + MAPS_BUFFER_SIZE;
while (cur < bufferEnd) {
int ret = read(fd, cur, static_cast<size_t>(bufferEnd - cur));
if (ret == -1) {
if (errno == EINTR) {
continue;
}
perror("Failed to read /proc/self/maps");
exit(1);
} else if (ret == 0) {
break;
}
cur += ret;
}
close(fd);
if (cur == bufferEnd) {
fprintf(stderr, "Buffer too small while reading /proc/self/maps\n");
exit(1);
}
*cur = '\0';
return static_cast<size_t>(cur - buffer);
}
/**
* Map the upper 2GB of memory to prevent libc from allocating there.
*
* This is necessary because 32-bit windows only reserves the lowest 2GB of memory for use by a process
* (https://www.tenouk.com/WinVirtualAddressSpace.html). Linux, on the other hand, will happily allow
* nearly the entire 4GB address space to be used. Some Windows programs rely on heap allocations to be
* in the lower 2GB of memory, otherwise they misbehave or crash.
*
* Between reading /proc/self/maps and mmap-ing the upper 2GB, we must be extremely careful not to allocate
* any memory, as that could cause libc to modify memory mappings while we're attempting to fill them.
*/
static void blockUpper2GB() {
const unsigned int FILL_MEMORY_ABOVE = 0x80000000; // 2GB
DEBUG_LOG("Blocking upper 2GB address space\n");
// Buffer lives on the stack to avoid heap allocation
char buffer[MAPS_BUFFER_SIZE];
size_t len = readMaps(buffer);
std::string_view procLine(buffer, len);
unsigned int lastMapEnd = 0;
while (true) {
size_t newline = procLine.find('\n');
if (newline == std::string::npos) {
break;
}
unsigned int mapStart = 0;
auto result = std::from_chars(procLine.data(), procLine.data() + procLine.size(), mapStart, 16);
if (result.ec != std::errc()) {
break;
}
unsigned int mapEnd = 0;
result = std::from_chars(result.ptr + 1, procLine.data() + procLine.size(), mapEnd, 16);
if (result.ec != std::errc()) {
break;
}
// The empty space we want to map out is now between lastMapEnd and mapStart
unsigned int holdingMapStart = lastMapEnd;
unsigned int holdingMapEnd = mapStart;
if ((holdingMapEnd - holdingMapStart) != 0 && holdingMapEnd > FILL_MEMORY_ABOVE) {
holdingMapStart = std::max(holdingMapStart, FILL_MEMORY_ABOVE);
// DEBUG_LOG("Mapping %08x-%08x\n", holdingMapStart, holdingMapEnd);
void *holdingMap = mmap((void *)holdingMapStart, holdingMapEnd - holdingMapStart, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0);
if (holdingMap == MAP_FAILED) {
perror("Failed to create holding map");
exit(1);
}
}
lastMapEnd = mapEnd;
procLine = procLine.substr(newline + 1);
}
}
int main(int argc, char **argv) {
if (argc >= 2 && strcmp(argv[1], "path") == 0) {
return handlePathCommand(argc - 2, argv + 2, argv[0]);
@@ -447,7 +343,6 @@ int main(int argc, char **argv) {
wibo::debugIndent = std::stoul(debugIndentEnv);
}
blockUpper2GB();
files::init();
// Create TIB
@@ -463,7 +358,6 @@ int main(int argc, char **argv) {
fprintf(stderr, "Failed to install TIB for main thread\n");
return 1;
}
wibo::setThreadTibForHost(&tib);
// Determine the guest program name
auto guestArgs = wibo::splitCommandLine(cmdLine.c_str());
@@ -579,7 +473,7 @@ int main(int argc, char **argv) {
}
fclose(f);
const auto entryPoint = executable->entryPoint;
const auto entryPoint = reinterpret_cast<EntryProc>(executable->entryPoint);
if (!entryPoint) {
fprintf(stderr, "Executable %s has no entry point\n", resolvedGuestPath.c_str());
return 1;
@@ -609,7 +503,7 @@ int main(int argc, char **argv) {
// Invoke the damn thing
{
GUEST_CONTEXT_GUARD(&tib);
asm volatile("call *%0" : : "r"(entryPoint) : "memory");
call_EntryProc(entryPoint);
}
DEBUG_LOG("We came back\n");
wibo::shutdownModuleRegistry();

View File

@@ -2,9 +2,13 @@
#include "common.h"
#include "context.h"
#include "entry.h"
#include "entry_trampolines.h"
#include "errors.h"
#include "files.h"
#include "kernel32/internal.h"
#include "msvcrt.h"
#include "msvcrt_trampolines.h"
#include "strutil.h"
#include "tls.h"
@@ -346,18 +350,11 @@ void runModuleTlsCallbacks(wibo::ModuleInfo &module, DWORD reason) {
if (!module.tlsInfo.hasTls || module.tlsInfo.callbacks.empty()) {
return;
}
TEB *tib = wibo::getThreadTibForHost();
if (!tib) {
return;
}
GUEST_CONTEXT_GUARD(tib);
using TlsCallback = void(WIN_FUNC *)(void *, DWORD, void *);
for (void *callbackAddr : module.tlsInfo.callbacks) {
if (!callbackAddr) {
for (auto *callback : module.tlsInfo.callbacks) {
if (!callback) {
continue;
}
auto callback = reinterpret_cast<TlsCallback>(callbackAddr);
callback(module.handle, reason, nullptr);
call_PIMAGE_TLS_CALLBACK(callback, module.handle, reason, nullptr);
}
}
@@ -565,8 +562,7 @@ BOOL callDllMain(wibo::ModuleInfo &info, DWORD reason, LPVOID reserved) {
// Reset last error
kernel32::setLastError(ERROR_SUCCESS);
using DllMainFunc = BOOL(WIN_FUNC *)(HMODULE, DWORD, LPVOID);
auto dllMain = reinterpret_cast<DllMainFunc>(entry);
auto dllMain = reinterpret_cast<DllEntryProc>(entry);
auto invokeWithGuestTIB = [&](DWORD callReason, LPVOID callReserved, bool force) -> BOOL {
if (!force) {
@@ -586,14 +582,8 @@ BOOL callDllMain(wibo::ModuleInfo &info, DWORD reason, LPVOID reserved) {
reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved,
info.normalizedName.c_str());
BOOL result = TRUE;
if (!wibo::tibSelector) {
result = dllMain(reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved);
} else {
TEB *tib = wibo::getThreadTibForHost();
GUEST_CONTEXT_GUARD(tib);
result = dllMain(reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved);
}
BOOL result =
call_DllEntryProc(dllMain, reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved);
DEBUG_LOG(" callDllMain: %s DllMain returned %d\n", info.normalizedName.c_str(), result);
return result;
};
@@ -873,7 +863,7 @@ void registerOnExitTable(void *table) {
}
}
void addOnExitFunction(void *table, void (*func)()) {
void addOnExitFunction(void *table, _PVFV func) {
if (!func)
return;
auto reg = registry();
@@ -887,17 +877,15 @@ void addOnExitFunction(void *table, void (*func)()) {
reg->onExitTables[table] = info;
}
if (info) {
info->onExitFunctions.push_back(reinterpret_cast<void *>(func));
info->onExitFunctions.push_back(func);
}
}
void runPendingOnExit(ModuleInfo &info) {
TEB *tib = wibo::getThreadTibForHost();
for (auto it = info.onExitFunctions.rbegin(); it != info.onExitFunctions.rend(); ++it) {
auto fn = reinterpret_cast<void (*)()>(*it);
auto *fn = *it;
if (fn) {
GUEST_CONTEXT_GUARD(tib);
fn();
call__PVFV(fn);
}
}
info.onExitFunctions.clear();
@@ -932,7 +920,7 @@ bool initializeModuleTls(ModuleInfo &module) {
if (callbacksArray) {
auto callbackPtr = reinterpret_cast<uintptr_t *>(callbacksArray);
while (callbackPtr && *callbackPtr) {
info.callbacks.push_back(reinterpret_cast<void *>(resolveModuleAddress(exec, *callbackPtr)));
info.callbacks.push_back(reinterpret_cast<PIMAGE_TLS_CALLBACK>(resolveModuleAddress(exec, *callbackPtr)));
++callbackPtr;
}
}
@@ -1068,10 +1056,9 @@ void notifyDllThreadAttach() {
targets.push_back(info);
}
}
TEB *tib = wibo::getThreadTibForHost();
for (wibo::ModuleInfo *info : targets) {
if (info && info->tlsInfo.hasTls && tib) {
if (!allocateModuleTlsForThread(*info, tib)) {
if (info && info->tlsInfo.hasTls) {
if (!allocateModuleTlsForThread(*info, currentThreadTeb)) {
DEBUG_LOG("notifyDllThreadAttach: failed to allocate TLS for %s\n", info->originalName.c_str());
}
runModuleTlsCallbacks(*info, TLS_THREAD_ATTACH);
@@ -1093,9 +1080,8 @@ void notifyDllThreadDetach() {
targets.push_back(info);
}
}
TEB *tib = wibo::getThreadTibForHost();
for (auto it = targets.rbegin(); it != targets.rend(); ++it) {
if (*it && (*it)->tlsInfo.hasTls && tib) {
if (*it && (*it)->tlsInfo.hasTls) {
runModuleTlsCallbacks(**it, TLS_THREAD_DETACH);
}
}
@@ -1103,8 +1089,8 @@ void notifyDllThreadDetach() {
callDllMain(**it, DLL_THREAD_DETACH, nullptr);
}
for (auto it = targets.rbegin(); it != targets.rend(); ++it) {
if (*it && (*it)->tlsInfo.hasTls && tib) {
freeModuleTlsForThread(**it, tib);
if (*it && (*it)->tlsInfo.hasTls) {
freeModuleTlsForThread(**it, currentThreadTeb);
}
}
kernel32::setLastError(ERROR_SUCCESS);

View File

@@ -1,6 +1,8 @@
#pragma once
#include "common.h"
#include "entry.h"
#include "msvcrt.h"
#include "tls.h"
#include <optional>
@@ -73,7 +75,7 @@ struct ModuleTlsInfo {
size_t zeroFillSize = 0;
uint32_t characteristics = 0;
size_t allocationSize = 0;
std::vector<void *> callbacks;
std::vector<PIMAGE_TLS_CALLBACK> callbacks;
std::unordered_map<TEB *, void *> threadAllocations;
};
@@ -100,7 +102,7 @@ struct ModuleInfo {
std::vector<void *> exportsByOrdinal;
std::unordered_map<std::string, uint16_t> exportNameToOrdinal;
bool exportsInitialized = false;
std::vector<void *> onExitFunctions;
std::vector<_PVFV> onExitFunctions;
ModuleTlsInfo tlsInfo;
};
extern ModuleInfo *mainModule;
@@ -115,7 +117,7 @@ void clearDllDirectoryOverride();
std::optional<std::filesystem::path> dllDirectoryOverride();
ModuleInfo *findLoadedModule(const char *name);
void registerOnExitTable(void *table);
void addOnExitFunction(void *table, void (*func)());
void addOnExitFunction(void *table, _PVFV func);
void executeOnExitTable(void *table);
void runPendingOnExit(ModuleInfo &info);
void notifyDllThreadAttach();

View File

@@ -357,9 +357,9 @@ bool setValue(TEB *tib, DWORD index, void *value) {
return true;
}
void *getValue(DWORD index) { return getValue(getThreadTibForHost(), index); }
void *getValue(DWORD index) { return getValue(currentThreadTeb, index); }
bool setValue(DWORD index, void *value) { return setValue(getThreadTibForHost(), index, value); }
bool setValue(DWORD index, void *value) { return setValue(currentThreadTeb, index, value); }
void forEachTib(void (*callback)(TEB *, void *), void *context) {
if (!callback) {

View File

@@ -28,10 +28,16 @@
#define _Out_writes_bytes_(n) WIBO_ANNOTATE("SAL:out_bcount(" #n ")")
// Codegen annotation for calling convention
#define _CC_CDECL WIBO_ANNOTATE("CC:cdecl")
#define _CC_STDCALL WIBO_ANNOTATE("CC:stdcall")
// Instructs codegen to convert stdcall to fastcall
// Instructs codegen to convert between calling conventions
#define WINAPI _CC_STDCALL __attribute__((fastcall))
#define CDECL _CC_CDECL __attribute__((fastcall))
#define CDECL_NO_CONV _CC_CDECL __attribute__((cdecl, force_align_arg_pointer))
// Used for host-to-guest calls
#define GUEST_STDCALL __attribute__((stdcall))
using VOID = void;
using HANDLE = VOID *;
@@ -39,6 +45,7 @@ using HMODULE = VOID *;
using HGLOBAL = HANDLE;
using HLOCAL = HANDLE;
using HRSRC = HANDLE;
using HINSTANCE = HANDLE;
using LPHANDLE = HANDLE *;
using PHANDLE = HANDLE *;
using HKL = HANDLE;
@@ -57,13 +64,13 @@ using LONG = int;
using PLONG = LONG *;
using ULONG = unsigned int;
using PULONG = ULONG *;
using LARGE_INTEGER = long long;
using PLARGE_INTEGER = LARGE_INTEGER *;
using ULARGE_INTEGER = unsigned long long;
using PULARGE_INTEGER = ULARGE_INTEGER *;
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;
using UINT_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 DWORD_PTR = ULONG_PTR;
using PDWORD_PTR = DWORD_PTR *;
@@ -89,6 +96,7 @@ using PSIZE_T = SIZE_T *;
using BYTE = unsigned char;
using BOOLEAN = unsigned char;
using UINT = unsigned int;
using PUINT = UINT *;
using HKEY = VOID *;
using PHKEY = HKEY *;
using PSID = VOID *;
@@ -105,6 +113,30 @@ using PWSTR = WCHAR *;
using NTSTATUS = LONG;
using HRESULT = LONG;
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
} DUMMYSTRUCTNAME;
struct {
DWORD LowPart;
LONG HighPart;
} u;
LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;
typedef union _ULARGE_INTEGER {
struct {
DWORD LowPart;
DWORD HighPart;
} DUMMYSTRUCTNAME;
struct {
DWORD LowPart;
DWORD HighPart;
} u;
ULONGLONG QuadPart;
} ULARGE_INTEGER, *PULARGE_INTEGER;
struct GUID {
DWORD Data1;
WORD Data2;
@@ -260,7 +292,7 @@ typedef struct _PEB_LDR_DATA {
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
using PS_POST_PROCESS_INIT_ROUTINE = void(WIN_FUNC *)(void);
typedef void(_CC_STDCALL *PS_POST_PROCESS_INIT_ROUTINE)();
using PPS_POST_PROCESS_INIT_ROUTINE = PS_POST_PROCESS_INIT_ROUTINE *;
typedef struct _PEB {
@@ -327,69 +359,70 @@ typedef struct _NT_TIB {
} NT_TIB, *PNT_TIB;
typedef struct _TEB {
NT_TIB Tib; /* 000 */
PVOID EnvironmentPointer; /* 01c */
CLIENT_ID ClientId; /* 020 */
PVOID ActiveRpcHandle; /* 028 */
PVOID ThreadLocalStoragePointer; /* 02c */
PPEB Peb; /* 030 */
ULONG LastErrorValue; /* 034 */
ULONG CountOfOwnedCriticalSections; /* 038 */
PVOID CsrClientThread; /* 03c */
PVOID Win32ThreadInfo; /* 040 */
ULONG Win32ClientInfo[31]; /* 044 used for user32 private data in Wine */
PVOID WOW32Reserved; /* 0c0 */
ULONG CurrentLocale; /* 0c4 */
ULONG FpSoftwareStatusRegister; /* 0c8 */
PVOID SystemReserved1[54]; /* 0cc used for kernel32 private data in Wine */
PVOID Spare1; /* 1a4 */
LONG ExceptionCode; /* 1a8 */
PVOID ActivationContextStackPointer; /* 1a8/02c8 */
BYTE SpareBytes1[36]; /* 1ac */
PVOID SystemReserved2[10]; /* 1d4 used for ntdll private data in Wine */
GDI_TEB_BATCH GdiTebBatch; /* 1fc */
ULONG gdiRgn; /* 6dc */
ULONG gdiPen; /* 6e0 */
ULONG gdiBrush; /* 6e4 */
CLIENT_ID RealClientId; /* 6e8 */
HANDLE GdiCachedProcessHandle; /* 6f0 */
ULONG GdiClientPID; /* 6f4 */
ULONG GdiClientTID; /* 6f8 */
PVOID GdiThreadLocaleInfo; /* 6fc */
PVOID UserReserved[5]; /* 700 */
PVOID glDispatchTable[280]; /* 714 */
ULONG glReserved1[26]; /* b74 */
PVOID glReserved2; /* bdc */
PVOID glSectionInfo; /* be0 */
PVOID glSection; /* be4 */
PVOID glTable; /* be8 */
PVOID glCurrentRC; /* bec */
PVOID glContext; /* bf0 */
ULONG LastStatusValue; /* bf4 */
UNICODE_STRING StaticUnicodeString; /* bf8 used by advapi32 */
WCHAR StaticUnicodeBuffer[261]; /* c00 used by advapi32 */
PVOID DeallocationStack; /* e0c */
PVOID TlsSlots[64]; /* e10 */
LIST_ENTRY TlsLinks; /* f10 */
PVOID Vdm; /* f18 */
PVOID ReservedForNtRpc; /* f1c */
PVOID DbgSsReserved[2]; /* f20 */
ULONG HardErrorDisabled; /* f28 */
PVOID Instrumentation[16]; /* f2c */
PVOID WinSockData; /* f6c */
ULONG GdiBatchCount; /* f70 */
ULONG Spare2; /* f74 */
ULONG Spare3; /* f78 */
ULONG Spare4; /* f7c */
PVOID ReservedForOle; /* f80 */
ULONG WaitingOnLoaderLock; /* f84 */
PVOID Reserved5[3]; /* f88 */
PVOID *TlsExpansionSlots; /* f94 */
// Custom
unsigned short hostFsSelector;
unsigned short hostGsSelector;
bool hostSegmentsValid;
unsigned char padding[3];
NT_TIB Tib;
PVOID EnvironmentPointer;
CLIENT_ID ClientId;
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
PPEB Peb;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo;
ULONG Win32ClientInfo[31]; /* used for user32 private data in Wine */
PVOID WOW32Reserved;
ULONG CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[54]; /* used for kernel32 private data in Wine */
PVOID Spare1;
LONG ExceptionCode;
PVOID ActivationContextStackPointer;
BYTE SpareBytes1[36];
PVOID SystemReserved2[10]; /* used for ntdll private data in Wine */
GDI_TEB_BATCH GdiTebBatch;
ULONG gdiRgn;
ULONG gdiPen;
ULONG gdiBrush;
CLIENT_ID RealClientId;
HANDLE GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocaleInfo;
PVOID UserReserved[5];
PVOID glDispatchTable[280];
ULONG glReserved1[26];
PVOID glReserved2;
PVOID glSectionInfo;
PVOID glSection;
PVOID glTable;
PVOID glCurrentRC;
PVOID glContext;
ULONG LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[261];
PVOID DeallocationStack;
PVOID TlsSlots[64];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[2];
ULONG HardErrorDisabled;
PVOID Instrumentation[16];
PVOID WinSockData;
ULONG GdiBatchCount;
ULONG Spare2;
ULONG Spare3;
ULONG Spare4;
PVOID ReservedForOle;
ULONG WaitingOnLoaderLock;
PVOID Reserved5[3];
PVOID *TlsExpansionSlots;
// wibo
WORD HostFsSelector;
WORD HostGsSelector;
PVOID HostStackBase;
PVOID HostStackLimit;
PVOID HostStackPointer;
} TEB, *PTEB;
#ifndef offsetof

View File

@@ -39,6 +39,8 @@ static void create_file_with_content(const char *path, const char *content) {
}
static void setup_fixture(void) {
TEST_CHECK_EQ(2, sizeof(wint_t));
DWORD len = GetCurrentDirectoryA(sizeof(g_original_dir), g_original_dir);
TEST_CHECK(len > 0 && len < sizeof(g_original_dir));

View File

@@ -15,9 +15,14 @@ if __name__ == "__main__":
script_venv.bootstrap_venv(__file__)
import argparse
import ctypes
import os
import sys
import tempfile
from dataclasses import dataclass, field
from enum import IntEnum
from pathlib import Path
from typing import Iterable, List, Optional
from clang.cindex import (
Config,
@@ -25,10 +30,12 @@ from clang.cindex import (
CursorKind,
Index,
TranslationUnit,
TypeKind,
conf,
)
from clang.cindex import (
Type as CXType,
)
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable, List, Optional
# Allow libclang path to be specified via environment variable
if "LIBCLANG_PATH" in os.environ:
@@ -43,13 +50,75 @@ if "LIBCLANG_PATH" in os.environ:
)
class CallingConv(IntEnum):
"""CXCallingConv enum values from clang-c/Index.h"""
DEFAULT = 0
C = 1
X86_STDCALL = 2
X86_FASTCALL = 3
X86_THISCALL = 4
X86_PASCAL = 5
AAPCS = 6
AAPCS_VFP = 7
X86_REGCALL = 8
INTELOCLBICC = 9
WIN64 = 10
X86_64_WIN64 = 11
X86_64_SYSV = 12
X86_VECTORCALL = 13
SWIFT = 14
PRESERVEMOST = 15
PRESERVEALL = 16
AARCH64_VECTORCALL = 17
SWIFTASYNC = 18
AARCH64_SVEPCS = 19
M68K_RTD = 20
INVALID = 100
UNEXPOSED = 200
# Register the clang_getFunctionTypeCallingConv function
_get_calling_conv = conf.lib.clang_getFunctionTypeCallingConv
_get_calling_conv.argtypes = [CXType]
_get_calling_conv.restype = ctypes.c_int
def _get_function_calling_conv(func_type: CXType) -> CallingConv:
"""
Get the calling convention of a function type.
"""
return CallingConv(_get_calling_conv(func_type))
@dataclass
class ArgInfo:
size: int
slot_size: int
primitive: bool
sign_extended: bool
type_str: str
@dataclass
class FuncInfo:
qualified_ns: str
name: str
mangled: str
argc: int
stdcall: bool
source_cc: CallingConv
target_cc: CallingConv
variadic: bool
args: List[ArgInfo] = field(default_factory=list)
@dataclass
class TypedefInfo:
name: str
source_cc: CallingConv
target_cc: CallingConv
variadic: bool
return_type: str
args: List[ArgInfo] = field(default_factory=list)
def parse_tu(
@@ -89,15 +158,85 @@ def _cursor_namespace(cursor: Cursor) -> List[str]:
return list(reversed(ns))
def _has_stdcall_annotation(func: Cursor) -> bool:
def _source_cc_from_annotations(func: Cursor) -> CallingConv:
for child in func.get_children():
if child.kind == CursorKind.ANNOTATE_ATTR and child.spelling == "CC:stdcall":
if child.kind == CursorKind.ANNOTATE_ATTR:
if child.spelling == "CC:fastcall":
return CallingConv.X86_FASTCALL
elif child.spelling == "CC:stdcall":
return CallingConv.X86_STDCALL
elif child.spelling == "CC:cdecl":
return CallingConv.C
return CallingConv.DEFAULT
def _is_handle_typedef(arg_type: CXType) -> bool:
"""Check if a type is a HANDLE-like typedef (HWND, HINSTANCE, etc.)."""
t = arg_type
# Trace through ELABORATED and TYPEDEF to find the original typedef name
while t.kind == TypeKind.ELABORATED or t.kind == TypeKind.TYPEDEF:
if t.kind == TypeKind.TYPEDEF:
decl = t.get_declaration()
name = decl.spelling
# Windows HANDLE types conventionally start with 'H'
if name and name.startswith("H") and name.isupper():
return True
t = decl.underlying_typedef_type
elif t.kind == TypeKind.ELABORATED:
named = t.get_named_type()
if named is None:
break
t = named
else:
break
return False
def _arg_count(func: Cursor) -> int:
return sum(1 for _ in func.type.argument_types())
SIGNED_KINDS = [
TypeKind.SCHAR,
TypeKind.CHAR_S,
TypeKind.SHORT,
TypeKind.INT,
TypeKind.LONG,
TypeKind.LONGLONG,
TypeKind.INT128,
]
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_str=_type_to_string(t),
)
)
return args
def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[FuncInfo]:
@@ -109,83 +248,267 @@ def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Fun
ns_parts = _cursor_namespace(node)
if want_ns is not None and ns_parts != want_ns:
return
name = node.spelling or ""
mangled = getattr(node, "mangled_name", None) or ""
if not name or not mangled:
name = node.spelling
if not name:
return
source_cc = _source_cc_from_annotations(node)
if source_cc == CallingConv.DEFAULT:
return # No CC annotation; skip
out[name] = FuncInfo(
qualified_ns="::".join(ns_parts),
name=name,
mangled=mangled,
argc=_arg_count(node),
stdcall=_has_stdcall_annotation(node),
mangled=node.mangled_name or name,
args=_collect_args(node.type),
source_cc=source_cc,
target_cc=_get_function_calling_conv(node.type),
variadic=node.type.is_function_variadic(),
)
# Recurse into children where it makes sense
# Recurse into children
if node.kind in (CursorKind.TRANSLATION_UNIT, CursorKind.NAMESPACE):
for c in node.get_children():
visit(c)
if tu.cursor is not None:
visit(tu.cursor)
return sorted(out.values(), key=lambda f: f.name)
def emit_x86_asm_trampolines(dll: str, funcs: Iterable[FuncInfo]) -> str:
lines: List[str] = []
lines.append("#\tAuto-generated trampolines; DO NOT EDIT.")
lines.append(".section .note.GNU-stack, \"\", @progbits")
lines.append(".text")
for f in funcs:
name = f.name
mangled = f.mangled
# Ensure ms_abi is encoded for stdcall function-pointer types to match GCC
# mangled = mangled.replace("U7stdcall", "U7stdcallU6ms_abi")
tramp = f"thunk_{dll}_{name}"
lines.append("")
lines.append(f".globl {tramp}")
lines.append(f".type {tramp}, @function")
lines.append(f"{tramp}:")
argc = int(f.argc or 0)
# Calculate number of stack args (fastcall uses ECX/EDX for first 2)
stack_argc = max(0, argc - 2)
stack_bytes = stack_argc * 4
# Use frame pointer for clean alignment and argument access
lines.append("\tpush %ebp")
lines.append("\tmovl %esp, %ebp")
# Align stack: we want ESP = 16n before the call,
# so that after call pushes return address, callee sees ESP = 16n - 4
# After pushing stack_bytes worth of args, we need ESP = 16n + stack_bytes
if stack_bytes > 0:
lines.append(f"\tleal -{stack_bytes}(%ebp), %esp")
lines.append("\tandl $0xFFFFFFF0, %esp")
lines.append(f"\taddl ${stack_bytes}, %esp")
def _type_to_string(t: CXType) -> str:
"""Convert a CXType to a C type string."""
spelling = t.spelling
# Clean up common type spellings
spelling = (
spelling.replace("struct ", "").replace("union ", "").replace("enum ", "")
)
return spelling
def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
"""Collect function pointer typedefs and type aliases from the translation unit."""
out: dict[str, TypedefInfo] = {}
def process_function_pointer_type(
name: str, node: Cursor, func_type: CXType
) -> None:
"""Process a function pointer type and add it to the output."""
if not name:
return
# Determine calling convention
source_cc = _get_function_calling_conv(func_type)
target_cc = _source_cc_from_annotations(node)
if target_cc == CallingConv.DEFAULT:
return # No CC annotation; skip
variadic = func_type.is_function_variadic()
args = _collect_args(func_type)
return_type = _type_to_string(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,
)
def visit(node: Cursor) -> None:
if node.kind == CursorKind.TYPEDEF_DECL:
name = node.spelling
if not name:
return
underlying = node.underlying_typedef_type
if underlying.kind == TypeKind.POINTER:
pointee = underlying.get_pointee()
if pointee.kind == TypeKind.FUNCTIONPROTO:
process_function_pointer_type(name, node, pointee)
# Recurse into children
if node.kind in (CursorKind.TRANSLATION_UNIT, CursorKind.NAMESPACE):
for c in node.get_children():
visit(c)
if tu.cursor is not None:
visit(tu.cursor)
return sorted(out.values(), key=lambda t: t.name)
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
if isinstance(f, TypedefInfo):
# Host-to-guest
target = "[ebp+8]"
arg_off = 12
align = 0
host_to_guest = True
elif isinstance(f, FuncInfo):
# Guest-to-host
target = f.mangled
arg_off = 8
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 {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:
# No stack args, just align to 16n for the call
lines.append("\tandl $0xFFFFFFF0, %esp")
# Move first two args into ECX/EDX for fastcall
if argc >= 1:
lines.append("\tmovl 8(%ebp), %ecx")
if argc >= 2:
lines.append("\tmovl 12(%ebp), %edx")
# Push remaining args (from last down to the 3rd) so layout matches fastcall
for i in range(argc, 2, -1):
off = 4 * (i + 1) # +1 because EBP offset includes pushed EBP
lines.append(f"\tpushl {off}(%ebp)")
# Call into fastcall stub
lines.append(f"\tcall {mangled}")
raise NotImplementedError(
f"Unsupported target calling convention {f.target_cc} 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
)
# Save frame pointer and use EBP for argument access
lines.append("\tpush ebp")
lines.append("\tmov ebp, esp")
# Get current TIB
if host_to_guest:
lines.append("\tmov edx, [gs:currentThreadTeb@ntpoff]")
else:
lines.append("\tmov edx, [fs:0x18]")
# Save previous fs and gs
lines.append("\tmov cx, fs")
lines.append("\txchg cx, word ptr [edx+0xf98]")
lines.append("\tmov fs, cx")
lines.append("\tmov cx, gs")
lines.append("\txchg cx, word ptr [edx+0xf9a]")
lines.append("\tmov gs, cx")
# TODO: switch stacks here
# Allocate stack space for arguments
if stack_bytes > 0:
lines.append(f"\tsub esp, {stack_bytes}")
# Align stack if needed (must be done after allocating args)
if align > 0:
lines.append(f"\tand esp, ~{align - 1}")
# Load args into registers as needed
if len(reg_indices) > 0:
i = reg_indices[0]
offset = offsets[i]
lines.append(f"\tmov ecx, [ebp+{offset}]")
if len(reg_indices) > 1:
i = reg_indices[1]
offset = offsets[i]
lines.append(f"\tmov edx, [ebp+{offset}]")
# Copy remaining args onto stack
cur_off = 0
for i, arg in enumerate(f.args):
if i in reg_indices:
continue
base = offsets[i]
for part_off in range(0, arg.slot_size, 4):
lines.append(f"\tmov eax, [ebp+{base + part_off}]")
lines.append(f"\tmov [esp+{cur_off + part_off}], eax")
cur_off += arg.slot_size
# Call into target
lines.append(f"\tcall {target}")
# Restore segment registers
if host_to_guest:
lines.append("\tmov edx, [fs:0x18]")
else:
lines.append("\tmov edx, [gs:currentThreadTeb@ntpoff]")
lines.append("\tmov cx, fs")
lines.append("\txchg cx, word ptr [edx+0xf98]")
lines.append("\tmov fs, cx")
lines.append("\tmov cx, gs")
lines.append("\txchg cx, word ptr [edx+0xf9a]")
lines.append("\tmov gs, cx")
# Restore stack and frame pointer
lines.append("\tleave")
# Return to guest
argb = argc * 4
if f.stdcall and argb:
lines.append(f"\tret ${argb}")
if f.source_cc == CallingConv.X86_STDCALL:
ret_bytes = sum(arg.slot_size for arg in f.args)
if ret_bytes > 0:
lines.append(f"\tret {ret_bytes}")
else:
lines.append("\tret")
lines.append(f".size {tramp}, . - {tramp}")
return "\n".join(lines) + "\n"
elif f.source_cc == CallingConv.C:
lines.append("\tret")
else:
raise NotImplementedError(
f"Unsupported source calling convention {f.source_cc} for function {f.name}"
)
def emit_header_mapping(dll: str, funcs: Iterable[FuncInfo]) -> str:
guard = f"WIBO_GEN_{dll.upper()}_TRAMPOLINES_H"
def emit_guest_to_host_thunks(
lines: List[str], dll: str, funcs: Iterable[FuncInfo]
) -> None:
for f in funcs:
thunk = f"thunk_{dll}_{f.name}"
lines.append("")
lines.append(
f"# {f.qualified_ns}::{f.name} (source_cc={f.source_cc.name}, target_cc={f.target_cc.name}, variadic={f.variadic})"
)
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})"
)
lines.append(f".globl {thunk}")
lines.append(f".type {thunk}, @function")
lines.append(f"{thunk}:")
emit_cc_thunk(f, lines)
lines.append(f".size {thunk}, .-{thunk}")
def emit_host_to_guest_thunks(
lines: List[str], typedefs: Iterable[TypedefInfo]
) -> None:
for f in typedefs:
thunk = f"call_{f.name}"
lines.append("")
lines.append(
f"# {f.name} (target_cc={f.target_cc.name}, variadic={f.variadic})"
)
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})"
)
lines.append(f".globl {thunk}")
lines.append(f".weak {thunk}")
lines.append(f".type {thunk}, @function")
lines.append(f"{thunk}:")
emit_cc_thunk(f, lines)
lines.append(f".size {thunk}, .-{thunk}")
def emit_header_mapping(
dll: str, funcs: Iterable[FuncInfo], typedefs: Iterable[TypedefInfo]
) -> str:
guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H"
lines: List[str] = []
lines.append("/* Auto-generated; DO NOT EDIT. */")
lines.append(f"#ifndef {guard}")
@@ -193,19 +516,36 @@ def emit_header_mapping(dll: str, funcs: Iterable[FuncInfo]) -> str:
lines.append("#include <stddef.h>")
lines.append("#include <string.h>")
lines.append('#ifdef __cplusplus\nextern "C" {\n#endif')
# Guest-to-host thunk functions
for f in funcs:
tramp = f"thunk_{dll}_{f.name}"
lines.append(f"void {tramp}(void);")
thunk = f"thunk_{dll}_{f.name}"
lines.append(f"void {thunk}(void);")
# Host-to-guest thunk functions
for td in typedefs:
thunk = f"call_{td.name}"
if td.variadic:
continue
params = [f"{td.name} fn"]
for i, arg in enumerate(td.args):
params.append(f"{arg.type_str} arg{i}")
param_list = ", ".join(params)
lines.append(f"{td.return_type} {thunk}({param_list});")
lines.append("#ifdef __cplusplus\n}\n#endif")
lines.append("")
# name->address helper for resolveByName
lines.append("static inline void *%s_trampoline_by_name(const char *name) {" % dll)
lines.append("static inline void *%sThunkByName(const char *name) {" % dll)
for f in funcs:
lines.append(
f'\tif (strcmp(name, "{f.name}") == 0) return (void*)&thunk_{dll}_{f.name};'
)
lines.append("\treturn NULL;")
lines.append("}")
lines.append(f"#endif /* {guard} */\n")
return "\n".join(lines)
@@ -230,12 +570,23 @@ def main() -> int:
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)
if not funcs:
sys.stderr.write("No functions found for generation.\n")
typedefs = collect_typedefs(tu)
if not funcs and not typedefs:
sys.stderr.write("No functions or typedefs found for generation.\n")
return 1
asm = emit_x86_asm_trampolines(args.dll, funcs)
hdr = emit_header_mapping(args.dll, funcs)
lines: List[str] = []
lines.append("# Auto-generated thunks; DO NOT EDIT.")
lines.append(".intel_syntax noprefix")
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)
asm = "\n".join(lines) + "\n"
hdr = emit_header_mapping(args.dll, funcs, typedefs)
args.out_asm.parent.mkdir(parents=True, exist_ok=True)
args.out_hdr.parent.mkdir(parents=True, exist_ok=True)