Split advapi32 into separate files (part 1)

This commit is contained in:
Luke Street 2025-10-02 01:20:51 -06:00
parent 2cbd624119
commit 79e1dbf523
6 changed files with 693 additions and 585 deletions

View File

@ -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

View File

@ -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 <cstring>
#include <mutex>
#include <string>
#include <sys/random.h>
#include <unordered_set>
#include <unordered_map>
#include <vector>
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<std::u16string> existingKeys;
struct Luid;
static std::mutex privilegeMapMutex;
static std::unordered_map<std::string, Luid> 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<uint16_t>(normalized));
result.push_back(static_cast<char16_t>(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<const char16_t *>(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<uintptr_t>(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<RegistryKeyHandleData *>(data.ptr);
}
static bool isPredefinedKeyHandle(HKEY hKey) {
uintptr_t raw = reinterpret_cast<uintptr_t>(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<uint8_t> data;
std::vector<uint8_t> 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<uint8_t> computeMD5(const std::vector<uint8_t> &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<uint8_t> data = input;
uint64_t bitLen = static_cast<uint64_t>(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<uint8_t>((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<uint32_t>(data[offset + i * 4]) |
(static_cast<uint32_t>(data[offset + i * 4 + 1]) << 8) |
(static_cast<uint32_t>(data[offset + i * 4 + 2]) << 16) |
(static_cast<uint32_t>(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<uint8_t> digest(16);
uint32_t output[4] = {A, B, C, D};
for (int i = 0; i < 4; ++i) {
digest[i * 4] = static_cast<uint8_t>(output[i] & 0xFF);
digest[i * 4 + 1] = static_cast<uint8_t>((output[i] >> 8) & 0xFF);
digest[i * 4 + 2] = static_cast<uint8_t>((output[i] >> 16) & 0xFF);
digest[i * 4 + 3] = static_cast<uint8_t>((output[i] >> 24) & 0xFF);
}
return digest;
}
static std::vector<uint8_t> computeSHA1(const std::vector<uint8_t> &input) {
std::vector<uint8_t> data = input;
uint64_t bitLen = static_cast<uint64_t>(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<uint8_t>((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<uint32_t>(data[offset + i * 4]) << 24) |
(static_cast<uint32_t>(data[offset + i * 4 + 1]) << 16) |
(static_cast<uint32_t>(data[offset + i * 4 + 2]) << 8) |
static_cast<uint32_t>(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<uint8_t> digest(20);
uint32_t output[5] = {h0, h1, h2, h3, h4};
for (int i = 0; i < 5; ++i) {
digest[i * 4] = static_cast<uint8_t>((output[i] >> 24) & 0xFF);
digest[i * 4 + 1] = static_cast<uint8_t>((output[i] >> 16) & 0xFF);
digest[i * 4 + 2] = static_cast<uint8_t>((output[i] >> 8) & 0xFF);
digest[i * 4 + 3] = static_cast<uint8_t>(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<std::mutex> 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<HKEY>(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<uint16_t> 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<RegistryKeyHandleData *>(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<HashObject *>(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<HashObject *>(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<HashObject *>(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;

396
dll/advapi32/wincrypt.cpp Normal file
View File

@ -0,0 +1,396 @@
#include "wincrypt.h"
#include "errors.h"
#include <cstring>
#include <sys/random.h>
#include <vector>
namespace {
struct HashObject {
ALG_ID algid = 0;
std::vector<uint8_t> data;
std::vector<uint8_t> digest;
bool digestComputed = false;
};
uint32_t leftRotate(uint32_t value, uint32_t bits) { return (value << bits) | (value >> (32 - bits)); }
std::vector<uint8_t> computeMD5(const std::vector<uint8_t> &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<uint8_t> data = input;
uint64_t bitLen = static_cast<uint64_t>(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<uint8_t>((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<uint32_t>(data[offset + i * 4]) |
(static_cast<uint32_t>(data[offset + i * 4 + 1]) << 8) |
(static_cast<uint32_t>(data[offset + i * 4 + 2]) << 16) |
(static_cast<uint32_t>(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<uint8_t> digest(16);
uint32_t output[4] = {A, B, C, D};
for (int i = 0; i < 4; ++i) {
digest[i * 4] = static_cast<uint8_t>(output[i] & 0xFF);
digest[i * 4 + 1] = static_cast<uint8_t>((output[i] >> 8) & 0xFF);
digest[i * 4 + 2] = static_cast<uint8_t>((output[i] >> 16) & 0xFF);
digest[i * 4 + 3] = static_cast<uint8_t>((output[i] >> 24) & 0xFF);
}
return digest;
}
std::vector<uint8_t> computeSHA1(const std::vector<uint8_t> &input) {
std::vector<uint8_t> data = input;
uint64_t bitLen = static_cast<uint64_t>(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<uint8_t>((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<uint32_t>(data[offset + i * 4]) << 24) |
(static_cast<uint32_t>(data[offset + i * 4 + 1]) << 16) |
(static_cast<uint32_t>(data[offset + i * 4 + 2]) << 8) |
static_cast<uint32_t>(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<uint8_t> digest(20);
uint32_t output[5] = {h0, h1, h2, h3, h4};
for (int i = 0; i < 5; ++i) {
digest[i * 4] = static_cast<uint8_t>((output[i] >> 24) & 0xFF);
digest[i * 4 + 1] = static_cast<uint8_t>((output[i] >> 16) & 0xFF);
digest[i * 4 + 2] = static_cast<uint8_t>((output[i] >> 8) & 0xFF);
digest[i * 4 + 3] = static_cast<uint8_t>(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<HashObject *>(static_cast<uintptr_t>(hHash));
}
HCRYPTHASH hashHandleFromObject(HashObject *hash) { return static_cast<HCRYPTHASH>(reinterpret_cast<uintptr_t>(hash)); }
} // namespace
namespace advapi32 {
BOOL WIN_FUNC CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags) {
DEBUG_LOG("STUB: CryptReleaseContext(%p, %u)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(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<HCRYPTPROV>(reinterpret_cast<uintptr_t>(&dummyProvider));
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) {
DEBUG_LOG("CryptGenRandom(%p)\n", reinterpret_cast<void *>(static_cast<uintptr_t>(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<DWORD>(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<void *>(static_cast<uintptr_t>(hProv)), Algid,
reinterpret_cast<void *>(static_cast<uintptr_t>(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<void *>(static_cast<uintptr_t>(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<void *>(static_cast<uintptr_t>(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<DWORD>(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<void *>(static_cast<uintptr_t>(hHash)));
auto *hash = hashObjectFromHandle(hHash);
if (!hash) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
delete hash;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
} // namespace advapi32

28
dll/advapi32/wincrypt.h Normal file
View File

@ -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

228
dll/advapi32/winreg.cpp Normal file
View File

@ -0,0 +1,228 @@
#include "winreg.h"
#include "errors.h"
#include "handles.h"
#include "strutil.h"
#include <iterator>
#include <mutex>
#include <string>
#include <unordered_set>
#include <vector>
namespace {
struct RegistryKeyHandleData {
std::u16string canonicalPath;
bool predefined = false;
};
struct PredefinedKeyInfo {
uintptr_t value;
const char16_t *name;
};
constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = {
{static_cast<uintptr_t>(0x80000000u), u"HKEY_CLASSES_ROOT"},
{static_cast<uintptr_t>(0x80000001u), u"HKEY_CURRENT_USER"},
{static_cast<uintptr_t>(0x80000002u), u"HKEY_LOCAL_MACHINE"},
{static_cast<uintptr_t>(0x80000003u), u"HKEY_USERS"},
{static_cast<uintptr_t>(0x80000004u), u"HKEY_PERFORMANCE_DATA"},
{static_cast<uintptr_t>(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<std::u16string> 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<uint16_t>(normalized));
result.push_back(static_cast<char16_t>(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<const char16_t *>(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<uintptr_t>(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<RegistryKeyHandleData *>(data.ptr);
}
bool isPredefinedKeyHandle(HKEY hKey) {
uintptr_t raw = reinterpret_cast<uintptr_t>(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<std::mutex> 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<HKEY>(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<uint16_t> wideStorage;
if (lpSubKey) {
wideStorage = stringToWideString(lpSubKey);
widePtr = reinterpret_cast<LPCWSTR>(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<RegistryKeyHandleData *>(data.ptr);
delete handleData;
wibo::lastError = ERROR_SUCCESS;
return ERROR_SUCCESS;
}
} // namespace advapi32

35
dll/advapi32/winreg.h Normal file
View File

@ -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