diff --git a/CMakeLists.txt b/CMakeLists.txt index 335307a..7bda4e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,8 @@ FetchContent_MakeAvailable(mimalloc) include_directories(.) add_executable(wibo dll/advapi32.cpp + dll/advapi32/winreg.cpp + dll/advapi32/wincrypt.cpp dll/bcrypt.cpp dll/crt.cpp dll/kernel32.cpp diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index aa09d13..4e863f5 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -1,4 +1,6 @@ #include "common.h" +#include "advapi32/winreg.h" +#include "advapi32/wincrypt.h" #include "errors.h" #include "handles.h" #include "strutil.h" @@ -8,147 +10,13 @@ #include #include #include -#include -#include #include -#include namespace { - constexpr DWORD REG_OPTION_OPEN_LINK = 0x00000008; - constexpr DWORD KEY_WOW64_64KEY = 0x00000100; - constexpr DWORD KEY_WOW64_32KEY = 0x00000200; - - struct RegistryKeyHandleData { - std::u16string canonicalPath; - bool predefined = false; - }; - - struct PredefinedKeyInfo { - uintptr_t value; - const char16_t *name; - }; - - static constexpr PredefinedKeyInfo predefinedKeyInfos[] = { - {0x80000000u, u"HKEY_CLASSES_ROOT"}, - {0x80000001u, u"HKEY_CURRENT_USER"}, - {0x80000002u, u"HKEY_LOCAL_MACHINE"}, - {0x80000003u, u"HKEY_USERS"}, - {0x80000004u, u"HKEY_PERFORMANCE_DATA"}, - {0x80000005u, u"HKEY_CURRENT_CONFIG"}, - }; - - static constexpr size_t predefinedKeyCount = sizeof(predefinedKeyInfos) / sizeof(predefinedKeyInfos[0]); - - static std::mutex registryMutex; - static bool predefinedHandlesInitialized = false; - static RegistryKeyHandleData predefinedHandles[predefinedKeyCount]; - static bool registryInitialized = false; - static std::unordered_set existingKeys; struct Luid; static std::mutex privilegeMapMutex; static std::unordered_map privilegeLuidCache; - static std::u16string canonicalizeKeySegment(const std::u16string &input) { - std::u16string result; - result.reserve(input.size()); - bool lastWasSlash = false; - for (char16_t ch : input) { - char16_t normalized = (ch == u'/') ? u'\\' : ch; - if (normalized == u'\\') { - if (!result.empty() && !lastWasSlash) { - result.push_back(u'\\'); - } - lastWasSlash = true; - continue; - } - lastWasSlash = false; - uint16_t lowered = wcharToLower(static_cast(normalized)); - result.push_back(static_cast(lowered)); - } - while (!result.empty() && result.back() == u'\\') { - result.pop_back(); - } - auto it = result.begin(); - while (it != result.end() && *it == u'\\') { - it = result.erase(it); - } - return result; - } - - static std::u16string canonicalizeKeySegment(const uint16_t *input) { - if (!input) { - return {}; - } - std::u16string wide(reinterpret_cast(input), wstrlen(input)); - return canonicalizeKeySegment(wide); - } - - static void initializePredefinedHandlesLocked() { - if (predefinedHandlesInitialized) { - return; - } - for (size_t i = 0; i < predefinedKeyCount; ++i) { - predefinedHandles[i].canonicalPath = canonicalizeKeySegment(std::u16string(predefinedKeyInfos[i].name)); - predefinedHandles[i].predefined = true; - } - predefinedHandlesInitialized = true; - } - - static RegistryKeyHandleData *predefinedHandleForValue(uintptr_t value) { - for (size_t i = 0; i < predefinedKeyCount; ++i) { - if (predefinedKeyInfos[i].value == value) { - return &predefinedHandles[i]; - } - } - return nullptr; - } - - static RegistryKeyHandleData *handleDataFromHKeyLocked(HKEY hKey) { - uintptr_t raw = reinterpret_cast(hKey); - if (raw == 0) { - return nullptr; - } - initializePredefinedHandlesLocked(); - if (auto *predefined = predefinedHandleForValue(raw)) { - return predefined; - } - auto data = handles::dataFromHandle(hKey, false); - if (data.type != handles::TYPE_REGISTRY_KEY || data.ptr == nullptr) { - return nullptr; - } - return static_cast(data.ptr); - } - - static bool isPredefinedKeyHandle(HKEY hKey) { - uintptr_t raw = reinterpret_cast(hKey); - for (size_t i = 0; i < predefinedKeyCount; ++i) { - if (predefinedKeyInfos[i].value == raw) { - return true; - } - } - return false; - } - - static void ensureRegistryInitializedLocked() { - if (registryInitialized) { - return; - } - initializePredefinedHandlesLocked(); - for (size_t i = 0; i < predefinedKeyCount; ++i) { - existingKeys.insert(predefinedHandles[i].canonicalPath); - } - registryInitialized = true; - } - - using ALG_ID = unsigned int; - - constexpr ALG_ID CALG_MD5 = 0x00008003; - constexpr ALG_ID CALG_SHA1 = 0x00008004; - - constexpr DWORD HP_ALGID = 0x00000001; - constexpr DWORD HP_HASHVAL = 0x00000002; - constexpr DWORD HP_HASHSIZE = 0x00000004; - constexpr DWORD SECURITY_DESCRIPTOR_REVISION = 1; constexpr uint16_t SE_DACL_PRESENT = 0x0004; constexpr uint16_t SE_DACL_DEFAULTED = 0x0008; @@ -163,13 +31,6 @@ namespace { void *Dacl = nullptr; }; - struct HashObject { - ALG_ID algid = 0; - std::vector data; - std::vector digest; - bool digestComputed = false; - }; - struct TokenObject { HANDLE processHandle = nullptr; DWORD desiredAccess = 0; @@ -247,453 +108,9 @@ namespace { Luid modifiedId; }; - static inline uint32_t leftRotate(uint32_t value, uint32_t bits) { - return (value << bits) | (value >> (32 - bits)); - } - - static std::vector computeMD5(const std::vector &input) { - static const uint32_t s[64] = { - 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, - 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, - 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, - 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 - }; - static const uint32_t K[64] = { - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - - std::vector data = input; - uint64_t bitLen = static_cast(data.size()) * 8ULL; - data.push_back(0x80); - while ((data.size() % 64) != 56) { - data.push_back(0); - } - for (int i = 0; i < 8; ++i) { - data.push_back(static_cast((bitLen >> (8 * i)) & 0xFF)); - } - - uint32_t A = 0x67452301; - uint32_t B = 0xEFCDAB89; - uint32_t C = 0x98BADCFE; - uint32_t D = 0x10325476; - - for (size_t offset = 0; offset < data.size(); offset += 64) { - uint32_t M[16]; - for (int i = 0; i < 16; ++i) { - M[i] = static_cast(data[offset + i * 4]) | - (static_cast(data[offset + i * 4 + 1]) << 8) | - (static_cast(data[offset + i * 4 + 2]) << 16) | - (static_cast(data[offset + i * 4 + 3]) << 24); - } - uint32_t a = A; - uint32_t b = B; - uint32_t c = C; - uint32_t d = D; - for (int i = 0; i < 64; ++i) { - uint32_t F; - int g; - if (i < 16) { - F = (b & c) | ((~b) & d); - g = i; - } else if (i < 32) { - F = (d & b) | ((~d) & c); - g = (5 * i + 1) % 16; - } else if (i < 48) { - F = b ^ c ^ d; - g = (3 * i + 5) % 16; - } else { - F = c ^ (b | (~d)); - g = (7 * i) % 16; - } - uint32_t temp = d; - d = c; - c = b; - uint32_t rotateVal = a + F + K[i] + M[g]; - b = b + leftRotate(rotateVal, s[i]); - a = temp; - } - A += a; - B += b; - C += c; - D += d; - } - - std::vector digest(16); - uint32_t output[4] = {A, B, C, D}; - for (int i = 0; i < 4; ++i) { - digest[i * 4] = static_cast(output[i] & 0xFF); - digest[i * 4 + 1] = static_cast((output[i] >> 8) & 0xFF); - digest[i * 4 + 2] = static_cast((output[i] >> 16) & 0xFF); - digest[i * 4 + 3] = static_cast((output[i] >> 24) & 0xFF); - } - return digest; - } - - static std::vector computeSHA1(const std::vector &input) { - std::vector data = input; - uint64_t bitLen = static_cast(data.size()) * 8ULL; - data.push_back(0x80); - while ((data.size() % 64) != 56) { - data.push_back(0); - } - for (int i = 7; i >= 0; --i) { - data.push_back(static_cast((bitLen >> (8 * i)) & 0xFF)); - } - - uint32_t h0 = 0x67452301; - uint32_t h1 = 0xEFCDAB89; - uint32_t h2 = 0x98BADCFE; - uint32_t h3 = 0x10325476; - uint32_t h4 = 0xC3D2E1F0; - - for (size_t offset = 0; offset < data.size(); offset += 64) { - uint32_t w[80]; - for (int i = 0; i < 16; ++i) { - w[i] = (static_cast(data[offset + i * 4]) << 24) | - (static_cast(data[offset + i * 4 + 1]) << 16) | - (static_cast(data[offset + i * 4 + 2]) << 8) | - static_cast(data[offset + i * 4 + 3]); - } - for (int i = 16; i < 80; ++i) { - w[i] = leftRotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); - } - uint32_t a = h0; - uint32_t b = h1; - uint32_t c = h2; - uint32_t d = h3; - uint32_t e = h4; - for (int i = 0; i < 80; ++i) { - uint32_t f; - uint32_t k; - if (i < 20) { - f = (b & c) | ((~b) & d); - k = 0x5A827999; - } else if (i < 40) { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } else if (i < 60) { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } else { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = leftRotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = leftRotate(b, 30); - b = a; - a = temp; - } - h0 += a; - h1 += b; - h2 += c; - h3 += d; - h4 += e; - } - - std::vector digest(20); - uint32_t output[5] = {h0, h1, h2, h3, h4}; - for (int i = 0; i < 5; ++i) { - digest[i * 4] = static_cast((output[i] >> 24) & 0xFF); - digest[i * 4 + 1] = static_cast((output[i] >> 16) & 0xFF); - digest[i * 4 + 2] = static_cast((output[i] >> 8) & 0xFF); - digest[i * 4 + 3] = static_cast(output[i] & 0xFF); - } - return digest; - } - - static bool computeDigest(HashObject &hash) { - if (hash.digestComputed) { - return true; - } - switch (hash.algid) { - case CALG_MD5: - hash.digest = computeMD5(hash.data); - hash.digestComputed = true; - return true; - case CALG_SHA1: - hash.digest = computeSHA1(hash.data); - hash.digestComputed = true; - return true; - default: - return false; - } - } } namespace advapi32 { - LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, const uint16_t *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); - if (!phkResult) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return ERROR_INVALID_PARAMETER; - } - *phkResult = nullptr; - if ((ulOptions & ~REG_OPTION_OPEN_LINK) != 0) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return ERROR_INVALID_PARAMETER; - } - if (ulOptions & REG_OPTION_OPEN_LINK) { - DEBUG_LOG("RegOpenKeyExW: ignoring REG_OPTION_OPEN_LINK\n"); - } - REGSAM sanitizedAccess = samDesired & ~(KEY_WOW64_64KEY | KEY_WOW64_32KEY); - if (sanitizedAccess != samDesired) { - DEBUG_LOG("RegOpenKeyExW: ignoring WOW64 access mask 0x%x\n", samDesired ^ sanitizedAccess); - } - (void) sanitizedAccess; - std::lock_guard lock(registryMutex); - ensureRegistryInitializedLocked(); - RegistryKeyHandleData *baseHandle = handleDataFromHKeyLocked(hKey); - if (!baseHandle) { - wibo::lastError = ERROR_INVALID_HANDLE; - return ERROR_INVALID_HANDLE; - } - std::u16string targetPath = baseHandle->canonicalPath; - if (lpSubKey && lpSubKey[0] != 0) { - std::u16string subComponent = canonicalizeKeySegment(lpSubKey); - if (!subComponent.empty()) { - if (!targetPath.empty()) { - targetPath.push_back(u'\\'); - } - targetPath.append(subComponent); - } - } - if (targetPath.empty()) { - wibo::lastError = ERROR_INVALID_HANDLE; - return ERROR_INVALID_HANDLE; - } - if (existingKeys.find(targetPath) == existingKeys.end()) { - wibo::lastError = ERROR_FILE_NOT_FOUND; - return ERROR_FILE_NOT_FOUND; - } - if (!lpSubKey || lpSubKey[0] == 0) { - if (baseHandle->predefined) { - *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 RegOpenKeyExA(HKEY hKey, const char *lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { - DEBUG_LOG("RegOpenKeyExA(%p, %s, %u, 0x%x, %p)\n", hKey, lpSubKey ? lpSubKey : "(null)", ulOptions, samDesired, phkResult); - const uint16_t *widePtr = nullptr; - std::vector wideStorage; - if (lpSubKey) { - wideStorage = stringToWideString(lpSubKey); - widePtr = wideStorage.data(); - } - return RegOpenKeyExW(hKey, widePtr, ulOptions, samDesired, phkResult); - } - - LSTATUS WIN_FUNC RegCloseKey(HKEY hKey) { - DEBUG_LOG("RegCloseKey(%p)\n", hKey); - if (isPredefinedKeyHandle(hKey)) { - wibo::lastError = ERROR_SUCCESS; - return ERROR_SUCCESS; - } - auto data = handles::dataFromHandle(hKey, true); - if (data.type != handles::TYPE_REGISTRY_KEY || data.ptr == nullptr) { - wibo::lastError = ERROR_INVALID_HANDLE; - return ERROR_INVALID_HANDLE; - } - auto *handleData = static_cast(data.ptr); - delete handleData; - wibo::lastError = ERROR_SUCCESS; - return ERROR_SUCCESS; - } - - BOOL WIN_FUNC CryptReleaseContext(void* hProv, unsigned int dwFlags) { - DEBUG_LOG("STUB: CryptReleaseContext(%p, %u)\n", hProv, dwFlags); - return TRUE; - } - - BOOL WIN_FUNC CryptAcquireContextW(void **phProv, const uint16_t *pszContainer, const uint16_t *pszProvider, - unsigned int dwProvType, unsigned int dwFlags) { - DEBUG_LOG("STUB: CryptAcquireContextW(%p, %p, %p, %u, %u)\n", phProv, pszContainer, pszProvider, dwProvType, dwFlags); - - // to quote the guy above me: screw them for now - static int lmao = 42; - if (phProv) { - *phProv = &lmao; - return TRUE; - } - - return FALSE; - } - - BOOL WIN_FUNC CryptGenRandom(void* hProv, unsigned int dwLen, unsigned char* pbBuffer){ - DEBUG_LOG("CryptGenRandom(%p)\n", hProv); - if (!pbBuffer || dwLen == 0) return FALSE; - - ssize_t ret = getrandom(pbBuffer, dwLen, 0); - if (ret < 0 || (size_t)ret != dwLen) { - return FALSE; - } - - return TRUE; - } - - BOOL WIN_FUNC CryptCreateHash(void* hProv, unsigned int Algid, void* hKey, unsigned int dwFlags, void** phHash) { - DEBUG_LOG("CryptCreateHash(%p, %u, %p, %u, %p)\n", hProv, Algid, hKey, dwFlags, phHash); - (void)hProv; - if (!phHash) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - if (dwFlags != 0) { - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - if (hKey != nullptr) { - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - if (Algid != CALG_MD5 && Algid != CALG_SHA1) { - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - auto *hash = new HashObject; - hash->algid = Algid; - hash->digestComputed = false; - hash->data.clear(); - hash->digest.clear(); - *phHash = hash; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC CryptHashData(void* hHash, const unsigned char* pbData, unsigned int dwDataLen, unsigned int dwFlags) { - DEBUG_LOG("CryptHashData(%p, %p, %u, %u)\n", hHash, pbData, dwDataLen, dwFlags); - if (!hHash || (dwDataLen && !pbData) || dwFlags != 0) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto *hash = reinterpret_cast(hHash); - if (pbData && dwDataLen) { - hash->data.insert(hash->data.end(), pbData, pbData + dwDataLen); - hash->digestComputed = false; - hash->digest.clear(); - } - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - - BOOL WIN_FUNC CryptGetHashParam(void* hHash, unsigned int dwParam, unsigned char* pbData, unsigned int* pdwDataLen, unsigned int dwFlags) { - DEBUG_LOG("CryptGetHashParam(%p, %u, %p, %p, %u)\n", hHash, dwParam, pbData, pdwDataLen, dwFlags); - if (!hHash || !pdwDataLen || dwFlags != 0) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - auto *hash = reinterpret_cast(hHash); - switch (dwParam) { - case HP_ALGID: { - unsigned int required = sizeof(ALG_ID); - if (!pbData) { - *pdwDataLen = required; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (*pdwDataLen < required) { - *pdwDataLen = required; - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - memcpy(pbData, &hash->algid, required); - *pdwDataLen = required; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - case HP_HASHSIZE: { - unsigned int size = 0; - switch (hash->algid) { - case CALG_MD5: - size = 16; - break; - case CALG_SHA1: - size = 20; - break; - default: - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - if (!pbData) { - *pdwDataLen = sizeof(unsigned int); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (*pdwDataLen < sizeof(unsigned int)) { - *pdwDataLen = sizeof(unsigned int); - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - memcpy(pbData, &size, sizeof(unsigned int)); - *pdwDataLen = sizeof(unsigned int); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - case HP_HASHVAL: { - if (!computeDigest(*hash)) { - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - unsigned int required = hash->digest.size(); - if (!pbData) { - *pdwDataLen = required; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - if (*pdwDataLen < required) { - *pdwDataLen = required; - wibo::lastError = ERROR_INSUFFICIENT_BUFFER; - return FALSE; - } - memcpy(pbData, hash->digest.data(), required); - *pdwDataLen = required; - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - default: - wibo::lastError = ERROR_NOT_SUPPORTED; - return FALSE; - } - } - - BOOL WIN_FUNC CryptDestroyHash(void* hHash) { - DEBUG_LOG("CryptDestroyHash(%p)\n", hHash); - if (!hHash) { - wibo::lastError = ERROR_INVALID_PARAMETER; - return FALSE; - } - delete reinterpret_cast(hHash); - wibo::lastError = ERROR_SUCCESS; - return TRUE; - } - BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle) { DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle); if (!TokenHandle) { @@ -1092,9 +509,11 @@ namespace advapi32 { } 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; diff --git a/dll/advapi32/wincrypt.cpp b/dll/advapi32/wincrypt.cpp new file mode 100644 index 0000000..9daae14 --- /dev/null +++ b/dll/advapi32/wincrypt.cpp @@ -0,0 +1,396 @@ +#include "wincrypt.h" + +#include "errors.h" + +#include +#include +#include + +namespace { + +struct HashObject { + ALG_ID algid = 0; + std::vector data; + std::vector digest; + bool digestComputed = false; +}; + +uint32_t leftRotate(uint32_t value, uint32_t bits) { return (value << bits) | (value >> (32 - bits)); } + +std::vector computeMD5(const std::vector &input) { + static const uint32_t s[64] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; + static const uint32_t K[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391}; + + std::vector data = input; + uint64_t bitLen = static_cast(data.size()) * 8ULL; + data.push_back(0x80); + while ((data.size() % 64) != 56) { + data.push_back(0); + } + for (int i = 0; i < 8; ++i) { + data.push_back(static_cast((bitLen >> (8 * i)) & 0xFF)); + } + + uint32_t A = 0x67452301; + uint32_t B = 0xEFCDAB89; + uint32_t C = 0x98BADCFE; + uint32_t D = 0x10325476; + + for (size_t offset = 0; offset < data.size(); offset += 64) { + uint32_t M[16]; + for (int i = 0; i < 16; ++i) { + M[i] = static_cast(data[offset + i * 4]) | + (static_cast(data[offset + i * 4 + 1]) << 8) | + (static_cast(data[offset + i * 4 + 2]) << 16) | + (static_cast(data[offset + i * 4 + 3]) << 24); + } + uint32_t a = A; + uint32_t b = B; + uint32_t c = C; + uint32_t d = D; + for (int i = 0; i < 64; ++i) { + uint32_t F; + int g; + if (i < 16) { + F = (b & c) | ((~b) & d); + g = i; + } else if (i < 32) { + F = (d & b) | ((~d) & c); + g = (5 * i + 1) % 16; + } else if (i < 48) { + F = b ^ c ^ d; + g = (3 * i + 5) % 16; + } else { + F = c ^ (b | (~d)); + g = (7 * i) % 16; + } + uint32_t temp = d; + d = c; + c = b; + uint32_t rotateVal = a + F + K[i] + M[g]; + b = b + leftRotate(rotateVal, s[i]); + a = temp; + } + A += a; + B += b; + C += c; + D += d; + } + + std::vector digest(16); + uint32_t output[4] = {A, B, C, D}; + for (int i = 0; i < 4; ++i) { + digest[i * 4] = static_cast(output[i] & 0xFF); + digest[i * 4 + 1] = static_cast((output[i] >> 8) & 0xFF); + digest[i * 4 + 2] = static_cast((output[i] >> 16) & 0xFF); + digest[i * 4 + 3] = static_cast((output[i] >> 24) & 0xFF); + } + return digest; +} + +std::vector computeSHA1(const std::vector &input) { + std::vector data = input; + uint64_t bitLen = static_cast(data.size()) * 8ULL; + data.push_back(0x80); + while ((data.size() % 64) != 56) { + data.push_back(0); + } + for (int i = 7; i >= 0; --i) { + data.push_back(static_cast((bitLen >> (8 * i)) & 0xFF)); + } + + uint32_t h0 = 0x67452301; + uint32_t h1 = 0xEFCDAB89; + uint32_t h2 = 0x98BADCFE; + uint32_t h3 = 0x10325476; + uint32_t h4 = 0xC3D2E1F0; + + for (size_t offset = 0; offset < data.size(); offset += 64) { + uint32_t w[80]; + for (int i = 0; i < 16; ++i) { + w[i] = (static_cast(data[offset + i * 4]) << 24) | + (static_cast(data[offset + i * 4 + 1]) << 16) | + (static_cast(data[offset + i * 4 + 2]) << 8) | + static_cast(data[offset + i * 4 + 3]); + } + for (int i = 16; i < 80; ++i) { + w[i] = leftRotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); + } + uint32_t a = h0; + uint32_t b = h1; + uint32_t c = h2; + uint32_t d = h3; + uint32_t e = h4; + for (int i = 0; i < 80; ++i) { + uint32_t f; + uint32_t k; + if (i < 20) { + f = (b & c) | ((~b) & d); + k = 0x5A827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = leftRotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = leftRotate(b, 30); + b = a; + a = temp; + } + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + } + + std::vector digest(20); + uint32_t output[5] = {h0, h1, h2, h3, h4}; + for (int i = 0; i < 5; ++i) { + digest[i * 4] = static_cast((output[i] >> 24) & 0xFF); + digest[i * 4 + 1] = static_cast((output[i] >> 16) & 0xFF); + digest[i * 4 + 2] = static_cast((output[i] >> 8) & 0xFF); + digest[i * 4 + 3] = static_cast(output[i] & 0xFF); + } + return digest; +} + +bool computeDigest(HashObject &hash) { + if (hash.digestComputed) { + return true; + } + switch (hash.algid) { + case CALG_MD5: + hash.digest = computeMD5(hash.data); + hash.digestComputed = true; + return true; + case CALG_SHA1: + hash.digest = computeSHA1(hash.data); + hash.digestComputed = true; + return true; + default: + return false; + } +} + +HashObject *hashObjectFromHandle(HCRYPTHASH hHash) { + if (hHash == 0) { + return nullptr; + } + return reinterpret_cast(static_cast(hHash)); +} + +HCRYPTHASH hashHandleFromObject(HashObject *hash) { return static_cast(reinterpret_cast(hash)); } + +} // namespace + +namespace advapi32 { + +BOOL WIN_FUNC CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) { + DEBUG_LOG("STUB: CryptReleaseContext(%p, %u)\n", reinterpret_cast(static_cast(hProv)), dwFlags); + (void)hProv; + (void)dwFlags; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType, + DWORD dwFlags) { + DEBUG_LOG("STUB: CryptAcquireContextW(%p, %p, %p, %u, %u)\n", phProv, pszContainer, pszProvider, dwProvType, + dwFlags); + // to quote the guy above me: screw them for now + static int dummyProvider = 42; + if (!phProv) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + *phProv = static_cast(reinterpret_cast(&dummyProvider)); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) { + DEBUG_LOG("CryptGenRandom(%p)\n", reinterpret_cast(static_cast(hProv))); + (void)hProv; + if (!pbBuffer || dwLen == 0) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + + ssize_t ret = getrandom(pbBuffer, dwLen, 0); + if (ret < 0 || static_cast(ret) != dwLen) { + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } + + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash) { + DEBUG_LOG("CryptCreateHash(%p, %u, %p, %u, %p)\n", reinterpret_cast(static_cast(hProv)), Algid, + reinterpret_cast(static_cast(hKey)), dwFlags, phHash); + (void)hProv; + if (!phHash) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + if (dwFlags != 0) { + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } + if (hKey != 0) { + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } + if (Algid != CALG_MD5 && Algid != CALG_SHA1) { + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } + auto *hash = new HashObject; + hash->algid = Algid; + hash->digestComputed = false; + hash->data.clear(); + hash->digest.clear(); + *phHash = hashHandleFromObject(hash); + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags) { + DEBUG_LOG("CryptHashData(%p, %p, %u, %u)\n", reinterpret_cast(static_cast(hHash)), pbData, + dwDataLen, dwFlags); + if (dwFlags != 0) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto *hash = hashObjectFromHandle(hHash); + if (!hash || (dwDataLen != 0 && !pbData)) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + if (pbData && dwDataLen) { + hash->data.insert(hash->data.end(), pbData, pbData + dwDataLen); + hash->digestComputed = false; + hash->digest.clear(); + } + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +BOOL WIN_FUNC CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags) { + DEBUG_LOG("CryptGetHashParam(%p, %u, %p, %p, %u)\n", reinterpret_cast(static_cast(hHash)), + dwParam, pbData, pdwDataLen, dwFlags); + if (dwFlags != 0 || !pdwDataLen) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + auto *hash = hashObjectFromHandle(hHash); + if (!hash) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + switch (dwParam) { + case HP_ALGID: { + DWORD required = sizeof(ALG_ID); + if (!pbData) { + *pdwDataLen = required; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (*pdwDataLen < required) { + *pdwDataLen = required; + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + memcpy(pbData, &hash->algid, required); + *pdwDataLen = required; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + case HP_HASHSIZE: { + DWORD size = 0; + switch (hash->algid) { + case CALG_MD5: + size = 16; + break; + case CALG_SHA1: + size = 20; + break; + default: + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } + if (!pbData) { + *pdwDataLen = sizeof(DWORD); + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (*pdwDataLen < sizeof(DWORD)) { + *pdwDataLen = sizeof(DWORD); + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + memcpy(pbData, &size, sizeof(DWORD)); + *pdwDataLen = sizeof(DWORD); + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + case HP_HASHVAL: { + if (!computeDigest(*hash)) { + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } + DWORD required = static_cast(hash->digest.size()); + if (!pbData) { + *pdwDataLen = required; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + if (*pdwDataLen < required) { + *pdwDataLen = required; + wibo::lastError = ERROR_INSUFFICIENT_BUFFER; + return FALSE; + } + memcpy(pbData, hash->digest.data(), required); + *pdwDataLen = required; + wibo::lastError = ERROR_SUCCESS; + return TRUE; + } + default: + wibo::lastError = ERROR_NOT_SUPPORTED; + return FALSE; + } +} + +BOOL WIN_FUNC CryptDestroyHash(HCRYPTHASH hHash) { + DEBUG_LOG("CryptDestroyHash(%p)\n", reinterpret_cast(static_cast(hHash))); + auto *hash = hashObjectFromHandle(hHash); + if (!hash) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return FALSE; + } + delete hash; + wibo::lastError = ERROR_SUCCESS; + return TRUE; +} + +} // namespace advapi32 diff --git a/dll/advapi32/wincrypt.h b/dll/advapi32/wincrypt.h new file mode 100644 index 0000000..29a3821 --- /dev/null +++ b/dll/advapi32/wincrypt.h @@ -0,0 +1,28 @@ +#pragma once + +#include "common.h" + +using ALG_ID = DWORD; +using HCRYPTPROV = ULONG_PTR; +using HCRYPTKEY = ULONG_PTR; +using HCRYPTHASH = ULONG_PTR; + +constexpr ALG_ID CALG_MD5 = 0x00008003; +constexpr ALG_ID CALG_SHA1 = 0x00008004; + +constexpr DWORD HP_ALGID = 0x00000001; +constexpr DWORD HP_HASHVAL = 0x00000002; +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, + 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); + +} // namespace advapi32 diff --git a/dll/advapi32/winreg.cpp b/dll/advapi32/winreg.cpp new file mode 100644 index 0000000..e3fa879 --- /dev/null +++ b/dll/advapi32/winreg.cpp @@ -0,0 +1,228 @@ +#include "winreg.h" + +#include "errors.h" +#include "handles.h" +#include "strutil.h" + +#include +#include +#include +#include +#include + +namespace { + +struct RegistryKeyHandleData { + std::u16string canonicalPath; + bool predefined = false; +}; + +struct PredefinedKeyInfo { + uintptr_t value; + const char16_t *name; +}; + +constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = { + {static_cast(0x80000000u), u"HKEY_CLASSES_ROOT"}, + {static_cast(0x80000001u), u"HKEY_CURRENT_USER"}, + {static_cast(0x80000002u), u"HKEY_LOCAL_MACHINE"}, + {static_cast(0x80000003u), u"HKEY_USERS"}, + {static_cast(0x80000004u), u"HKEY_PERFORMANCE_DATA"}, + {static_cast(0x80000005u), u"HKEY_CURRENT_CONFIG"}, +}; + +constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos); + +std::mutex registryMutex; +bool predefinedHandlesInitialized = false; +RegistryKeyHandleData predefinedHandles[kPredefinedKeyCount]; +bool registryInitialized = false; +std::unordered_set existingKeys; + +std::u16string canonicalizeKeySegment(const std::u16string &input) { + std::u16string result; + result.reserve(input.size()); + bool lastWasSlash = false; + for (char16_t ch : input) { + char16_t normalized = (ch == u'/') ? u'\\' : ch; + if (normalized == u'\\') { + if (!result.empty() && !lastWasSlash) { + result.push_back(u'\\'); + } + lastWasSlash = true; + continue; + } + lastWasSlash = false; + uint16_t lowered = wcharToLower(static_cast(normalized)); + result.push_back(static_cast(lowered)); + } + while (!result.empty() && result.back() == u'\\') { + result.pop_back(); + } + auto it = result.begin(); + while (it != result.end() && *it == u'\\') { + it = result.erase(it); + } + return result; +} + +std::u16string canonicalizeKeySegment(LPCWSTR input) { + if (!input) { + return {}; + } + std::u16string wide(reinterpret_cast(input), wstrlen(input)); + return canonicalizeKeySegment(wide); +} + +void initializePredefinedHandlesLocked() { + if (predefinedHandlesInitialized) { + return; + } + for (size_t i = 0; i < kPredefinedKeyCount; ++i) { + predefinedHandles[i].canonicalPath = canonicalizeKeySegment(std::u16string(kPredefinedKeyInfos[i].name)); + predefinedHandles[i].predefined = true; + } + predefinedHandlesInitialized = true; +} + +RegistryKeyHandleData *predefinedHandleForValue(uintptr_t value) { + for (size_t i = 0; i < kPredefinedKeyCount; ++i) { + if (kPredefinedKeyInfos[i].value == value) { + return &predefinedHandles[i]; + } + } + return nullptr; +} + +RegistryKeyHandleData *handleDataFromHKeyLocked(HKEY hKey) { + uintptr_t raw = reinterpret_cast(hKey); + if (raw == 0) { + return nullptr; + } + initializePredefinedHandlesLocked(); + if (auto *predefined = predefinedHandleForValue(raw)) { + return predefined; + } + auto data = handles::dataFromHandle(hKey, false); + if (data.type != handles::TYPE_REGISTRY_KEY || data.ptr == nullptr) { + return nullptr; + } + return static_cast(data.ptr); +} + +bool isPredefinedKeyHandle(HKEY hKey) { + uintptr_t raw = reinterpret_cast(hKey); + for (size_t i = 0; i < kPredefinedKeyCount; ++i) { + if (kPredefinedKeyInfos[i].value == raw) { + return true; + } + } + return false; +} + +void ensureRegistryInitializedLocked() { + if (registryInitialized) { + return; + } + initializePredefinedHandlesLocked(); + for (size_t i = 0; i < kPredefinedKeyCount; ++i) { + existingKeys.insert(predefinedHandles[i].canonicalPath); + } + registryInitialized = true; +} + +} // namespace + +namespace advapi32 { + +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); + if (!phkResult) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + *phkResult = nullptr; + if ((ulOptions & ~REG_OPTION_OPEN_LINK) != 0) { + wibo::lastError = ERROR_INVALID_PARAMETER; + return ERROR_INVALID_PARAMETER; + } + if (ulOptions & REG_OPTION_OPEN_LINK) { + DEBUG_LOG("RegOpenKeyExW: ignoring REG_OPTION_OPEN_LINK\n"); + } + REGSAM sanitizedAccess = samDesired & ~(KEY_WOW64_64KEY | KEY_WOW64_32KEY); + if (sanitizedAccess != samDesired) { + DEBUG_LOG("RegOpenKeyExW: ignoring WOW64 access mask 0x%x\n", samDesired ^ sanitizedAccess); + } + (void)sanitizedAccess; + std::lock_guard lock(registryMutex); + ensureRegistryInitializedLocked(); + RegistryKeyHandleData *baseHandle = handleDataFromHKeyLocked(hKey); + if (!baseHandle) { + wibo::lastError = ERROR_INVALID_HANDLE; + return ERROR_INVALID_HANDLE; + } + std::u16string targetPath = baseHandle->canonicalPath; + if (lpSubKey && lpSubKey[0] != 0) { + std::u16string subComponent = canonicalizeKeySegment(lpSubKey); + if (!subComponent.empty()) { + if (!targetPath.empty()) { + targetPath.push_back(u'\\'); + } + targetPath.append(subComponent); + } + } + if (targetPath.empty()) { + wibo::lastError = ERROR_INVALID_HANDLE; + return ERROR_INVALID_HANDLE; + } + if (existingKeys.find(targetPath) == existingKeys.end()) { + wibo::lastError = ERROR_FILE_NOT_FOUND; + return ERROR_FILE_NOT_FOUND; + } + if (!lpSubKey || lpSubKey[0] == 0) { + if (baseHandle->predefined) { + *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 RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { + DEBUG_LOG("RegOpenKeyExA(%p, %s, %u, 0x%x, %p)\n", hKey, lpSubKey ? lpSubKey : "(null)", ulOptions, samDesired, + phkResult); + LPCWSTR widePtr = nullptr; + std::vector wideStorage; + if (lpSubKey) { + wideStorage = stringToWideString(lpSubKey); + widePtr = reinterpret_cast(wideStorage.data()); + } + return RegOpenKeyExW(hKey, widePtr, ulOptions, samDesired, phkResult); +} + +LSTATUS WIN_FUNC RegCloseKey(HKEY hKey) { + DEBUG_LOG("RegCloseKey(%p)\n", hKey); + if (isPredefinedKeyHandle(hKey)) { + wibo::lastError = ERROR_SUCCESS; + return ERROR_SUCCESS; + } + auto data = handles::dataFromHandle(hKey, true); + if (data.type != handles::TYPE_REGISTRY_KEY || data.ptr == nullptr) { + wibo::lastError = ERROR_INVALID_HANDLE; + return ERROR_INVALID_HANDLE; + } + auto *handleData = static_cast(data.ptr); + delete handleData; + wibo::lastError = ERROR_SUCCESS; + return ERROR_SUCCESS; +} + +} // namespace advapi32 diff --git a/dll/advapi32/winreg.h b/dll/advapi32/winreg.h new file mode 100644 index 0000000..004e6eb --- /dev/null +++ b/dll/advapi32/winreg.h @@ -0,0 +1,35 @@ +#pragma once + +#include "common.h" + +#ifndef HKEY_CLASSES_ROOT +#define HKEY_CLASSES_ROOT ((HKEY)(uintptr_t)0x80000000u) +#endif +#ifndef HKEY_CURRENT_USER +#define HKEY_CURRENT_USER ((HKEY)(uintptr_t)0x80000001u) +#endif +#ifndef HKEY_LOCAL_MACHINE +#define HKEY_LOCAL_MACHINE ((HKEY)(uintptr_t)0x80000002u) +#endif +#ifndef HKEY_USERS +#define HKEY_USERS ((HKEY)(uintptr_t)0x80000003u) +#endif +#ifndef HKEY_PERFORMANCE_DATA +#define HKEY_PERFORMANCE_DATA ((HKEY)(uintptr_t)0x80000004u) +#endif +#ifndef HKEY_CURRENT_CONFIG +#define HKEY_CURRENT_CONFIG ((HKEY)(uintptr_t)0x80000005u) +#endif + +constexpr DWORD REG_OPTION_OPEN_LINK = 0x00000008; + +constexpr REGSAM KEY_WOW64_64KEY = 0x00000100; +constexpr REGSAM KEY_WOW64_32KEY = 0x00000200; + +namespace advapi32 { + +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 RegCloseKey(HKEY hKey); + +} // namespace advapi32