diff --git a/CMakeLists.txt b/CMakeLists.txt index 7bda4e3..5094d7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,12 @@ FetchContent_MakeAvailable(mimalloc) include_directories(.) add_executable(wibo dll/advapi32.cpp - dll/advapi32/winreg.cpp + dll/advapi32/internal.cpp + dll/advapi32/processthreadsapi.cpp + dll/advapi32/securitybaseapi.cpp + dll/advapi32/winbase.cpp dll/advapi32/wincrypt.cpp + dll/advapi32/winreg.cpp dll/bcrypt.cpp dll/crt.cpp dll/kernel32.cpp diff --git a/common.h b/common.h index 75916d4..e602f77 100644 --- a/common.h +++ b/common.h @@ -42,6 +42,7 @@ using HGLOBAL = HANDLE; using HLOCAL = HANDLE; using HRSRC = HANDLE; using LPHANDLE = HANDLE *; +using PHANDLE = HANDLE *; using PVOID = void *; using LPVOID = void *; using LPCVOID = const void *; @@ -56,6 +57,12 @@ using LONG = int32_t; using PLONG = LONG *; using ULONG = uint32_t; using PULONG = ULONG *; +struct LUID { + DWORD LowPart; + LONG HighPart; +}; +using PLUID = LUID *; +using LPLUID = LUID *; using LARGE_INTEGER = int64_t; using PLARGE_INTEGER = LARGE_INTEGER *; using ULONG_PTR = uintptr_t; @@ -84,6 +91,7 @@ using BOOLEAN = unsigned char; using UINT = unsigned int; using HKEY = void *; using PHKEY = HKEY *; +using PSID = void *; using REGSAM = DWORD; using LSTATUS = LONG; using LCID = DWORD; diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index 4e863f5..afa460c 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -1,540 +1,106 @@ -#include "common.h" -#include "advapi32/winreg.h" +#include "advapi32/processthreadsapi.h" +#include "advapi32/securitybaseapi.h" +#include "advapi32/winbase.h" #include "advapi32/wincrypt.h" -#include "errors.h" -#include "handles.h" -#include "strutil.h" +#include "advapi32/winreg.h" +#include "common.h" -#include -#include #include -#include -#include -#include namespace { - struct Luid; - static std::mutex privilegeMapMutex; - static std::unordered_map privilegeLuidCache; - constexpr DWORD SECURITY_DESCRIPTOR_REVISION = 1; - constexpr uint16_t SE_DACL_PRESENT = 0x0004; - constexpr uint16_t SE_DACL_DEFAULTED = 0x0008; +void *resolveByName(const char *name) { + // processthreadsapi.h + if (strcmp(name, "OpenProcessToken") == 0) + return (void *)advapi32::OpenProcessToken; - struct SecurityDescriptor { - uint8_t Revision = 0; - uint8_t Sbz1 = 0; - uint16_t Control = 0; - void *Owner = nullptr; - void *Group = nullptr; - void *Sacl = nullptr; - void *Dacl = nullptr; - }; + // securitybaseapi.h + if (strcmp(name, "InitializeAcl") == 0) + return (void *)advapi32::InitializeAcl; + if (strcmp(name, "AddAccessAllowedAce") == 0) + return (void *)advapi32::AddAccessAllowedAce; + if (strcmp(name, "FindFirstFreeAce") == 0) + return (void *)advapi32::FindFirstFreeAce; + if (strcmp(name, "GetSidIdentifierAuthority") == 0) + return (void *)advapi32::GetSidIdentifierAuthority; + if (strcmp(name, "GetSidSubAuthorityCount") == 0) + return (void *)advapi32::GetSidSubAuthorityCount; + if (strcmp(name, "GetSidSubAuthority") == 0) + return (void *)advapi32::GetSidSubAuthority; + if (strcmp(name, "ImpersonateLoggedOnUser") == 0) + return (void *)advapi32::ImpersonateLoggedOnUser; + if (strcmp(name, "DuplicateTokenEx") == 0) + return (void *)advapi32::DuplicateTokenEx; + if (strcmp(name, "CopySid") == 0) + return (void *)advapi32::CopySid; + if (strcmp(name, "GetSecurityDescriptorDacl") == 0) + return (void *)advapi32::GetSecurityDescriptorDacl; + if (strcmp(name, "SetKernelObjectSecurity") == 0) + return (void *)advapi32::SetKernelObjectSecurity; + if (strcmp(name, "InitializeSecurityDescriptor") == 0) + return (void *)advapi32::InitializeSecurityDescriptor; + if (strcmp(name, "SetSecurityDescriptorDacl") == 0) + return (void *)advapi32::SetSecurityDescriptorDacl; + if (strcmp(name, "GetTokenInformation") == 0) + return (void *)advapi32::GetTokenInformation; + if (strcmp(name, "AdjustTokenPrivileges") == 0) + return (void *)advapi32::AdjustTokenPrivileges; + if (strcmp(name, "SetTokenInformation") == 0) + return (void *)advapi32::SetTokenInformation; - struct TokenObject { - HANDLE processHandle = nullptr; - DWORD desiredAccess = 0; - }; + // winbase.h + if (strcmp(name, "LookupAccountSidW") == 0) + return (void *)advapi32::LookupAccountSidW; + if (strcmp(name, "LookupPrivilegeValueA") == 0) + return (void *)advapi32::LookupPrivilegeValueA; + if (strcmp(name, "LookupPrivilegeValueW") == 0) + return (void *)advapi32::LookupPrivilegeValueW; + if (strcmp(name, "GetUserNameA") == 0) + return (void *)advapi32::GetUserNameA; + if (strcmp(name, "GetUserNameW") == 0) + return (void *)advapi32::GetUserNameW; - struct SidIdentifierAuthority { - uint8_t Value[6] = {0}; - }; - - struct Sid { - uint8_t Revision = 1; - uint8_t SubAuthorityCount = 0; - SidIdentifierAuthority IdentifierAuthority = {}; - uint32_t SubAuthority[1] = {0}; - }; - - struct SidAndAttributes { - Sid *SidPtr = nullptr; - DWORD Attributes = 0; - }; - - struct TokenUserData { - SidAndAttributes User; - }; - - enum SID_NAME_USE { - SidTypeUser = 1, - SidTypeGroup, - SidTypeDomain, - SidTypeAlias, - SidTypeWellKnownGroup, - SidTypeDeletedAccount, - SidTypeInvalid, - SidTypeUnknown, - SidTypeComputer, - SidTypeLabel - }; - - bool isLocalSystemSid(const Sid *sid) { - if (!sid) { - return false; - } - static const uint8_t ntAuthority[6] = {0, 0, 0, 0, 0, 5}; - if (sid->Revision != 1 || sid->SubAuthorityCount != 1) { - return false; - } - for (size_t i = 0; i < 6; ++i) { - if (sid->IdentifierAuthority.Value[i] != ntAuthority[i]) { - return false; - } - } - return sid->SubAuthority[0] == 18; // SECURITY_LOCAL_SYSTEM_RID - } - - struct Luid { - uint32_t LowPart = 0; - int32_t HighPart = 0; - }; - - struct LuidAndAttributes { - Luid value; - DWORD Attributes = 0; - }; - - struct TokenStatisticsData { - Luid tokenId; - Luid authenticationId; - int64_t expirationTime = 0; - uint32_t tokenType = 0; - uint32_t impersonationLevel = 0; - uint32_t dynamicCharged = 0; - uint32_t dynamicAvailable = 0; - uint32_t groupCount = 0; - uint32_t privilegeCount = 0; - Luid modifiedId; - }; - -} - -namespace advapi32 { - BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle) { - DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle); - if (!TokenHandle) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto *token = new TokenObject; - token->processHandle = ProcessHandle; - token->desiredAccess = DesiredAccess; - handles::Data data; - data.type = handles::TYPE_TOKEN; - data.ptr = token; - data.size = 0; - *TokenHandle = handles::allocDataHandle(data); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - void releaseToken(void *tokenPtr) { - delete reinterpret_cast(tokenPtr); - } - - BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, unsigned int TokenInformationClass, void *TokenInformation, unsigned int TokenInformationLength, unsigned int *ReturnLength) { - DEBUG_LOG("GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation, - TokenInformationLength, ReturnLength); - if (!ReturnLength) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto data = handles::dataFromHandle(TokenHandle, false); - if (data.type != handles::TYPE_TOKEN) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - constexpr unsigned int TokenUserClass = 1; // TokenUser - constexpr unsigned int TokenStatisticsClass = 10; // TokenStatistics - constexpr unsigned int TokenElevationClass = 20; // TokenElevation - constexpr unsigned int TokenPrimaryGroupClass = 5; // TokenPrimaryGroup - if (TokenInformationClass == TokenUserClass) { - constexpr size_t sidSize = sizeof(Sid); - constexpr size_t tokenUserSize = sizeof(TokenUserData); - const auto required = static_cast(tokenUserSize + sidSize); - *ReturnLength = required; - if (!TokenInformation || TokenInformationLength < required) { - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - auto *tokenUser = reinterpret_cast(TokenInformation); - auto *sid = reinterpret_cast(reinterpret_cast(TokenInformation) + tokenUserSize); - SidIdentifierAuthority ntAuthority = {{0, 0, 0, 0, 0, 5}}; - sid->Revision = 1; - sid->SubAuthorityCount = 1; - sid->IdentifierAuthority = ntAuthority; - sid->SubAuthority[0] = 18; // SECURITY_LOCAL_SYSTEM_RID - tokenUser->User.SidPtr = sid; - tokenUser->User.Attributes = 0; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (TokenInformationClass == TokenStatisticsClass) { - const unsigned int required = sizeof(TokenStatisticsData); - *ReturnLength = required; - if (!TokenInformation || TokenInformationLength < required) { - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - auto *stats = reinterpret_cast(TokenInformation); - *stats = {}; - stats->tokenType = 1; // TokenPrimary - stats->impersonationLevel = 0; // SecurityAnonymous - stats->tokenId.LowPart = 1; - stats->authenticationId.LowPart = 1; - stats->modifiedId.LowPart = 1; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (TokenInformationClass == TokenElevationClass) { - const unsigned int required = sizeof(DWORD); - *ReturnLength = required; - if (!TokenInformation || TokenInformationLength < required) { - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - *reinterpret_cast(TokenInformation) = 0; // not elevated - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (TokenInformationClass == TokenPrimaryGroupClass) { - struct TokenPrimaryGroupStub { - Sid *PrimaryGroup; - }; - constexpr size_t sidSize = sizeof(Sid); - constexpr size_t headerSize = sizeof(TokenPrimaryGroupStub); - const unsigned int required = static_cast(headerSize + sidSize); - *ReturnLength = required; - if (!TokenInformation || TokenInformationLength < required) { - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - auto *groupInfo = reinterpret_cast(TokenInformation); - auto *sid = reinterpret_cast(reinterpret_cast(TokenInformation) + headerSize); - sid->Revision = 1; - sid->SubAuthorityCount = 1; - sid->IdentifierAuthority = {{0, 0, 0, 0, 0, 5}}; - sid->SubAuthority[0] = 18; // SECURITY_LOCAL_SYSTEM_RID - groupInfo->PrimaryGroup = sid; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - - BOOL WIN_FUNC LookupAccountSidW(const uint16_t *lpSystemName, const void *sidPointer, uint16_t *Name, - unsigned long *cchName, uint16_t *ReferencedDomainName, - unsigned long *cchReferencedDomainName, SID_NAME_USE *peUse) { - std::string systemName = lpSystemName ? wideStringToString(lpSystemName) : std::string("(null)"); - DEBUG_LOG("LookupAccountSidW(%s, %p, %p, %p, %p, %p, %p)\n", systemName.c_str(), sidPointer, Name, cchName, - ReferencedDomainName, cchReferencedDomainName, peUse); - (void) lpSystemName; // Only local lookup supported - if (!sidPointer || !cchName || !cchReferencedDomainName || !peUse) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto *sid = reinterpret_cast(sidPointer); - if (!isLocalSystemSid(sid)) { - wibo::lastError = ERROR_NONE_MAPPED; - return FALSE; - } - static constexpr uint16_t accountName[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'}; - static constexpr uint16_t domainName[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'}; - unsigned long requiredAccount = wstrlen(accountName) + 1; - unsigned long requiredDomain = wstrlen(domainName) + 1; - if (!Name || *cchName < requiredAccount || !ReferencedDomainName || *cchReferencedDomainName < requiredDomain) { - *cchName = requiredAccount; - *cchReferencedDomainName = requiredDomain; - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - std::copy_n(accountName, requiredAccount, Name); - std::copy_n(domainName, requiredDomain, ReferencedDomainName); - *peUse = SidTypeWellKnownGroup; - *cchName = requiredAccount - 1; - *cchReferencedDomainName = requiredDomain - 1; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - static Luid generateDeterministicLuid(const std::string &normalizedName) { - uint32_t hash = 2166136261u; - for (unsigned char ch : normalizedName) { - hash ^= ch; - hash *= 16777619u; - } - if (hash == 0) { - hash = 1; - } - Luid result{}; - result.LowPart = hash; - result.HighPart = 0; - return result; - } - - static std::string normalizePrivilegeName(const std::string &name) { - std::string normalized; - normalized.reserve(name.size()); - for (unsigned char ch : name) { - if (ch == '\r' || ch == '\n' || ch == '\t') { - continue; - } - normalized.push_back(static_cast(std::tolower(ch))); - } - return normalized; - } - - static Luid lookupOrGeneratePrivilegeLuid(const std::string &normalizedName) { - std::lock_guard lock(privilegeMapMutex); - auto cached = privilegeLuidCache.find(normalizedName); - if (cached != privilegeLuidCache.end()) { - return cached->second; - } - static const std::unordered_map predefined = { - {"secreatepagefileprivilege", 0x00000002}, - {"seshutdownprivilege", 0x00000003}, - {"sebackupprivilege", 0x00000004}, - {"serestoreprivilege", 0x00000005}, - {"sechangenotifyprivilege", 0x00000006}, - {"seassignprimarytokenprivilege", 0x00000007}, - {"seincreasequotaprivilege", 0x00000008}, - {"seincreasebasepriorityprivilege", 0x00000009}, - {"seloaddriverprivilege", 0x0000000a}, - {"setakeownershipprivilege", 0x0000000b}, - {"sesystemtimeprivilege", 0x0000000c}, - {"sesystemenvironmentprivilege", 0x0000000d}, - {"setcbprivilege", 0x0000000e}, - {"sedebugprivilege", 0x0000000f}, - {"semanagevolumeprivilege", 0x00000010}, - {"seimpersonateprivilege", 0x00000011}, - {"secreateglobalprivilege", 0x00000012}, - {"sesecurityprivilege", 0x00000013}, - {"selockmemoryprivilege", 0x00000014}, - {"seundockprivilege", 0x00000015}, - {"seremoteshutdownprivilege", 0x00000016} - }; - auto known = predefined.find(normalizedName); - Luid luid{}; - if (known != predefined.end()) { - luid.LowPart = known->second; - luid.HighPart = 0; - } else { - luid = generateDeterministicLuid(normalizedName); - } - privilegeLuidCache.emplace(normalizedName, luid); - return luid; - } - - BOOL WIN_FUNC LookupPrivilegeValueA(const char *lpSystemName, const char *lpName, Luid *lpLuid) { - DEBUG_LOG("LookupPrivilegeValueA(%s, %s, %p)\n", - lpSystemName ? lpSystemName : "", - lpName ? lpName : "", - lpLuid); - if (!lpName || !lpLuid) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - if (lpSystemName && lpSystemName[0] != '\0') { - DEBUG_LOG("-> remote system unsupported\n"); - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - std::string normalized = normalizePrivilegeName(lpName); - if (normalized.empty()) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - Luid luid = lookupOrGeneratePrivilegeLuid(normalized); - *lpLuid = luid; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC LookupPrivilegeValueW(const uint16_t *lpSystemName, const uint16_t *lpName, Luid *lpLuid) { - DEBUG_LOG("LookupPrivilegeValueW(%ls, %ls, %p)\n", - lpSystemName ? reinterpret_cast(lpSystemName) : L"", - lpName ? reinterpret_cast(lpName) : L"", - lpLuid); - if (!lpName || !lpLuid) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - if (lpSystemName && lpSystemName[0] != 0) { - std::string host = wideStringToString(lpSystemName); - if (!host.empty()) { - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - } - std::string ansiName = wideStringToString(lpName); - return LookupPrivilegeValueA(nullptr, ansiName.c_str(), lpLuid); - } - - struct TokenPrivilegesHeader { - DWORD PrivilegeCount = 0; - }; - - BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, void *NewState, DWORD BufferLength, - void *PreviousState, PDWORD ReturnLength) { - DEBUG_LOG("AdjustTokenPrivileges(%p, %d, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, - NewState, BufferLength, PreviousState, ReturnLength); - (void) DisableAllPrivileges; - (void) NewState; - auto data = handles::dataFromHandle(TokenHandle, false); - if (data.type != handles::TYPE_TOKEN) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - if (PreviousState) { - if (BufferLength < sizeof(TokenPrivilegesHeader)) { - if (ReturnLength) { - *ReturnLength = sizeof(TokenPrivilegesHeader); - } - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - auto *header = reinterpret_cast(PreviousState); - header->PrivilegeCount = 0; - if (ReturnLength) { - *ReturnLength = sizeof(TokenPrivilegesHeader); - } - } else if (ReturnLength) { - *ReturnLength = 0; - } - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC InitializeSecurityDescriptor(void *pSecurityDescriptor, DWORD dwRevision) { - DEBUG_LOG("InitializeSecurityDescriptor(%p, %u)\n", pSecurityDescriptor, dwRevision); - if (!pSecurityDescriptor) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - if (dwRevision != SECURITY_DESCRIPTOR_REVISION) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto *descriptor = static_cast(pSecurityDescriptor); - descriptor->Revision = static_cast(dwRevision); - descriptor->Sbz1 = 0; - descriptor->Control = 0; - descriptor->Owner = nullptr; - descriptor->Group = nullptr; - descriptor->Sacl = nullptr; - descriptor->Dacl = nullptr; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC SetSecurityDescriptorDacl(void *pSecurityDescriptor, BOOL bDaclPresent, void *pDacl, BOOL bDaclDefaulted) { - DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted); - if (!pSecurityDescriptor) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto *descriptor = static_cast(pSecurityDescriptor); - if (descriptor->Revision != SECURITY_DESCRIPTOR_REVISION) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - uint16_t control = static_cast(descriptor->Control & ~(SE_DACL_PRESENT | SE_DACL_DEFAULTED)); - if (bDaclPresent) { - control = static_cast(control | SE_DACL_PRESENT); - if (bDaclDefaulted) { - control = static_cast(control | SE_DACL_DEFAULTED); - } - descriptor->Dacl = pDacl; - } else { - descriptor->Dacl = nullptr; - } - descriptor->Control = control; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC GetUserNameA(char *lpBuffer, DWORD *pcbBuffer) { - DEBUG_LOG("GetUserNameA(%p, %p)\n", lpBuffer, pcbBuffer); - if (!pcbBuffer) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - const char *name = "SYSTEM"; - size_t needed = std::strlen(name) + 1; - if (!lpBuffer || *pcbBuffer < needed) { - *pcbBuffer = static_cast(needed); - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - std::memcpy(lpBuffer, name, needed); - *pcbBuffer = static_cast(needed); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC GetUserNameW(uint16_t *lpBuffer, DWORD *pcbBuffer) { - DEBUG_LOG("GetUserNameW(%p, %p)\n", lpBuffer, pcbBuffer); - if (!pcbBuffer) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - const char16_t name[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'}; - size_t needed = (std::size(name)); - if (!lpBuffer || *pcbBuffer < needed) { - *pcbBuffer = static_cast(needed); - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - std::memcpy(lpBuffer, name, needed * sizeof(uint16_t)); - *pcbBuffer = static_cast(needed); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC SetTokenInformation(HANDLE TokenHandle, unsigned int TokenInformationClass, void *TokenInformation, DWORD TokenInformationLength) { - DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation, TokenInformationLength); - (void) TokenInformationClass; - (void) TokenInformation; - (void) TokenInformationLength; - auto data = handles::dataFromHandle(TokenHandle, false); - if (data.type != handles::TYPE_TOKEN) { - wibo::lastError = ERROR_INVALID_HANDLE; - return FALSE; - } - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } -} - -static void *resolveByName(const char *name) { - // winreg.h - if (strcmp(name, "RegOpenKeyExA") == 0) return (void *) advapi32::RegOpenKeyExA; - if (strcmp(name, "RegOpenKeyExW") == 0) return (void *) advapi32::RegOpenKeyExW; - if (strcmp(name, "RegCloseKey") == 0) return (void *) advapi32::RegCloseKey; // wincrypt.h - if (strcmp(name, "CryptReleaseContext") == 0) return (void*) advapi32::CryptReleaseContext; - if (strcmp(name, "CryptAcquireContextW") == 0) return (void*) advapi32::CryptAcquireContextW; - if (strcmp(name, "CryptGenRandom") == 0) return (void*) advapi32::CryptGenRandom; - if (strcmp(name, "CryptCreateHash") == 0) return (void*) advapi32::CryptCreateHash; - if (strcmp(name, "CryptHashData") == 0) return (void*) advapi32::CryptHashData; - if (strcmp(name, "CryptGetHashParam") == 0) return (void*) advapi32::CryptGetHashParam; - if (strcmp(name, "CryptDestroyHash") == 0) return (void*) advapi32::CryptDestroyHash; - if (strcmp(name, "OpenProcessToken") == 0) return (void*) advapi32::OpenProcessToken; - if (strcmp(name, "GetTokenInformation") == 0) return (void*) advapi32::GetTokenInformation; - if (strcmp(name, "LookupAccountSidW") == 0) return (void*) advapi32::LookupAccountSidW; - if (strcmp(name, "InitializeSecurityDescriptor") == 0) return (void*) advapi32::InitializeSecurityDescriptor; - if (strcmp(name, "SetSecurityDescriptorDacl") == 0) return (void*) advapi32::SetSecurityDescriptorDacl; - if (strcmp(name, "LookupPrivilegeValueA") == 0) return (void*) advapi32::LookupPrivilegeValueA; - if (strcmp(name, "LookupPrivilegeValueW") == 0) return (void*) advapi32::LookupPrivilegeValueW; - if (strcmp(name, "AdjustTokenPrivileges") == 0) return (void*) advapi32::AdjustTokenPrivileges; - if (strcmp(name, "GetUserNameA") == 0) return (void*) advapi32::GetUserNameA; - if (strcmp(name, "GetUserNameW") == 0) return (void*) advapi32::GetUserNameW; - if (strcmp(name, "SetTokenInformation") == 0) return (void*) advapi32::SetTokenInformation; + if (strcmp(name, "CryptReleaseContext") == 0) + return (void *)advapi32::CryptReleaseContext; + if (strcmp(name, "CryptAcquireContextW") == 0) + return (void *)advapi32::CryptAcquireContextW; + if (strcmp(name, "CryptGenRandom") == 0) + return (void *)advapi32::CryptGenRandom; + if (strcmp(name, "CryptCreateHash") == 0) + return (void *)advapi32::CryptCreateHash; + if (strcmp(name, "CryptHashData") == 0) + return (void *)advapi32::CryptHashData; + if (strcmp(name, "CryptGetHashParam") == 0) + return (void *)advapi32::CryptGetHashParam; + if (strcmp(name, "CryptDestroyHash") == 0) + return (void *)advapi32::CryptDestroyHash; + + // winreg.h + if (strcmp(name, "RegCreateKeyExA") == 0) + return (void *)advapi32::RegCreateKeyExA; + if (strcmp(name, "RegCreateKeyExW") == 0) + return (void *)advapi32::RegCreateKeyExW; + if (strcmp(name, "RegOpenKeyExA") == 0) + return (void *)advapi32::RegOpenKeyExA; + if (strcmp(name, "RegOpenKeyExW") == 0) + return (void *)advapi32::RegOpenKeyExW; + if (strcmp(name, "RegQueryValueExA") == 0) + return (void *)advapi32::RegQueryValueExA; + if (strcmp(name, "RegQueryValueExW") == 0) + return (void *)advapi32::RegQueryValueExW; + if (strcmp(name, "RegEnumKeyExA") == 0) + return (void *)advapi32::RegEnumKeyExA; + if (strcmp(name, "RegEnumKeyExW") == 0) + return (void *)advapi32::RegEnumKeyExW; + if (strcmp(name, "RegCloseKey") == 0) + return (void *)advapi32::RegCloseKey; + return nullptr; } +} // namespace + wibo::Module lib_advapi32 = { (const char *[]){ "advapi32", diff --git a/dll/advapi32/internal.cpp b/dll/advapi32/internal.cpp new file mode 100644 index 0000000..d46c627 --- /dev/null +++ b/dll/advapi32/internal.cpp @@ -0,0 +1,98 @@ +#include "internal.h" + +#include +#include +#include + +namespace { + +constexpr DWORD SECURITY_LOCAL_SYSTEM_RID = 18; + +constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5}; + +std::mutex privilegeMapMutex; +std::unordered_map privilegeLuidCache; + +LUID generateDeterministicLuid(const std::string &normalizedName) { + uint32_t hash = 2166136261u; + for (unsigned char ch : normalizedName) { + hash ^= ch; + hash *= 16777619u; + } + if (hash == 0) { + hash = 1; + } + LUID luid{}; + luid.LowPart = hash; + luid.HighPart = 0; + return luid; +} + +} // namespace + +namespace advapi32 { + +bool isLocalSystemSid(const Sid *sid) { + if (!sid) { + return false; + } + if (sid->Revision != 1 || sid->SubAuthorityCount != 1) { + return false; + } + for (size_t i = 0; i < std::size(kNtAuthority); ++i) { + if (sid->IdentifierAuthority.Value[i] != kNtAuthority[i]) { + return false; + } + } + return sid->SubAuthority[0] == SECURITY_LOCAL_SYSTEM_RID; +} + +bool writeLocalSystemSid(Sid *sid) { + if (!sid) { + return false; + } + sid->Revision = 1; + sid->SubAuthorityCount = 1; + SidIdentifierAuthority authority{}; + for (size_t i = 0; i < std::size(kNtAuthority); ++i) { + authority.Value[i] = kNtAuthority[i]; + } + sid->IdentifierAuthority = authority; + sid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID; + return true; +} + +std::string normalizePrivilegeName(const std::string &name) { + std::string normalized; + normalized.reserve(name.size()); + for (unsigned char ch : name) { + normalized.push_back(static_cast(std::tolower(ch))); + } + return normalized; +} + +LUID lookupOrGeneratePrivilegeLuid(const std::string &normalizedName) { + std::lock_guard lock(privilegeMapMutex); + static const std::unordered_map predefined = { + {"se_debug_name", 0x14}, + {"se_shutdown_name", 0x13}, + }; + auto it = privilegeLuidCache.find(normalizedName); + if (it != privilegeLuidCache.end()) { + return it->second; + } + LUID luid{}; + auto predefinedIt = predefined.find(normalizedName); + if (predefinedIt != predefined.end()) { + luid.LowPart = predefinedIt->second; + luid.HighPart = 0; + } else { + luid = generateDeterministicLuid(normalizedName); + } + privilegeLuidCache[normalizedName] = luid; + return luid; +} + +void releaseToken(void *tokenPtr) { delete reinterpret_cast(tokenPtr); } + +} // namespace advapi32 diff --git a/dll/advapi32/internal.h b/dll/advapi32/internal.h new file mode 100644 index 0000000..9dba424 --- /dev/null +++ b/dll/advapi32/internal.h @@ -0,0 +1,30 @@ +#pragma once + +#include "common.h" +#include "securitybaseapi.h" + +#include + +namespace advapi32 { + +struct TokenObject { + HANDLE processHandle; + DWORD desiredAccess; +}; + +using SidIdentifierAuthority = SID_IDENTIFIER_AUTHORITY; + +struct Sid { + BYTE Revision; + BYTE SubAuthorityCount; + SidIdentifierAuthority IdentifierAuthority; + DWORD SubAuthority[1]; +}; + +bool isLocalSystemSid(const Sid *sid); +bool writeLocalSystemSid(Sid *sid); +std::string normalizePrivilegeName(const std::string &name); +LUID lookupOrGeneratePrivilegeLuid(const std::string &normalizedName); +void releaseToken(void *tokenPtr); + +} // namespace advapi32 diff --git a/dll/advapi32/processthreadsapi.cpp b/dll/advapi32/processthreadsapi.cpp new file mode 100644 index 0000000..03fc67e --- /dev/null +++ b/dll/advapi32/processthreadsapi.cpp @@ -0,0 +1,27 @@ +#include "processthreadsapi.h" + +#include "errors.h" +#include "handles.h" +#include "internal.h" + +namespace advapi32 { + +BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle) { + DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle); + if (!TokenHandle) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto *token = new TokenObject; + token->processHandle = ProcessHandle; + token->desiredAccess = DesiredAccess; + handles::Data data; + data.type = handles::TYPE_TOKEN; + data.ptr = token; + data.size = sizeof(TokenObject); + *TokenHandle = handles::allocDataHandle(data); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +} // namespace advapi32 diff --git a/dll/advapi32/processthreadsapi.h b/dll/advapi32/processthreadsapi.h new file mode 100644 index 0000000..52cf4c1 --- /dev/null +++ b/dll/advapi32/processthreadsapi.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common.h" + +namespace advapi32 { + +BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle); + +} // namespace advapi32 diff --git a/dll/advapi32/securitybaseapi.cpp b/dll/advapi32/securitybaseapi.cpp new file mode 100644 index 0000000..dfd4f7f --- /dev/null +++ b/dll/advapi32/securitybaseapi.cpp @@ -0,0 +1,518 @@ +#include "securitybaseapi.h" + +#include "errors.h" +#include "handles.h" +#include "internal.h" + +#include +#include +#include + +namespace { + +using advapi32::Sid; + +constexpr size_t kAceAlignment = 4; +constexpr DWORD ERROR_REVISION_MISMATCH = 1306; +constexpr DWORD ERROR_INVALID_ACL = 1336; +constexpr DWORD ERROR_INVALID_SID = 1337; +constexpr DWORD ERROR_ALLOTTED_SPACE_EXCEEDED = 1344; +constexpr DWORD ERROR_INVALID_SECURITY_DESCR = 1338; + +size_t alignToDword(size_t value) { return (value + (kAceAlignment - 1)) & ~(kAceAlignment - 1); } + +size_t sidLength(const Sid *sid) { + if (!sid) { + return 0; + } + if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { + return 0; + } + size_t base = sizeof(Sid) - sizeof(DWORD); + size_t extra = static_cast(sid->SubAuthorityCount) * sizeof(DWORD); + return base + extra; +} + +bool computeAclUsedSize(const ACL *acl, size_t capacity, size_t &used) { + if (!acl || capacity < sizeof(ACL)) { + return false; + } + size_t offset = sizeof(ACL); + const BYTE *base = reinterpret_cast(acl); + for (WORD i = 0; i < acl->AceCount; ++i) { + if (offset + sizeof(ACE_HEADER) > capacity) { + return false; + } + const auto *header = reinterpret_cast(base + offset); + if (header->AceSize < sizeof(ACE_HEADER)) { + return false; + } + size_t aceSize = header->AceSize; + if (offset + aceSize > capacity) { + return false; + } + offset += aceSize; + } + used = offset; + return true; +} + +struct SidAndAttributes { + Sid *SidPtr; + DWORD Attributes; +}; + +struct TokenUserData { + SidAndAttributes User; +}; + +struct TokenStatisticsData { + LUID tokenId{}; + LUID authenticationId{}; + LARGE_INTEGER expirationTime{}; + DWORD tokenType = 0; + DWORD impersonationLevel = 0; + DWORD dynamicCharged = 0; + DWORD dynamicAvailable = 0; + DWORD groupCount = 0; + DWORD privilegeCount = 0; + LUID modifiedId{}; +}; + +struct TokenPrimaryGroupStub { + Sid *PrimaryGroup; +}; + +} // namespace + +namespace advapi32 { + +BOOL WIN_FUNC InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision) { + DEBUG_LOG("InitializeAcl(%p, %u, %u)\n", pAcl, nAclLength, dwAclRevision); + if (!pAcl) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + if (nAclLength < sizeof(ACL) || nAclLength > std::numeric_limits::max() || (nAclLength & 0x3) != 0) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + BYTE revision = static_cast(dwAclRevision); + switch (revision) { + case ACL_REVISION1: + case ACL_REVISION2: + case ACL_REVISION3: + case ACL_REVISION4: + break; + default: + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + pAcl->AclRevision = revision; + pAcl->Sbz1 = 0; + pAcl->AclSize = static_cast(sizeof(ACL)); + pAcl->AceCount = 0; + pAcl->Sbz2 = static_cast(nAclLength); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid) { + DEBUG_LOG("AddAccessAllowedAce(%p, %u, 0x%x, %p)\n", pAcl, dwAceRevision, AccessMask, pSid); + if (!pAcl || !pSid) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + BYTE revision = static_cast(dwAceRevision); + switch (revision) { + case ACL_REVISION1: + case ACL_REVISION2: + case ACL_REVISION3: + case ACL_REVISION4: + break; + default: + wibo::lastError = ERROR_REVISION_MISMATCH; + return FALSE; + } + if (pAcl->AclRevision < revision) { + wibo::lastError = ERROR_REVISION_MISMATCH; + return FALSE; + } + if (pAcl->AceCount == std::numeric_limits::max()) { + wibo::lastError = ERROR_ALLOTTED_SPACE_EXCEEDED; + return FALSE; + } + size_t capacity = pAcl->Sbz2 ? pAcl->Sbz2 : pAcl->AclSize; + if (capacity < sizeof(ACL)) { + wibo::lastError = ERROR_INVALID_ACL; + return FALSE; + } + size_t used = 0; + if (!computeAclUsedSize(pAcl, capacity, used)) { + wibo::lastError = ERROR_INVALID_ACL; + return FALSE; + } + if (used > pAcl->AclSize) { + // Clamp to the computed size to avoid propagating inconsistent data. + pAcl->AclSize = static_cast(used); + } + const auto *sid = reinterpret_cast(pSid); + size_t sidLen = sidLength(sid); + if (sidLen == 0 || sidLen > capacity) { + wibo::lastError = ERROR_INVALID_SID; + return FALSE; + } + size_t aceSize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sidLen; + aceSize = alignToDword(aceSize); + if (aceSize > std::numeric_limits::max()) { + wibo::lastError = ERROR_INVALID_SID; + return FALSE; + } + if (used + aceSize > capacity) { + wibo::lastError = ERROR_ALLOTTED_SPACE_EXCEEDED; + return FALSE; + } + auto *dest = reinterpret_cast(pAcl) + used; + std::memset(dest, 0, aceSize); + auto *ace = reinterpret_cast(dest); + ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; + ace->Header.AceFlags = 0; + ace->Header.AceSize = static_cast(aceSize); + ace->Mask = AccessMask; + std::memcpy(&ace->SidStart, sid, sidLen); + pAcl->AceCount = static_cast(pAcl->AceCount + 1); + pAcl->AclSize = static_cast(used + aceSize); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC FindFirstFreeAce(PACL pAcl, LPVOID *pAce) { + DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce); + if (!pAce) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + *pAce = nullptr; + if (!pAcl) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + size_t capacity = pAcl->Sbz2 ? pAcl->Sbz2 : pAcl->AclSize; + size_t used = 0; + if (!computeAclUsedSize(pAcl, capacity, used)) { + wibo::lastError = ERROR_INVALID_ACL; + return FALSE; + } + *pAce = reinterpret_cast(pAcl) + used; + pAcl->AclSize = static_cast(std::max(pAcl->AclSize, used)); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, + LPBOOL lpbDaclDefaulted) { + DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl, + lpbDaclDefaulted); + if (!pSecurityDescriptor) { + wibo::lastError = ERROR_INVALID_SECURITY_DESCR; + return FALSE; + } + if (!lpbDaclPresent) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + if (pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) { + wibo::lastError = ERROR_INVALID_SECURITY_DESCR; + return FALSE; + } + BOOL hasDacl = (pSecurityDescriptor->Control & SE_DACL_PRESENT) ? TRUE : FALSE; + *lpbDaclPresent = hasDacl; + if (!hasDacl) { + if (pDacl) { + *pDacl = nullptr; + } + if (lpbDaclDefaulted) { + *lpbDaclDefaulted = FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (pDacl) { + *pDacl = pSecurityDescriptor->Dacl; + } + if (lpbDaclDefaulted) { + *lpbDaclDefaulted = (pSecurityDescriptor->Control & SE_DACL_DEFAULTED) ? TRUE : FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +PSID_IDENTIFIER_AUTHORITY WIN_FUNC GetSidIdentifierAuthority(PSID pSid) { + DEBUG_LOG("GetSidIdentifierAuthority(%p)\n", pSid); + if (!pSid) { + wibo::lastError = ERROR_INVALID_SID; + return nullptr; + } + auto *sid = reinterpret_cast(pSid); + if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { + wibo::lastError = ERROR_INVALID_SID; + return nullptr; + } + wibo::lastError = ERROR_SUCCESS; + return reinterpret_cast(&sid->IdentifierAuthority); +} + +PUCHAR WIN_FUNC GetSidSubAuthorityCount(PSID pSid) { + DEBUG_LOG("GetSidSubAuthorityCount(%p)\n", pSid); + if (!pSid) { + wibo::lastError = ERROR_INVALID_SID; + return nullptr; + } + auto *sid = reinterpret_cast(pSid); + if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { + wibo::lastError = ERROR_INVALID_SID; + return nullptr; + } + wibo::lastError = ERROR_SUCCESS; + return &sid->SubAuthorityCount; +} + +PDWORD WIN_FUNC GetSidSubAuthority(PSID pSid, DWORD nSubAuthority) { + DEBUG_LOG("GetSidSubAuthority(%p, %u)\n", pSid, nSubAuthority); + if (!pSid) { + wibo::lastError = ERROR_INVALID_SID; + return nullptr; + } + auto *sid = reinterpret_cast(pSid); + if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES || nSubAuthority >= sid->SubAuthorityCount) { + wibo::lastError = ERROR_INVALID_SID; + return nullptr; + } + wibo::lastError = ERROR_SUCCESS; + return &sid->SubAuthority[nSubAuthority]; +} + +BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken) { + DEBUG_LOG("STUB: ImpersonateLoggedOnUser(%p)\n", hToken); + (void)hToken; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes, + DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) { + DEBUG_LOG("DuplicateTokenEx(%p, 0x%x, %p, %u, %u, %p)\n", hExistingToken, dwDesiredAccess, lpTokenAttributes, + ImpersonationLevel, TokenType, phNewToken); + (void)lpTokenAttributes; + (void)ImpersonationLevel; + (void)TokenType; + if (!phNewToken) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + handles::Data existingData = handles::dataFromHandle(hExistingToken, false); + if (existingData.type != handles::TYPE_TOKEN || existingData.ptr == nullptr) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + auto *existingToken = static_cast(existingData.ptr); + auto *newToken = new TokenObject(*existingToken); + if (dwDesiredAccess != 0) { + newToken->desiredAccess = dwDesiredAccess; + } + handles::Data newData; + newData.type = handles::TYPE_TOKEN; + newData.ptr = newToken; + newData.size = sizeof(TokenObject); + *phNewToken = handles::allocDataHandle(newData); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid) { + DEBUG_LOG("CopySid(%u, %p, %p)\n", nDestinationSidLength, pDestinationSid, pSourceSid); + if (!pDestinationSid || !pSourceSid) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto *source = reinterpret_cast(pSourceSid); + size_t required = sidLength(source); + if (required == 0 || required > nDestinationSidLength) { + wibo::lastError = ERROR_ALLOTTED_SPACE_EXCEEDED; + return FALSE; + } + std::memcpy(pDestinationSid, pSourceSid, required); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor) { + DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor); + (void)SecurityInformation; + if (!SecurityDescriptor) { + wibo::lastError = ERROR_INVALID_SECURITY_DESCR; + return FALSE; + } + auto data = handles::dataFromHandle(Handle, false); + if (data.type == handles::TYPE_UNUSED) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision) { + DEBUG_LOG("InitializeSecurityDescriptor(%p, %u)\n", pSecurityDescriptor, dwRevision); + if (!pSecurityDescriptor || dwRevision != SECURITY_DESCRIPTOR_REVISION) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + pSecurityDescriptor->Revision = static_cast(dwRevision); + pSecurityDescriptor->Sbz1 = 0; + pSecurityDescriptor->Control = 0; + pSecurityDescriptor->Owner = nullptr; + pSecurityDescriptor->Group = nullptr; + pSecurityDescriptor->Sacl = nullptr; + pSecurityDescriptor->Dacl = nullptr; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl, + BOOL bDaclDefaulted) { + DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted); + if (!pSecurityDescriptor || pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + WORD control = static_cast(pSecurityDescriptor->Control & ~(SE_DACL_PRESENT | SE_DACL_DEFAULTED)); + if (bDaclPresent) { + control = static_cast(control | SE_DACL_PRESENT); + if (bDaclDefaulted) { + control = static_cast(control | SE_DACL_DEFAULTED); + } + pSecurityDescriptor->Dacl = pDacl; + } else { + pSecurityDescriptor->Dacl = nullptr; + } + pSecurityDescriptor->Control = control; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, + LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) { + DEBUG_LOG("GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation, + TokenInformationLength, ReturnLength); + if (!ReturnLength) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto data = handles::dataFromHandle(TokenHandle, false); + if (data.type != handles::TYPE_TOKEN) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + *ReturnLength = 0; + if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenUser) { + constexpr size_t sidSize = sizeof(Sid); + constexpr size_t tokenUserSize = sizeof(TokenUserData); + DWORD required = static_cast(tokenUserSize + sidSize); + *ReturnLength = required; + if (!TokenInformation || TokenInformationLength < required) { + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + auto *tokenUser = reinterpret_cast(TokenInformation); + auto *sid = reinterpret_cast(reinterpret_cast(TokenInformation) + tokenUserSize); + if (!writeLocalSystemSid(sid)) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + tokenUser->User.SidPtr = sid; + tokenUser->User.Attributes = 0; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenStatistics) { + DWORD required = sizeof(TokenStatisticsData); + *ReturnLength = required; + if (!TokenInformation || TokenInformationLength < required) { + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + auto *stats = reinterpret_cast(TokenInformation); + *stats = TokenStatisticsData{}; + stats->tokenType = 1; // TokenPrimary + stats->impersonationLevel = 0; // SecurityAnonymous + stats->tokenId.LowPart = 1; + stats->authenticationId.LowPart = 1; + stats->modifiedId.LowPart = 1; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenElevation) { + DWORD required = sizeof(DWORD); + *ReturnLength = required; + if (!TokenInformation || TokenInformationLength < required) { + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + *reinterpret_cast(TokenInformation) = 0; // not elevated + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenPrimaryGroup) { + DWORD required = static_cast(sizeof(TokenPrimaryGroupStub) + sizeof(Sid)); + *ReturnLength = required; + if (!TokenInformation || TokenInformationLength < required) { + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + auto *groupInfo = reinterpret_cast(TokenInformation); + auto *sid = reinterpret_cast(reinterpret_cast(TokenInformation) + sizeof(TokenPrimaryGroupStub)); + if (!writeLocalSystemSid(sid)) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + groupInfo->PrimaryGroup = sid; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; +} + +BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, + DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) { + DEBUG_LOG("AdjustTokenPrivileges(%p, %u, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, NewState, + BufferLength, PreviousState, ReturnLength); + (void)TokenHandle; + (void)DisableAllPrivileges; + (void)NewState; + (void)BufferLength; + (void)PreviousState; + (void)ReturnLength; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, + LPVOID TokenInformation, DWORD TokenInformationLength) { + DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation, + TokenInformationLength); + (void)TokenInformationClass; + (void)TokenInformation; + (void)TokenInformationLength; + auto data = handles::dataFromHandle(TokenHandle, false); + if (data.type != handles::TYPE_TOKEN) { + wibo::lastError = ERROR_INVALID_HANDLE; + return FALSE; + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +} // namespace advapi32 diff --git a/dll/advapi32/securitybaseapi.h b/dll/advapi32/securitybaseapi.h new file mode 100644 index 0000000..23ed624 --- /dev/null +++ b/dll/advapi32/securitybaseapi.h @@ -0,0 +1,109 @@ +#pragma once + +#include "common.h" + +struct ACL { + BYTE AclRevision; + BYTE Sbz1; + WORD AclSize; + WORD AceCount; + WORD Sbz2; +}; + +struct ACE_HEADER { + BYTE AceType; + BYTE AceFlags; + WORD AceSize; +}; + +struct ACCESS_ALLOWED_ACE { + ACE_HEADER Header; + DWORD Mask; + DWORD SidStart; +}; + +struct SID_IDENTIFIER_AUTHORITY { + BYTE Value[6]; +}; + +struct SECURITY_DESCRIPTOR { + BYTE Revision; + BYTE Sbz1; + WORD Control; + void *Owner; + void *Group; + ACL *Sacl; + ACL *Dacl; +}; + +using PSECURITY_DESCRIPTOR = SECURITY_DESCRIPTOR *; +using PACL = ACL *; +using PSID_IDENTIFIER_AUTHORITY = SID_IDENTIFIER_AUTHORITY *; +using SECURITY_INFORMATION = DWORD; + +constexpr DWORD SECURITY_DESCRIPTOR_REVISION = 1; +constexpr WORD SE_DACL_PRESENT = 0x0004; +constexpr WORD SE_DACL_DEFAULTED = 0x0008; + +constexpr BYTE ACL_REVISION1 = 1; +constexpr BYTE ACL_REVISION2 = 2; +constexpr BYTE ACL_REVISION3 = 3; +constexpr BYTE ACL_REVISION4 = 4; +constexpr BYTE ACL_REVISION = ACL_REVISION2; +constexpr BYTE ACL_REVISION_DS = ACL_REVISION4; +constexpr BYTE ACCESS_ALLOWED_ACE_TYPE = 0x00; +constexpr BYTE SID_MAX_SUB_AUTHORITIES = 15; + +struct TOKEN_PRIVILEGES; +using PTOKEN_PRIVILEGES = TOKEN_PRIVILEGES *; + +enum TOKEN_INFORMATION_CLASS : DWORD { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation = 20, +}; + +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, + DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken); +BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid); +BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl, + LPBOOL lpbDaclDefaulted); +BOOL WIN_FUNC 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 bDaclDefaulted); +BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, + LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength); +BOOL WIN_FUNC 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, + LPVOID TokenInformation, DWORD TokenInformationLength); + +} // namespace advapi32 diff --git a/dll/advapi32/winbase.cpp b/dll/advapi32/winbase.cpp new file mode 100644 index 0000000..b937554 --- /dev/null +++ b/dll/advapi32/winbase.cpp @@ -0,0 +1,117 @@ +#include "winbase.h" + +#include "errors.h" +#include "internal.h" +#include "strutil.h" + +#include +#include + +namespace { + +constexpr WCHAR kAccountSystem[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'}; +constexpr WCHAR kDomainNtAuthority[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'}; + +} // namespace + +namespace advapi32 { + +BOOL WIN_FUNC LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, + LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse) { + std::string systemName = lpSystemName ? wideStringToString(lpSystemName) : std::string("(null)"); + DEBUG_LOG("LookupAccountSidW(%s, %p, %p, %p, %p, %p, %p)\n", systemName.c_str(), Sid, Name, cchName, + ReferencedDomainName, cchReferencedDomainName, peUse); + if (!Sid || !cchName || !cchReferencedDomainName || !peUse) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto *sidStruct = reinterpret_cast(Sid); + if (!isLocalSystemSid(sidStruct)) { + wibo::lastError = ERROR_NONE_MAPPED; + return FALSE; + } + DWORD requiredAccount = static_cast(wstrlen(kAccountSystem)); + DWORD requiredDomain = static_cast(wstrlen(kDomainNtAuthority)); + if (!Name || *cchName <= requiredAccount || !ReferencedDomainName || *cchReferencedDomainName <= requiredDomain) { + *cchName = requiredAccount + 1; + *cchReferencedDomainName = requiredDomain + 1; + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + std::copy_n(kAccountSystem, requiredAccount + 1, Name); + std::copy_n(kDomainNtAuthority, requiredDomain + 1, ReferencedDomainName); + *peUse = SidTypeWellKnownGroup; + *cchName = requiredAccount; + *cchReferencedDomainName = requiredDomain; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid) { + DEBUG_LOG("LookupPrivilegeValueA(%s, %s, %p)\n", lpSystemName ? lpSystemName : "(null)", lpName ? lpName : "(null)", + lpLuid); + (void)lpSystemName; // only local lookup supported + if (!lpName || !lpLuid) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + std::string normalized = normalizePrivilegeName(lpName); + LUID luid = lookupOrGeneratePrivilegeLuid(normalized); + *lpLuid = luid; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid) { + DEBUG_LOG("LookupPrivilegeValueW(%p, %p, %p)\n", lpSystemName, lpName, lpLuid); + (void)lpSystemName; // only local lookup supported + if (!lpName || !lpLuid) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + std::string ansiName = wideStringToString(lpName); + std::string normalized = normalizePrivilegeName(ansiName); + LUID luid = lookupOrGeneratePrivilegeLuid(normalized); + *lpLuid = luid; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer) { + DEBUG_LOG("GetUserNameA(%p, %p)\n", lpBuffer, pcbBuffer); + if (!pcbBuffer) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + const char *name = "SYSTEM"; + size_t needed = std::strlen(name) + 1; + if (!lpBuffer || *pcbBuffer < needed) { + *pcbBuffer = static_cast(needed); + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + std::memcpy(lpBuffer, name, needed); + *pcbBuffer = static_cast(needed); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer) { + DEBUG_LOG("GetUserNameW(%p, %p)\n", lpBuffer, pcbBuffer); + if (!pcbBuffer) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + size_t needed = wstrlen(kAccountSystem) + 1; + if (!lpBuffer || *pcbBuffer < needed) { + *pcbBuffer = static_cast(needed); + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + std::memcpy(lpBuffer, kAccountSystem, needed * sizeof(WCHAR)); + *pcbBuffer = static_cast(needed); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +} // namespace advapi32 diff --git a/dll/advapi32/winbase.h b/dll/advapi32/winbase.h new file mode 100644 index 0000000..c38a27a --- /dev/null +++ b/dll/advapi32/winbase.h @@ -0,0 +1,27 @@ +#pragma once + +#include "common.h" + +enum SID_NAME_USE : DWORD { + SidTypeUser = 1, + SidTypeGroup, + SidTypeDomain, + SidTypeAlias, + SidTypeWellKnownGroup, + SidTypeDeletedAccount, + SidTypeInvalid, + SidTypeUnknown, + SidTypeComputer, + SidTypeLabel +}; + +namespace advapi32 { + +BOOL WIN_FUNC 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); + +} // namespace advapi32 diff --git a/dll/advapi32/winreg.cpp b/dll/advapi32/winreg.cpp index e3fa879..1c3e757 100644 --- a/dll/advapi32/winreg.cpp +++ b/dll/advapi32/winreg.cpp @@ -33,11 +33,11 @@ constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = { constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos); -std::mutex registryMutex; -bool predefinedHandlesInitialized = false; -RegistryKeyHandleData predefinedHandles[kPredefinedKeyCount]; -bool registryInitialized = false; -std::unordered_set existingKeys; +std::mutex g_registryMutex; +bool g_predefinedHandlesInitialized = false; +RegistryKeyHandleData g_predefinedHandles[kPredefinedKeyCount]; +bool g_registryInitialized = false; +std::unordered_set g_existingKeys; std::u16string canonicalizeKeySegment(const std::u16string &input) { std::u16string result; @@ -75,20 +75,20 @@ std::u16string canonicalizeKeySegment(LPCWSTR input) { } void initializePredefinedHandlesLocked() { - if (predefinedHandlesInitialized) { + if (g_predefinedHandlesInitialized) { return; } for (size_t i = 0; i < kPredefinedKeyCount; ++i) { - predefinedHandles[i].canonicalPath = canonicalizeKeySegment(std::u16string(kPredefinedKeyInfos[i].name)); - predefinedHandles[i].predefined = true; + g_predefinedHandles[i].canonicalPath = canonicalizeKeySegment(std::u16string(kPredefinedKeyInfos[i].name)); + g_predefinedHandles[i].predefined = true; } - predefinedHandlesInitialized = true; + g_predefinedHandlesInitialized = true; } RegistryKeyHandleData *predefinedHandleForValue(uintptr_t value) { for (size_t i = 0; i < kPredefinedKeyCount; ++i) { if (kPredefinedKeyInfos[i].value == value) { - return &predefinedHandles[i]; + return &g_predefinedHandles[i]; } } return nullptr; @@ -121,20 +121,110 @@ bool isPredefinedKeyHandle(HKEY hKey) { } void ensureRegistryInitializedLocked() { - if (registryInitialized) { + if (g_registryInitialized) { return; } initializePredefinedHandlesLocked(); - for (size_t i = 0; i < kPredefinedKeyCount; ++i) { - existingKeys.insert(predefinedHandles[i].canonicalPath); + for (auto &g_predefinedHandle : g_predefinedHandles) { + g_existingKeys.insert(g_predefinedHandle.canonicalPath); } - registryInitialized = true; + g_registryInitialized = true; } } // namespace namespace advapi32 { +LSTATUS WIN_FUNC RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, + REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, + LPDWORD lpdwDisposition) { + std::string subKeyString = lpSubKey ? wideStringToString(lpSubKey) : std::string("(null)"); + std::string classString = lpClass ? wideStringToString(lpClass) : std::string("(null)"); + DEBUG_LOG("RegCreateKeyExW(%p, %s, %u, %s, 0x%x, 0x%x, %p, %p, %p)\n", hKey, subKeyString.c_str(), Reserved, + classString.c_str(), dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition); + (void)lpClass; + (void)lpSecurityAttributes; + if (!phkResult) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + *phkResult = nullptr; + if (Reserved != 0) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + if (dwOptions != 0) { + DEBUG_LOG("RegCreateKeyExW: unsupported options 0x%x\n", dwOptions); + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + REGSAM sanitizedAccess = samDesired & ~(KEY_WOW64_64KEY | KEY_WOW64_32KEY); + if (sanitizedAccess != samDesired) { + DEBUG_LOG("RegCreateKeyExW: ignoring WOW64 access mask 0x%x\n", samDesired ^ sanitizedAccess); + } + std::lock_guard lock(g_registryMutex); + ensureRegistryInitializedLocked(); + RegistryKeyHandleData *baseHandle = handleDataFromHKeyLocked(hKey); + if (!baseHandle) { + wibo::lastError = ERROR_INVALID_HANDLE; + return ERROR_INVALID_HANDLE; + } + std::u16string targetPath = baseHandle->canonicalPath; + bool targetingBase = true; + if (lpSubKey && lpSubKey[0] != 0) { + std::u16string subComponent = canonicalizeKeySegment(lpSubKey); + if (!subComponent.empty()) { + targetingBase = false; + if (!targetPath.empty()) { + targetPath.push_back(u'\\'); + } + targetPath.append(subComponent); + } + } + if (targetPath.empty()) { + wibo::lastError = ERROR_INVALID_HANDLE; + return ERROR_INVALID_HANDLE; + } + bool existed = g_existingKeys.find(targetPath) != g_existingKeys.end(); + if (!existed) { + g_existingKeys.insert(targetPath); + } + if (lpdwDisposition) { + *lpdwDisposition = existed ? REG_OPENED_EXISTING_KEY : REG_CREATED_NEW_KEY; + } + if (targetingBase) { + *phkResult = hKey; + wibo::lastError = ERROR_SUCCESS; + return ERROR_SUCCESS; + } + auto *handleData = new RegistryKeyHandleData; + handleData->canonicalPath = targetPath; + handleData->predefined = false; + auto handle = handles::allocDataHandle({handles::TYPE_REGISTRY_KEY, handleData, sizeof(*handleData)}); + *phkResult = reinterpret_cast(handle); + wibo::lastError = ERROR_SUCCESS; + return ERROR_SUCCESS; +} + +LSTATUS WIN_FUNC RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, + REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, + LPDWORD lpdwDisposition) { + DEBUG_LOG("RegCreateKeyExA(%p, %s, %u, %s, 0x%x, 0x%x, %p, %p, %p)\n", hKey, lpSubKey ? lpSubKey : "(null)", + Reserved, lpClass ? lpClass : "(null)", dwOptions, samDesired, lpSecurityAttributes, phkResult, + lpdwDisposition); + std::vector subKeyWideStorage; + if (lpSubKey) { + subKeyWideStorage = stringToWideString(lpSubKey); + } + std::vector classWideStorage; + if (lpClass) { + classWideStorage = stringToWideString(lpClass); + } + return RegCreateKeyExW(hKey, lpSubKey ? reinterpret_cast(subKeyWideStorage.data()) : nullptr, Reserved, + lpClass ? reinterpret_cast(classWideStorage.data()) : nullptr, dwOptions, samDesired, + lpSecurityAttributes, phkResult, lpdwDisposition); +} + LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { 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); @@ -155,7 +245,7 @@ LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REG DEBUG_LOG("RegOpenKeyExW: ignoring WOW64 access mask 0x%x\n", samDesired ^ sanitizedAccess); } (void)sanitizedAccess; - std::lock_guard lock(registryMutex); + std::lock_guard lock(g_registryMutex); ensureRegistryInitializedLocked(); RegistryKeyHandleData *baseHandle = handleDataFromHKeyLocked(hKey); if (!baseHandle) { @@ -176,7 +266,7 @@ LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REG wibo::lastError = ERROR_INVALID_HANDLE; return ERROR_INVALID_HANDLE; } - if (existingKeys.find(targetPath) == existingKeys.end()) { + if (g_existingKeys.find(targetPath) == g_existingKeys.end()) { wibo::lastError = ERROR_FILE_NOT_FOUND; return ERROR_FILE_NOT_FOUND; } @@ -208,6 +298,93 @@ 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, + LPDWORD lpcbData) { + std::string valueName = lpValueName ? wideStringToString(lpValueName) : std::string("(default)"); + DEBUG_LOG("RegQueryValueExW(%p, %s, %p, %p, %p, %p)\n", hKey, valueName.c_str(), lpReserved, lpType, lpData, + lpcbData); + if (lpReserved) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + if (lpcbData) { + *lpcbData = 0; + } + if (lpType) { + *lpType = 0; + } + (void)hKey; + (void)lpData; + wibo::lastError = ERROR_FILE_NOT_FOUND; + return ERROR_FILE_NOT_FOUND; +} + +LSTATUS WIN_FUNC RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData, + LPDWORD lpcbData) { + DEBUG_LOG("RegQueryValueExA(%p, %s, %p, %p, %p, %p)\n", hKey, lpValueName ? lpValueName : "(null)", lpReserved, + lpType, lpData, lpcbData); + std::vector valueWideStorage; + if (lpValueName) { + valueWideStorage = stringToWideString(lpValueName); + } + return RegQueryValueExW(hKey, lpValueName ? reinterpret_cast(valueWideStorage.data()) : nullptr, + lpReserved, lpType, lpData, lpcbData); +} + +LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved, + LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime) { + DEBUG_LOG("RegEnumKeyExW(%p, %u, %p, %p, %p, %p, %p, %p)\n", hKey, dwIndex, lpName, lpcchName, lpReserved, lpClass, + lpcchClass, lpftLastWriteTime); + (void)hKey; + (void)dwIndex; + if (lpReserved) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + if (lpcchName) { + *lpcchName = 0; + } + if (lpName && lpcchName && *lpcchName > 0) { + lpName[0] = 0; + } + if (lpClass && lpcchClass && *lpcchClass > 0) { + lpClass[0] = 0; + } + if (lpcchClass) { + *lpcchClass = 0; + } + (void)lpftLastWriteTime; + wibo::lastError = ERROR_NO_MORE_ITEMS; + return ERROR_NO_MORE_ITEMS; +} + +LSTATUS WIN_FUNC RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved, + LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime) { + DEBUG_LOG("RegEnumKeyExA(%p, %u, %p, %p, %p, %p, %p, %p)\n", hKey, dwIndex, lpName, lpcchName, lpReserved, lpClass, + lpcchClass, lpftLastWriteTime); + (void)hKey; + (void)dwIndex; + if (lpReserved) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + if (lpcchName) { + *lpcchName = 0; + } + if (lpName && lpcchName && *lpcchName > 0) { + lpName[0] = '\0'; + } + if (lpClass && lpcchClass && *lpcchClass > 0) { + lpClass[0] = '\0'; + } + if (lpcchClass) { + *lpcchClass = 0; + } + (void)lpftLastWriteTime; + wibo::lastError = ERROR_NO_MORE_ITEMS; + return ERROR_NO_MORE_ITEMS; +} + LSTATUS WIN_FUNC RegCloseKey(HKEY hKey) { DEBUG_LOG("RegCloseKey(%p)\n", hKey); if (isPredefinedKeyHandle(hKey)) { diff --git a/dll/advapi32/winreg.h b/dll/advapi32/winreg.h index 004e6eb..e5c855d 100644 --- a/dll/advapi32/winreg.h +++ b/dll/advapi32/winreg.h @@ -2,6 +2,8 @@ #include "common.h" +struct FILETIME; + #ifndef HKEY_CLASSES_ROOT #define HKEY_CLASSES_ROOT ((HKEY)(uintptr_t)0x80000000u) #endif @@ -23,13 +25,30 @@ constexpr DWORD REG_OPTION_OPEN_LINK = 0x00000008; +constexpr DWORD REG_CREATED_NEW_KEY = 0x00000001; +constexpr DWORD REG_OPENED_EXISTING_KEY = 0x00000002; + constexpr REGSAM KEY_WOW64_64KEY = 0x00000100; constexpr REGSAM KEY_WOW64_32KEY = 0x00000200; namespace advapi32 { +LSTATUS WIN_FUNC 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, + 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, + LPDWORD lpcbData); +LSTATUS WIN_FUNC 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, + LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime); +LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved, + LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime); LSTATUS WIN_FUNC RegCloseKey(HKEY hKey); } // namespace advapi32 diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index cb19e50..134652f 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -23,7 +23,9 @@ #include "kernel32/winnt.h" #include "kernel32/wow64apiset.h" -static void *resolveByName(const char *name) { +namespace { + +void *resolveByName(const char *name) { // errhandlingapi.h if (strcmp(name, "GetLastError") == 0) return (void *)kernel32::GetLastError; @@ -97,6 +99,8 @@ static void *resolveByName(const char *name) { return (void *)kernel32::SetThreadPriority; if (strcmp(name, "GetThreadPriority") == 0) return (void *)kernel32::GetThreadPriority; + if (strcmp(name, "GetPriorityClass") == 0) + return (void *)kernel32::GetPriorityClass; if (strcmp(name, "GetProcessAffinityMask") == 0) return (void *)kernel32::GetProcessAffinityMask; if (strcmp(name, "SetProcessAffinityMask") == 0) @@ -293,6 +297,10 @@ static void *resolveByName(const char *name) { return (void *)kernel32::WriteConsoleW; if (strcmp(name, "GetConsoleOutputCP") == 0) return (void *)kernel32::GetConsoleOutputCP; + if (strcmp(name, "GetConsoleTitleA") == 0) + return (void *)kernel32::GetConsoleTitleA; + if (strcmp(name, "GetConsoleTitleW") == 0) + return (void *)kernel32::GetConsoleTitleW; if (strcmp(name, "PeekConsoleInputA") == 0) return (void *)kernel32::PeekConsoleInputA; if (strcmp(name, "ReadConsoleInputA") == 0) @@ -323,6 +331,18 @@ static void *resolveByName(const char *name) { return (void *)kernel32::GetFileAttributesA; if (strcmp(name, "GetFileAttributesW") == 0) return (void *)kernel32::GetFileAttributesW; + if (strcmp(name, "GetDriveTypeA") == 0) + return (void *)kernel32::GetDriveTypeA; + if (strcmp(name, "GetDriveTypeW") == 0) + return (void *)kernel32::GetDriveTypeW; + if (strcmp(name, "GetVolumeInformationA") == 0) + return (void *)kernel32::GetVolumeInformationA; + if (strcmp(name, "GetVolumeInformationW") == 0) + return (void *)kernel32::GetVolumeInformationW; + if (strcmp(name, "CompareFileTime") == 0) + return (void *)kernel32::CompareFileTime; + if (strcmp(name, "GetFileAttributesW") == 0) + return (void *)kernel32::GetFileAttributesW; if (strcmp(name, "WriteFile") == 0) return (void *)kernel32::WriteFile; if (strcmp(name, "FlushFileBuffers") == 0) @@ -339,6 +359,8 @@ static void *resolveByName(const char *name) { return (void *)kernel32::CreateFileMappingW; if (strcmp(name, "MapViewOfFile") == 0) return (void *)kernel32::MapViewOfFile; + if (strcmp(name, "MapViewOfFileEx") == 0) + return (void *)kernel32::MapViewOfFileEx; if (strcmp(name, "UnmapViewOfFile") == 0) return (void *)kernel32::UnmapViewOfFile; if (strcmp(name, "DeleteFileA") == 0) @@ -541,6 +563,8 @@ static void *resolveByName(const char *name) { return 0; } +} // namespace + wibo::Module lib_kernel32 = { (const char *[]){ "kernel32", diff --git a/dll/kernel32/fileapi.cpp b/dll/kernel32/fileapi.cpp index aa2f5d4..90e69c7 100644 --- a/dll/kernel32/fileapi.cpp +++ b/dll/kernel32/fileapi.cpp @@ -288,6 +288,100 @@ DWORD WIN_FUNC GetFileAttributesW(LPCWSTR lpFileName) { return GetFileAttributesA(str.c_str()); } +UINT WIN_FUNC GetDriveTypeA(LPCSTR lpRootPathName) { + DEBUG_LOG("STUB: GetDriveTypeA(%s)\n", lpRootPathName ? lpRootPathName : "(null)"); + (void)lpRootPathName; + wibo::lastError = ERROR_SUCCESS; + return DRIVE_FIXED; +} + +UINT WIN_FUNC GetDriveTypeW(LPCWSTR lpRootPathName) { + DEBUG_LOG("STUB: GetDriveTypeW(%p)\n", lpRootPathName); + (void)lpRootPathName; + wibo::lastError = ERROR_SUCCESS; + return DRIVE_FIXED; +} + +BOOL WIN_FUNC GetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, + LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, + LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, + DWORD nFileSystemNameSize) { + DEBUG_LOG("STUB: GetVolumeInformationA(%s)\n", lpRootPathName ? lpRootPathName : "(null)"); + if (lpVolumeNameBuffer && nVolumeNameSize > 0) { + lpVolumeNameBuffer[0] = '\0'; + } + if (lpVolumeSerialNumber) { + *lpVolumeSerialNumber = 0x12345678; + } + if (lpMaximumComponentLength) { + *lpMaximumComponentLength = 255; + } + if (lpFileSystemFlags) { + *lpFileSystemFlags = 0; + } + if (lpFileSystemNameBuffer) { + if (nFileSystemNameSize > 0) { + const char *fsName = "NTFS"; + size_t copyLen = std::min(std::strlen(fsName), nFileSystemNameSize - 1); + std::memcpy(lpFileSystemNameBuffer, fsName, copyLen); + lpFileSystemNameBuffer[copyLen] = '\0'; + } + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC GetVolumeInformationW(LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, + LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, + LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, + DWORD nFileSystemNameSize) { + DEBUG_LOG("STUB: GetVolumeInformationW(%p)\n", lpRootPathName); + if (lpVolumeNameBuffer && nVolumeNameSize > 0) { + lpVolumeNameBuffer[0] = 0; + } + if (lpVolumeSerialNumber) { + *lpVolumeSerialNumber = 0x12345678; + } + if (lpMaximumComponentLength) { + *lpMaximumComponentLength = 255; + } + if (lpFileSystemFlags) { + *lpFileSystemFlags = 0; + } + if (lpFileSystemNameBuffer) { + if (nFileSystemNameSize > 0) { + std::vector fsWide = stringToWideString("NTFS"); + size_t copyLen = std::min(fsWide.size() > 0 ? fsWide.size() - 1 : 0, nFileSystemNameSize - 1); + for (size_t i = 0; i < copyLen; ++i) { + lpFileSystemNameBuffer[i] = static_cast(fsWide[i]); + } + lpFileSystemNameBuffer[copyLen] = 0; + } + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +LONG WIN_FUNC CompareFileTime(const FILETIME *lpFileTime1, const FILETIME *lpFileTime2) { + DEBUG_LOG("CompareFileTime(%p, %p)\n", lpFileTime1, lpFileTime2); + auto toInt64 = [](const FILETIME *ft) -> int64_t { + if (!ft) { + return 0; + } + uint64_t combined = (static_cast(ft->dwHighDateTime) << 32) | ft->dwLowDateTime; + return static_cast(combined); + }; + int64_t value1 = toInt64(lpFileTime1); + int64_t value2 = toInt64(lpFileTime2); + if (value1 < value2) { + return -1; + } + if (value1 > value2) { + return 1; + } + return 0; +} + BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { DEBUG_LOG("WriteFile(%p, %u)\n", hFile, nNumberOfBytesToWrite); diff --git a/dll/kernel32/fileapi.h b/dll/kernel32/fileapi.h index a5c1388..24463dc 100644 --- a/dll/kernel32/fileapi.h +++ b/dll/kernel32/fileapi.h @@ -47,6 +47,14 @@ constexpr DWORD FILE_ATTRIBUTE_OFFLINE = 0x00001000; constexpr DWORD FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000; constexpr DWORD FILE_ATTRIBUTE_ENCRYPTED = 0x00004000; +constexpr UINT DRIVE_UNKNOWN = 0; +constexpr UINT DRIVE_NO_ROOT_DIR = 1; +constexpr UINT DRIVE_REMOVABLE = 2; +constexpr UINT DRIVE_FIXED = 3; +constexpr UINT DRIVE_REMOTE = 4; +constexpr UINT DRIVE_CDROM = 5; +constexpr UINT DRIVE_RAMDISK = 6; + constexpr DWORD FILE_TYPE_UNKNOWN = 0x0000; constexpr DWORD FILE_TYPE_DISK = 0x0001; constexpr DWORD FILE_TYPE_CHAR = 0x0002; @@ -72,6 +80,8 @@ BOOL WIN_FUNC FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) BOOL WIN_FUNC FindClose(HANDLE hFindFile); DWORD WIN_FUNC GetFileAttributesA(LPCSTR lpFileName); DWORD WIN_FUNC GetFileAttributesW(LPCWSTR lpFileName); +UINT WIN_FUNC GetDriveTypeA(LPCSTR lpRootPathName); +UINT WIN_FUNC GetDriveTypeW(LPCWSTR lpRootPathName); BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, @@ -101,5 +111,13 @@ BOOL WIN_FUNC SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, const FI const FILETIME *lpLastWriteTime); BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation); DWORD WIN_FUNC GetFileType(HANDLE hFile); +LONG WIN_FUNC CompareFileTime(const FILETIME *lpFileTime1, const FILETIME *lpFileTime2); +BOOL WIN_FUNC GetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, + LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, + LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize); +BOOL WIN_FUNC GetVolumeInformationW(LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize, + LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength, + LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer, + DWORD nFileSystemNameSize); } // namespace kernel32 diff --git a/dll/kernel32/handleapi.cpp b/dll/kernel32/handleapi.cpp index 34adb41..bd77f76 100644 --- a/dll/kernel32/handleapi.cpp +++ b/dll/kernel32/handleapi.cpp @@ -1,5 +1,6 @@ #include "handleapi.h" +#include "dll/advapi32/internal.h" #include "errors.h" #include "files.h" #include "handles.h" @@ -9,10 +10,6 @@ #include #include -namespace advapi32 { -void releaseToken(void *tokenPtr); -} - namespace kernel32 { BOOL WIN_FUNC DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, @@ -151,12 +148,7 @@ BOOL WIN_FUNC CloseHandle(HANDLE hObject) { success = false; } } else if (data.type == handles::TYPE_PROCESS) { - auto *proc = reinterpret_cast(data.ptr); - if (proc) { - delete proc; - } else { - success = false; - } + delete reinterpret_cast(data.ptr); } else if (data.type == handles::TYPE_TOKEN) { advapi32::releaseToken(data.ptr); } else if (data.type == handles::TYPE_MUTEX) { diff --git a/dll/kernel32/memoryapi.cpp b/dll/kernel32/memoryapi.cpp index 35f3c9b..d51caf3 100644 --- a/dll/kernel32/memoryapi.cpp +++ b/dll/kernel32/memoryapi.cpp @@ -303,17 +303,8 @@ HANDLE WIN_FUNC CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap lpName ? name.c_str() : nullptr); } -LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, - DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) { - DEBUG_LOG("MapViewOfFile(%p, 0x%x, %u, %u, %zu)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, - dwFileOffsetLow, dwNumberOfBytesToMap); - - handles::Data data = handles::dataFromHandle(hFileMappingObject, false); - if (data.type != handles::TYPE_MAPPED) { - wibo::lastError = ERROR_INVALID_HANDLE; - return nullptr; - } - auto *mapping = reinterpret_cast(data.ptr); +static LPVOID mapViewOfFileInternal(MappingObject *mapping, DWORD dwDesiredAccess, uint64_t offset, + SIZE_T dwNumberOfBytesToMap, LPVOID baseAddress) { if (!mapping) { wibo::lastError = ERROR_INVALID_HANDLE; return nullptr; @@ -322,8 +313,6 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, wibo::lastError = ERROR_INVALID_HANDLE; return nullptr; } - - uint64_t offset = (static_cast(dwFileOffsetHigh) << 32) | dwFileOffsetLow; if (mapping->anonymous && offset != 0) { wibo::lastError = ERROR_INVALID_PARAMETER; return nullptr; @@ -331,11 +320,7 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, size_t maxSize = mapping->maxSize; uint64_t length = static_cast(dwNumberOfBytesToMap); if (length == 0) { - if (maxSize == 0) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return nullptr; - } - if (offset > maxSize) { + if (maxSize == 0 || offset > maxSize) { wibo::lastError = ERROR_INVALID_PARAMETER; return nullptr; } @@ -353,28 +338,27 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, int prot = PROT_READ; bool wantWrite = (dwDesiredAccess & FILE_MAP_WRITE) != 0; bool wantExecute = (dwDesiredAccess & FILE_MAP_EXECUTE) != 0; + bool wantCopy = (dwDesiredAccess & FILE_MAP_COPY) != 0; if (mapping->protect == PAGE_READWRITE) { - if (wantWrite) { + if (wantWrite || wantCopy) { prot |= PROT_WRITE; } } else { - if (wantWrite && (dwDesiredAccess & FILE_MAP_COPY) == 0) { + if (wantWrite && !wantCopy) { wibo::lastError = ERROR_ACCESS_DENIED; return nullptr; } + if (wantCopy) { + prot |= PROT_WRITE; + } } if (wantExecute) { prot |= PROT_EXEC; } - int flags = 0; - if (mapping->anonymous) { - flags |= MAP_ANONYMOUS; - } - flags |= (dwDesiredAccess & FILE_MAP_COPY) ? MAP_PRIVATE : MAP_SHARED; - - size_t pageSize = static_cast(sysconf(_SC_PAGESIZE)); + int flags = (mapping->anonymous ? MAP_ANONYMOUS : 0) | (wantCopy ? MAP_PRIVATE : MAP_SHARED); + const size_t pageSize = static_cast(sysconf(_SC_PAGESIZE)); off_t alignedOffset = mapping->anonymous ? 0 : static_cast(offset & ~static_cast(pageSize - 1)); size_t offsetDelta = static_cast(offset - static_cast(alignedOffset)); uint64_t requestedLength = length + offsetDelta; @@ -389,18 +373,84 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, } int mmapFd = mapping->anonymous ? -1 : mapping->fd; - void *mapBase = mmap(nullptr, mapLength, prot, flags, mmapFd, alignedOffset); + void *requestedBase = nullptr; + int mapFlags = flags; + if (baseAddress) { + uintptr_t baseAddr = reinterpret_cast(baseAddress); + if (baseAddr == 0 || (baseAddr % kVirtualAllocationGranularity) != 0) { + wibo::lastError = ERROR_INVALID_ADDRESS; + return nullptr; + } + if (offsetDelta > baseAddr) { + wibo::lastError = ERROR_INVALID_ADDRESS; + return nullptr; + } + uintptr_t mapBaseAddr = baseAddr - offsetDelta; + if ((mapBaseAddr & (pageSize - 1)) != 0) { + wibo::lastError = ERROR_INVALID_ADDRESS; + return nullptr; + } + requestedBase = reinterpret_cast(mapBaseAddr); +#ifdef MAP_FIXED_NOREPLACE + mapFlags |= MAP_FIXED_NOREPLACE; +#else + mapFlags |= MAP_FIXED; +#endif + } + + errno = 0; + void *mapBase = mmap(requestedBase, mapLength, prot, mapFlags, mmapFd, alignedOffset); if (mapBase == MAP_FAILED) { - setLastErrorFromErrno(); + int err = errno; + if (baseAddress && (err == ENOMEM || err == EEXIST || err == EINVAL || err == EPERM)) { + wibo::lastError = ERROR_INVALID_ADDRESS; + } else { + wibo::lastError = wibo::winErrorFromErrno(err); + } return nullptr; } void *viewPtr = static_cast(mapBase) + offsetDelta; + if (baseAddress && viewPtr != baseAddress) { + munmap(mapBase, mapLength); + wibo::lastError = ERROR_INVALID_ADDRESS; + return nullptr; + } g_viewInfo[viewPtr] = ViewInfo{mapBase, mapLength, mapping}; mapping->refCount++; wibo::lastError = ERROR_SUCCESS; return viewPtr; } +LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) { + DEBUG_LOG("MapViewOfFile(%p, 0x%x, %u, %u, %zu)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, + dwFileOffsetLow, dwNumberOfBytesToMap); + + handles::Data data = handles::dataFromHandle(hFileMappingObject, false); + if (data.type != handles::TYPE_MAPPED) { + wibo::lastError = ERROR_INVALID_HANDLE; + return nullptr; + } + auto *mapping = reinterpret_cast(data.ptr); + uint64_t offset = (static_cast(dwFileOffsetHigh) << 32) | dwFileOffsetLow; + return mapViewOfFileInternal(mapping, dwDesiredAccess, offset, dwNumberOfBytesToMap, nullptr); +} + +LPVOID WIN_FUNC MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) { + DEBUG_LOG("MapViewOfFileEx(%p, 0x%x, %u, %u, %zu, %p)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, + dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress); + + handles::Data data = handles::dataFromHandle(hFileMappingObject, false); + if (data.type != handles::TYPE_MAPPED) { + wibo::lastError = ERROR_INVALID_HANDLE; + return nullptr; + } + auto *mapping = reinterpret_cast(data.ptr); + uint64_t offset = (static_cast(dwFileOffsetHigh) << 32) | dwFileOffsetLow; + return mapViewOfFileInternal(mapping, dwDesiredAccess, offset, dwNumberOfBytesToMap, lpBaseAddress); +} + BOOL WIN_FUNC UnmapViewOfFile(LPCVOID lpBaseAddress) { DEBUG_LOG("UnmapViewOfFile(%p)\n", lpBaseAddress); auto it = g_viewInfo.find(const_cast(lpBaseAddress)); diff --git a/dll/kernel32/memoryapi.h b/dll/kernel32/memoryapi.h index 09be4b4..25e33cf 100644 --- a/dll/kernel32/memoryapi.h +++ b/dll/kernel32/memoryapi.h @@ -53,6 +53,8 @@ HANDLE WIN_FUNC CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName); LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap); +LPVOID WIN_FUNC MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, + DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress); BOOL WIN_FUNC UnmapViewOfFile(LPCVOID lpBaseAddress); LPVOID WIN_FUNC VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); diff --git a/dll/kernel32/processthreadsapi.cpp b/dll/kernel32/processthreadsapi.cpp index b0228a7..b25c9ea 100644 --- a/dll/kernel32/processthreadsapi.cpp +++ b/dll/kernel32/processthreadsapi.cpp @@ -625,6 +625,13 @@ int WIN_FUNC GetThreadPriority(HANDLE hThread) { return 0; } +DWORD WIN_FUNC GetPriorityClass(HANDLE hProcess) { + DEBUG_LOG("GetPriorityClass(%p)\n", hProcess); + (void)hProcess; + wibo::lastError = ERROR_SUCCESS; + return NORMAL_PRIORITY_CLASS; +} + BOOL WIN_FUNC GetThreadTimes(HANDLE hThread, FILETIME *lpCreationTime, FILETIME *lpExitTime, FILETIME *lpKernelTime, FILETIME *lpUserTime) { DEBUG_LOG("GetThreadTimes(%p, %p, %p, %p, %p)\n", hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime); diff --git a/dll/kernel32/processthreadsapi.h b/dll/kernel32/processthreadsapi.h index 99d6116..10bd76e 100644 --- a/dll/kernel32/processthreadsapi.h +++ b/dll/kernel32/processthreadsapi.h @@ -61,6 +61,7 @@ struct STARTUPINFOW { using LPSTARTUPINFOW = STARTUPINFOW *; constexpr DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFFu; +constexpr DWORD NORMAL_PRIORITY_CLASS = 0x00000020; typedef DWORD(WIN_FUNC *LPTHREAD_START_ROUTINE)(LPVOID); @@ -91,6 +92,7 @@ void WIN_FUNC ExitThread(DWORD dwExitCode); BOOL WIN_FUNC GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode); BOOL WIN_FUNC SetThreadPriority(HANDLE hThread, int nPriority); int WIN_FUNC GetThreadPriority(HANDLE hThread); +DWORD WIN_FUNC GetPriorityClass(HANDLE hProcess); BOOL WIN_FUNC GetThreadTimes(HANDLE hThread, FILETIME *lpCreationTime, FILETIME *lpExitTime, FILETIME *lpKernelTime, FILETIME *lpUserTime); BOOL WIN_FUNC CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, diff --git a/dll/kernel32/wincon.cpp b/dll/kernel32/wincon.cpp index 5376d78..701b3f8 100644 --- a/dll/kernel32/wincon.cpp +++ b/dll/kernel32/wincon.cpp @@ -83,6 +83,24 @@ BOOL WIN_FUNC WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumb return FALSE; } +DWORD WIN_FUNC GetConsoleTitleA(LPSTR lpConsoleTitle, DWORD nSize) { + DEBUG_LOG("GetConsoleTitleA(%p, %u)\n", lpConsoleTitle, nSize); + if (lpConsoleTitle && nSize > 0) { + lpConsoleTitle[0] = '\0'; + } + wibo::lastError = ERROR_SUCCESS; + return 0; +} + +DWORD WIN_FUNC GetConsoleTitleW(LPWSTR lpConsoleTitle, DWORD nSize) { + DEBUG_LOG("GetConsoleTitleW(%p, %u)\n", lpConsoleTitle, nSize); + if (lpConsoleTitle && nSize > 0) { + lpConsoleTitle[0] = 0; + } + wibo::lastError = ERROR_SUCCESS; + return 0; +} + BOOL WIN_FUNC PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead) { DEBUG_LOG("STUB: PeekConsoleInputA(%p, %p, %u)\n", hConsoleInput, lpBuffer, nLength); diff --git a/dll/kernel32/wincon.h b/dll/kernel32/wincon.h index 0570698..99edf47 100644 --- a/dll/kernel32/wincon.h +++ b/dll/kernel32/wincon.h @@ -35,6 +35,8 @@ BOOL WIN_FUNC SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add); BOOL WIN_FUNC GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO *lpConsoleScreenBufferInfo); BOOL WIN_FUNC WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved); +DWORD WIN_FUNC GetConsoleTitleA(LPSTR lpConsoleTitle, DWORD nSize); +DWORD WIN_FUNC GetConsoleTitleW(LPWSTR lpConsoleTitle, DWORD nSize); BOOL WIN_FUNC PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead); BOOL WIN_FUNC ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength, diff --git a/errors.h b/errors.h index a8241a4..deab53f 100644 --- a/errors.h +++ b/errors.h @@ -9,6 +9,7 @@ #define ERROR_INVALID_HANDLE 6 #define ERROR_NOT_ENOUGH_MEMORY 8 #define ERROR_NO_MORE_FILES 18 +#define ERROR_NO_MORE_ITEMS 259 #define ERROR_FILE_EXISTS 80 #define ERROR_READ_FAULT 30 #define ERROR_HANDLE_EOF 38