mirror of
https://github.com/decompals/wibo.git
synced 2025-10-27 20:30:24 +00:00
Improve current thread handles
This commit is contained in:
parent
41f8388bac
commit
c099a1b577
4
common.h
4
common.h
@ -60,6 +60,10 @@ typedef size_t SIZE_T;
|
||||
typedef SIZE_T *PSIZE_T;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned int UINT;
|
||||
typedef void *HKEY;
|
||||
typedef HKEY *PHKEY;
|
||||
typedef DWORD REGSAM;
|
||||
typedef LONG LSTATUS;
|
||||
|
||||
typedef struct _OVERLAPPED {
|
||||
ULONG_PTR Internal;
|
||||
|
||||
522
dll/advapi32.cpp
522
dll/advapi32.cpp
@ -4,10 +4,142 @@
|
||||
#include "strutil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#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;
|
||||
@ -17,6 +149,20 @@ namespace {
|
||||
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;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct HashObject {
|
||||
ALG_ID algid = 0;
|
||||
std::vector<uint8_t> data;
|
||||
@ -83,6 +229,11 @@ namespace {
|
||||
int32_t HighPart = 0;
|
||||
};
|
||||
|
||||
struct LuidAndAttributes {
|
||||
Luid value;
|
||||
DWORD Attributes = 0;
|
||||
};
|
||||
|
||||
struct TokenStatisticsData {
|
||||
Luid tokenId;
|
||||
Luid authenticationId;
|
||||
@ -287,9 +438,93 @@ namespace {
|
||||
}
|
||||
|
||||
namespace advapi32 {
|
||||
unsigned int WIN_FUNC RegOpenKeyExA(void *hKey, const char *lpSubKey, unsigned int ulOptions, void *samDesired, void **phkResult) {
|
||||
DEBUG_LOG("STUB: RegOpenKeyExA(%p, %s, ...)\n", hKey, lpSubKey);
|
||||
return 1; // screw them for now
|
||||
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) {
|
||||
@ -496,6 +731,7 @@ namespace advapi32 {
|
||||
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);
|
||||
@ -545,6 +781,28 @@ namespace advapi32 {
|
||||
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<unsigned int>(headerSize + sidSize);
|
||||
*ReturnLength = required;
|
||||
if (!TokenInformation || TokenInformationLength < required) {
|
||||
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
|
||||
return FALSE;
|
||||
}
|
||||
auto *groupInfo = reinterpret_cast<TokenPrimaryGroupStub *>(TokenInformation);
|
||||
auto *sid = reinterpret_cast<Sid *>(reinterpret_cast<uint8_t *>(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;
|
||||
}
|
||||
@ -583,10 +841,260 @@ namespace advapi32 {
|
||||
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<char>(std::tolower(ch)));
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
static Luid lookupOrGeneratePrivilegeLuid(const std::string &normalizedName) {
|
||||
std::lock_guard<std::mutex> lock(privilegeMapMutex);
|
||||
auto cached = privilegeLuidCache.find(normalizedName);
|
||||
if (cached != privilegeLuidCache.end()) {
|
||||
return cached->second;
|
||||
}
|
||||
static const std::unordered_map<std::string, uint32_t> 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 : "<null>",
|
||||
lpName ? lpName : "<null>",
|
||||
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<const wchar_t *>(lpSystemName) : L"<null>",
|
||||
lpName ? reinterpret_cast<const wchar_t *>(lpName) : L"<null>",
|
||||
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<TokenPrivilegesHeader *>(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<SecurityDescriptor *>(pSecurityDescriptor);
|
||||
descriptor->Revision = static_cast<uint8_t>(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<SecurityDescriptor *>(pSecurityDescriptor);
|
||||
if (descriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
uint16_t control = static_cast<uint16_t>(descriptor->Control & ~(SE_DACL_PRESENT | SE_DACL_DEFAULTED));
|
||||
if (bDaclPresent) {
|
||||
control = static_cast<uint16_t>(control | SE_DACL_PRESENT);
|
||||
if (bDaclDefaulted) {
|
||||
control = static_cast<uint16_t>(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<DWORD>(needed);
|
||||
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
|
||||
return FALSE;
|
||||
}
|
||||
std::memcpy(lpBuffer, name, needed);
|
||||
*pcbBuffer = static_cast<DWORD>(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<DWORD>(needed);
|
||||
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
|
||||
return FALSE;
|
||||
}
|
||||
std::memcpy(lpBuffer, name, needed * sizeof(uint16_t));
|
||||
*pcbBuffer = static_cast<DWORD>(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) {
|
||||
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;
|
||||
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;
|
||||
@ -597,6 +1105,14 @@ static void *resolveByName(const char *name) {
|
||||
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;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
376
dll/kernel32.cpp
376
dll/kernel32.cpp
@ -303,6 +303,34 @@ namespace kernel32 {
|
||||
}
|
||||
}
|
||||
|
||||
struct SemaphoreObject {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
LONG count = 0;
|
||||
LONG maxCount = 0;
|
||||
std::u16string name;
|
||||
int refCount = 1;
|
||||
};
|
||||
|
||||
static std::mutex semaphoreRegistryLock;
|
||||
static std::unordered_map<std::u16string, SemaphoreObject *> namedSemaphores;
|
||||
|
||||
static void releaseSemaphoreObject(SemaphoreObject *obj) {
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(semaphoreRegistryLock);
|
||||
obj->refCount--;
|
||||
if (obj->refCount == 0) {
|
||||
if (!obj->name.empty()) {
|
||||
namedSemaphores.erase(obj->name);
|
||||
}
|
||||
pthread_cond_destroy(&obj->cond);
|
||||
pthread_mutex_destroy(&obj->mutex);
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
|
||||
typedef DWORD (WIN_FUNC *LPTHREAD_START_ROUTINE)(LPVOID);
|
||||
|
||||
struct ThreadObject {
|
||||
@ -310,6 +338,7 @@ namespace kernel32 {
|
||||
bool finished = false;
|
||||
bool joined = false;
|
||||
bool detached = false;
|
||||
bool synthetic = false;
|
||||
DWORD exitCode = 0;
|
||||
int refCount = 1;
|
||||
pthread_mutex_t mutex;
|
||||
@ -332,15 +361,17 @@ namespace kernel32 {
|
||||
delete obj;
|
||||
}
|
||||
|
||||
static ThreadObject *retainThreadObject(ThreadObject *obj);
|
||||
static void releaseThreadObject(ThreadObject *obj);
|
||||
static void *threadTrampoline(void *param);
|
||||
static ThreadObject *ensureCurrentThreadObject();
|
||||
static thread_local ThreadObject *currentThreadObject = nullptr;
|
||||
static constexpr uintptr_t PSEUDO_CURRENT_THREAD_HANDLE_VALUE = 0x100007u;
|
||||
static constexpr uintptr_t PSEUDO_CURRENT_THREAD_HANDLE_VALUE = static_cast<uintptr_t>(-2);
|
||||
|
||||
static ThreadObject *threadObjectFromHandle(HANDLE hThread) {
|
||||
auto raw = reinterpret_cast<uintptr_t>(hThread);
|
||||
if (raw == PSEUDO_CURRENT_THREAD_HANDLE_VALUE || raw == static_cast<uintptr_t>(-2)) {
|
||||
return currentThreadObject;
|
||||
if (raw == PSEUDO_CURRENT_THREAD_HANDLE_VALUE) {
|
||||
return ensureCurrentThreadObject();
|
||||
}
|
||||
if (raw == static_cast<uintptr_t>(-1) || raw == 0) {
|
||||
return nullptr;
|
||||
@ -352,6 +383,26 @@ namespace kernel32 {
|
||||
return reinterpret_cast<ThreadObject *>(data.ptr);
|
||||
}
|
||||
|
||||
static ThreadObject *ensureCurrentThreadObject() {
|
||||
ThreadObject *obj = currentThreadObject;
|
||||
if (obj) {
|
||||
return obj;
|
||||
}
|
||||
obj = new ThreadObject();
|
||||
obj->thread = pthread_self();
|
||||
obj->finished = false;
|
||||
obj->joined = false;
|
||||
obj->detached = true;
|
||||
obj->synthetic = false;
|
||||
obj->exitCode = STILL_ACTIVE;
|
||||
obj->refCount = 0;
|
||||
obj->suspendCount = 0;
|
||||
pthread_mutex_init(&obj->mutex, nullptr);
|
||||
pthread_cond_init(&obj->cond, nullptr);
|
||||
currentThreadObject = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static std::u16string makeMutexName(LPCWSTR name) {
|
||||
if (!name) {
|
||||
return std::u16string();
|
||||
@ -378,6 +429,16 @@ namespace kernel32 {
|
||||
}
|
||||
}
|
||||
|
||||
static ThreadObject *retainThreadObject(ThreadObject *obj) {
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
pthread_mutex_lock(&obj->mutex);
|
||||
obj->refCount++;
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void releaseThreadObject(ThreadObject *obj) {
|
||||
if (!obj) {
|
||||
return;
|
||||
@ -388,14 +449,16 @@ namespace kernel32 {
|
||||
bool finished = false;
|
||||
bool joined = false;
|
||||
bool detached = false;
|
||||
bool synthetic = false;
|
||||
pthread_mutex_lock(&obj->mutex);
|
||||
obj->refCount--;
|
||||
finished = obj->finished;
|
||||
joined = obj->joined;
|
||||
detached = obj->detached;
|
||||
synthetic = obj->synthetic;
|
||||
thread = obj->thread;
|
||||
if (obj->refCount == 0) {
|
||||
if (finished) {
|
||||
if (finished || synthetic) {
|
||||
shouldDelete = true;
|
||||
} else if (!detached) {
|
||||
obj->detached = true;
|
||||
@ -405,14 +468,16 @@ namespace kernel32 {
|
||||
}
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
|
||||
if (shouldDetach) {
|
||||
if (shouldDetach && !synthetic) {
|
||||
pthread_detach(thread);
|
||||
}
|
||||
|
||||
if (shouldDelete) {
|
||||
if (!synthetic) {
|
||||
if (!joined && !detached) {
|
||||
pthread_join(thread, nullptr);
|
||||
}
|
||||
}
|
||||
destroyThreadObject(obj);
|
||||
}
|
||||
}
|
||||
@ -577,6 +642,32 @@ namespace kernel32 {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WIN_FUNC IsWow64Process(HANDLE hProcess, PBOOL Wow64Process) {
|
||||
DEBUG_LOG("IsWow64Process(%p, %p)\n", hProcess, Wow64Process);
|
||||
if (!Wow64Process) {
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(hProcess);
|
||||
bool isPseudoHandle = rawHandle == static_cast<uintptr_t>(-1);
|
||||
if (!isPseudoHandle) {
|
||||
if (!hProcess) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
auto data = handles::dataFromHandle(hProcess, false);
|
||||
if (data.type != handles::TYPE_PROCESS || data.ptr == nullptr) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
*Wow64Process = FALSE;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void WIN_FUNC RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR *lpArguments) {
|
||||
DEBUG_LOG("RaiseException(0x%x, 0x%x, %u, %p)\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
|
||||
(void)lpArguments;
|
||||
@ -991,6 +1082,22 @@ namespace kernel32 {
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
case handles::TYPE_SEMAPHORE: {
|
||||
auto *obj = reinterpret_cast<SemaphoreObject *>(data.ptr);
|
||||
if (dwMilliseconds != 0xffffffff) {
|
||||
DEBUG_LOG("WaitForSingleObject: timeout for semaphore not supported\n");
|
||||
wibo::lastError = ERROR_NOT_SUPPORTED;
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
pthread_mutex_lock(&obj->mutex);
|
||||
while (obj->count == 0) {
|
||||
pthread_cond_wait(&obj->cond, &obj->mutex);
|
||||
}
|
||||
obj->count--;
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
case handles::TYPE_MUTEX: {
|
||||
auto *obj = reinterpret_cast<MutexObject *>(data.ptr);
|
||||
if (dwMilliseconds != 0xffffffff) {
|
||||
@ -1372,27 +1479,123 @@ namespace kernel32 {
|
||||
unsigned int bInheritHandle, unsigned int dwOptions) {
|
||||
DEBUG_LOG("DuplicateHandle(%p, %p, %p, %p, %x, %d, %x)\n", hSourceProcessHandle, hSourceHandle,
|
||||
hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
|
||||
assert(hSourceProcessHandle == (void *)0xFFFFFFFF); // current process
|
||||
assert(hTargetProcessHandle == (void *)0xFFFFFFFF); // current process
|
||||
(void)dwDesiredAccess;
|
||||
(void)bInheritHandle;
|
||||
(void)dwOptions;
|
||||
if (!lpTargetHandle) {
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto validateProcessHandle = [&](void *handle) -> bool {
|
||||
uintptr_t raw = reinterpret_cast<uintptr_t>(handle);
|
||||
if (raw == static_cast<uintptr_t>(-1)) {
|
||||
return true;
|
||||
}
|
||||
auto data = handles::dataFromHandle(handle, false);
|
||||
if (data.type != handles::TYPE_PROCESS || data.ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
auto *proc = reinterpret_cast<processes::Process *>(data.ptr);
|
||||
return proc && proc->pid == getpid();
|
||||
};
|
||||
|
||||
if (!validateProcessHandle(hSourceProcessHandle) || !validateProcessHandle(hTargetProcessHandle)) {
|
||||
DEBUG_LOG("DuplicateHandle: unsupported process handle combination (source=%p target=%p)\n",
|
||||
hSourceProcessHandle, hTargetProcessHandle);
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto file = files::fileHandleFromHandle(hSourceHandle);
|
||||
if (file && (file->fp == stdin || file->fp == stdout || file->fp == stderr)) {
|
||||
// we never close standard handles so they are fine to duplicate
|
||||
void *handle = files::duplicateFileHandle(file, false);
|
||||
DEBUG_LOG("-> %p\n", handle);
|
||||
DEBUG_LOG("DuplicateHandle: duplicated std handle -> %p\n", handle);
|
||||
*lpTargetHandle = handle;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
// other handles are more problematic; fail for now
|
||||
printf("failed to duplicate handle\n");
|
||||
assert(0);
|
||||
|
||||
uintptr_t sourceHandleRaw = reinterpret_cast<uintptr_t>(hSourceHandle);
|
||||
if (sourceHandleRaw == static_cast<uintptr_t>(-1)) {
|
||||
void *handle = processes::allocProcessHandle(getpid());
|
||||
processes::Process *proc = processes::processFromHandle(handle, false);
|
||||
if (proc) {
|
||||
proc->exitCode = STILL_ACTIVE;
|
||||
proc->forcedExitCode = STILL_ACTIVE;
|
||||
proc->terminationRequested = false;
|
||||
}
|
||||
DEBUG_LOG("DuplicateHandle: created process handle for current process -> %p\n", handle);
|
||||
*lpTargetHandle = handle;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
if (sourceHandleRaw == PSEUDO_CURRENT_THREAD_HANDLE_VALUE) {
|
||||
ThreadObject *obj = ensureCurrentThreadObject();
|
||||
if (obj) {
|
||||
retainThreadObject(obj);
|
||||
void *handle = handles::allocDataHandle({handles::TYPE_THREAD, obj, 0});
|
||||
DEBUG_LOG("DuplicateHandle: duplicated pseudo current thread -> %p\n", handle);
|
||||
*lpTargetHandle = handle;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
ThreadObject *syntheticObj = new ThreadObject();
|
||||
syntheticObj->thread = pthread_self();
|
||||
syntheticObj->finished = false;
|
||||
syntheticObj->joined = false;
|
||||
syntheticObj->detached = true;
|
||||
syntheticObj->synthetic = true;
|
||||
syntheticObj->exitCode = 0;
|
||||
syntheticObj->refCount = 1;
|
||||
syntheticObj->suspendCount = 0;
|
||||
pthread_mutex_init(&syntheticObj->mutex, nullptr);
|
||||
pthread_cond_init(&syntheticObj->cond, nullptr);
|
||||
void *handle = handles::allocDataHandle({handles::TYPE_THREAD, syntheticObj, 0});
|
||||
DEBUG_LOG("DuplicateHandle: created synthetic thread handle -> %p\n", handle);
|
||||
*lpTargetHandle = handle;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
handles::Data data = handles::dataFromHandle(hSourceHandle, false);
|
||||
if (data.type == handles::TYPE_PROCESS && data.ptr) {
|
||||
auto *original = reinterpret_cast<processes::Process *>(data.ptr);
|
||||
void *handle = processes::allocProcessHandle(original->pid);
|
||||
auto *copy = processes::processFromHandle(handle, false);
|
||||
if (copy) {
|
||||
*copy = *original;
|
||||
}
|
||||
DEBUG_LOG("DuplicateHandle: duplicated process handle -> %p\n", handle);
|
||||
*lpTargetHandle = handle;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
if (data.type == handles::TYPE_THREAD && data.ptr) {
|
||||
auto *threadObj = reinterpret_cast<ThreadObject *>(data.ptr);
|
||||
if (!retainThreadObject(threadObj)) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
void *handle = handles::allocDataHandle({handles::TYPE_THREAD, threadObj, 0});
|
||||
DEBUG_LOG("DuplicateHandle: duplicated thread handle -> %p\n", handle);
|
||||
*lpTargetHandle = handle;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 1;
|
||||
}
|
||||
DEBUG_LOG("DuplicateHandle: unsupported handle type for %p\n", hSourceHandle);
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL WIN_FUNC CloseHandle(HANDLE hObject) {
|
||||
DEBUG_LOG("CloseHandle(%p)\n", hObject);
|
||||
auto data = handles::dataFromHandle(hObject, true);
|
||||
if (data.type == handles::TYPE_UNUSED || data.ptr == nullptr) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
bool success = true;
|
||||
if (data.type == handles::TYPE_FILE) {
|
||||
auto file = reinterpret_cast<files::FileHandle *>(data.ptr);
|
||||
if (file) {
|
||||
@ -1401,15 +1604,24 @@ namespace kernel32 {
|
||||
fclose(file->fp);
|
||||
}
|
||||
delete file;
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
} else if (data.type == handles::TYPE_MAPPED) {
|
||||
auto *mapping = reinterpret_cast<MappingObject *>(data.ptr);
|
||||
if (mapping) {
|
||||
mapping->closed = true;
|
||||
tryReleaseMapping(mapping);
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
} else if (data.type == handles::TYPE_PROCESS) {
|
||||
delete (processes::Process *)data.ptr;
|
||||
auto *proc = reinterpret_cast<processes::Process *>(data.ptr);
|
||||
if (proc) {
|
||||
delete proc;
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
} else if (data.type == handles::TYPE_TOKEN) {
|
||||
advapi32::releaseToken(data.ptr);
|
||||
} else if (data.type == handles::TYPE_MUTEX) {
|
||||
@ -1418,7 +1630,16 @@ namespace kernel32 {
|
||||
releaseEventObject(reinterpret_cast<EventObject *>(data.ptr));
|
||||
} else if (data.type == handles::TYPE_THREAD) {
|
||||
releaseThreadObject(reinterpret_cast<ThreadObject *>(data.ptr));
|
||||
} else if (data.type == handles::TYPE_SEMAPHORE) {
|
||||
releaseSemaphoreObject(reinterpret_cast<SemaphoreObject *>(data.ptr));
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
if (!success) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -4895,8 +5116,11 @@ namespace kernel32 {
|
||||
}
|
||||
|
||||
HANDLE WIN_FUNC GetCurrentThread() {
|
||||
DEBUG_LOG("STUB: GetCurrentThread\n");
|
||||
return reinterpret_cast<HANDLE>(PSEUDO_CURRENT_THREAD_HANDLE_VALUE);
|
||||
ThreadObject *obj = ensureCurrentThreadObject();
|
||||
(void)obj;
|
||||
HANDLE pseudoHandle = reinterpret_cast<HANDLE>(PSEUDO_CURRENT_THREAD_HANDLE_VALUE);
|
||||
DEBUG_LOG("GetCurrentThread() -> %p\n", pseudoHandle);
|
||||
return pseudoHandle;
|
||||
}
|
||||
|
||||
DWORD_PTR WIN_FUNC SetThreadAffinityMask(HANDLE hThread, DWORD_PTR dwThreadAffinityMask) {
|
||||
@ -4908,7 +5132,6 @@ namespace kernel32 {
|
||||
|
||||
uintptr_t rawThreadHandle = reinterpret_cast<uintptr_t>(hThread);
|
||||
bool isPseudoHandle = rawThreadHandle == PSEUDO_CURRENT_THREAD_HANDLE_VALUE ||
|
||||
rawThreadHandle == static_cast<uintptr_t>(-2) ||
|
||||
rawThreadHandle == 0 ||
|
||||
rawThreadHandle == static_cast<uintptr_t>(-1);
|
||||
if (!isPseudoHandle) {
|
||||
@ -5060,25 +5283,11 @@ namespace kernel32 {
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
if (reinterpret_cast<uintptr_t>(hThread) == PSEUDO_CURRENT_THREAD_HANDLE_VALUE) {
|
||||
ThreadObject *obj = currentThreadObject;
|
||||
if (obj) {
|
||||
pthread_mutex_lock(&obj->mutex);
|
||||
DWORD code = obj->finished ? obj->exitCode : STILL_ACTIVE;
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
*lpExitCode = code;
|
||||
} else {
|
||||
*lpExitCode = STILL_ACTIVE;
|
||||
}
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return TRUE;
|
||||
}
|
||||
auto data = handles::dataFromHandle(hThread, false);
|
||||
if (data.type != handles::TYPE_THREAD) {
|
||||
ThreadObject *obj = threadObjectFromHandle(hThread);
|
||||
if (!obj) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
ThreadObject *obj = reinterpret_cast<ThreadObject *>(data.ptr);
|
||||
pthread_mutex_lock(&obj->mutex);
|
||||
DWORD code = obj->finished ? obj->exitCode : STILL_ACTIVE;
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
@ -5222,6 +5431,100 @@ namespace kernel32 {
|
||||
return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName ? reinterpret_cast<LPCWSTR>(wideName.data()) : nullptr);
|
||||
}
|
||||
|
||||
HANDLE WIN_FUNC CreateSemaphoreW(void *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
|
||||
LPCWSTR lpName) {
|
||||
DEBUG_LOG("CreateSemaphoreW(%p, %ld, %ld, %ls)\n", lpSemaphoreAttributes, static_cast<long>(lInitialCount),
|
||||
static_cast<long>(lMaximumCount), lpName ? reinterpret_cast<const wchar_t *>(lpName) : L"<null>");
|
||||
(void)lpSemaphoreAttributes;
|
||||
SemaphoreObject *obj = nullptr;
|
||||
bool alreadyExists = false;
|
||||
std::u16string name = makeMutexName(lpName);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(semaphoreRegistryLock);
|
||||
if (!name.empty()) {
|
||||
auto it = namedSemaphores.find(name);
|
||||
if (it != namedSemaphores.end()) {
|
||||
obj = it->second;
|
||||
obj->refCount++;
|
||||
alreadyExists = true;
|
||||
}
|
||||
}
|
||||
if (!obj) {
|
||||
if (lMaximumCount <= 0 || lInitialCount < 0 || lInitialCount > lMaximumCount) {
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return nullptr;
|
||||
}
|
||||
obj = new SemaphoreObject();
|
||||
pthread_mutex_init(&obj->mutex, nullptr);
|
||||
pthread_cond_init(&obj->cond, nullptr);
|
||||
obj->count = lInitialCount;
|
||||
obj->maxCount = lMaximumCount;
|
||||
obj->name = name;
|
||||
obj->refCount = 1;
|
||||
if (!name.empty()) {
|
||||
namedSemaphores[name] = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
void *handle = handles::allocDataHandle({handles::TYPE_SEMAPHORE, obj, 0});
|
||||
wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS;
|
||||
return handle;
|
||||
}
|
||||
|
||||
HANDLE WIN_FUNC CreateSemaphoreA(void *lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
|
||||
LPCSTR lpName) {
|
||||
DEBUG_LOG("CreateSemaphoreA -> ");
|
||||
std::vector<uint16_t> wideName;
|
||||
if (lpName) {
|
||||
wideName = stringToWideString(lpName);
|
||||
}
|
||||
return CreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount,
|
||||
lpName ? reinterpret_cast<LPCWSTR>(wideName.data()) : nullptr);
|
||||
}
|
||||
|
||||
BOOL WIN_FUNC ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, PLONG lpPreviousCount) {
|
||||
DEBUG_LOG("ReleaseSemaphore(%p, %ld, %p)\n", hSemaphore, static_cast<long>(lReleaseCount), lpPreviousCount);
|
||||
if (lReleaseCount <= 0) {
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
auto data = handles::dataFromHandle(hSemaphore, false);
|
||||
if (data.type != handles::TYPE_SEMAPHORE || data.ptr == nullptr) {
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
return FALSE;
|
||||
}
|
||||
auto *obj = reinterpret_cast<SemaphoreObject *>(data.ptr);
|
||||
pthread_mutex_lock(&obj->mutex);
|
||||
if (lpPreviousCount) {
|
||||
*lpPreviousCount = obj->count;
|
||||
}
|
||||
if (lReleaseCount > obj->maxCount - obj->count) {
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||
return FALSE;
|
||||
}
|
||||
obj->count += lReleaseCount;
|
||||
pthread_mutex_unlock(&obj->mutex);
|
||||
pthread_cond_broadcast(&obj->cond);
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL WIN_FUNC SetThreadPriority(HANDLE hThread, int nPriority) {
|
||||
DEBUG_LOG("STUB: SetThreadPriority(%p, %d)\n", hThread, nPriority);
|
||||
(void) hThread;
|
||||
(void) nPriority;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int WIN_FUNC GetThreadPriority(HANDLE hThread) {
|
||||
DEBUG_LOG("STUB: GetThreadPriority(%p)\n", hThread);
|
||||
(void) hThread;
|
||||
wibo::lastError = ERROR_SUCCESS;
|
||||
return 0; // THREAD_PRIORITY_NORMAL
|
||||
}
|
||||
|
||||
BOOL WIN_FUNC SetEvent(HANDLE hEvent) {
|
||||
DEBUG_LOG("SetEvent(%p)\n", hEvent);
|
||||
auto data = handles::dataFromHandle(hEvent, false);
|
||||
@ -5271,8 +5574,7 @@ namespace kernel32 {
|
||||
}
|
||||
|
||||
bool isPseudoCurrentThread = reinterpret_cast<uintptr_t>(hThread) == PSEUDO_CURRENT_THREAD_HANDLE_VALUE ||
|
||||
hThread == (HANDLE)0xFFFFFFFE || hThread == (HANDLE)0 ||
|
||||
hThread == (HANDLE)0xFFFFFFFF;
|
||||
hThread == (HANDLE)0 || hThread == (HANDLE)0xFFFFFFFF;
|
||||
if (!isPseudoCurrentThread) {
|
||||
DEBUG_LOG("GetThreadTimes: unsupported handle %p\n", hThread);
|
||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
||||
@ -6340,6 +6642,7 @@ static void *resolveByName(const char *name) {
|
||||
if (strcmp(name, "IsBadWritePtr") == 0) return (void *) kernel32::IsBadWritePtr;
|
||||
if (strcmp(name, "Wow64DisableWow64FsRedirection") == 0) return (void *) kernel32::Wow64DisableWow64FsRedirection;
|
||||
if (strcmp(name, "Wow64RevertWow64FsRedirection") == 0) return (void *) kernel32::Wow64RevertWow64FsRedirection;
|
||||
if (strcmp(name, "IsWow64Process") == 0) return (void *) kernel32::IsWow64Process;
|
||||
if (strcmp(name, "RaiseException") == 0) return (void *) kernel32::RaiseException;
|
||||
if (strcmp(name, "AddVectoredExceptionHandler") == 0) return (void *) kernel32::AddVectoredExceptionHandler;
|
||||
|
||||
@ -6404,11 +6707,16 @@ static void *resolveByName(const char *name) {
|
||||
if (strcmp(name, "CreateMutexW") == 0) return (void *) kernel32::CreateMutexW;
|
||||
if (strcmp(name, "CreateEventA") == 0) return (void *) kernel32::CreateEventA;
|
||||
if (strcmp(name, "CreateEventW") == 0) return (void *) kernel32::CreateEventW;
|
||||
if (strcmp(name, "CreateSemaphoreA") == 0) return (void *) kernel32::CreateSemaphoreA;
|
||||
if (strcmp(name, "CreateSemaphoreW") == 0) return (void *) kernel32::CreateSemaphoreW;
|
||||
if (strcmp(name, "SetEvent") == 0) return (void *) kernel32::SetEvent;
|
||||
if (strcmp(name, "ResetEvent") == 0) return (void *) kernel32::ResetEvent;
|
||||
if (strcmp(name, "ReleaseMutex") == 0) return (void *) kernel32::ReleaseMutex;
|
||||
if (strcmp(name, "ReleaseSemaphore") == 0) return (void *) kernel32::ReleaseSemaphore;
|
||||
if (strcmp(name, "SetThreadAffinityMask") == 0) return (void *) kernel32::SetThreadAffinityMask;
|
||||
if (strcmp(name, "ResumeThread") == 0) return (void *) kernel32::ResumeThread;
|
||||
if (strcmp(name, "SetThreadPriority") == 0) return (void *) kernel32::SetThreadPriority;
|
||||
if (strcmp(name, "GetThreadPriority") == 0) return (void *) kernel32::GetThreadPriority;
|
||||
|
||||
// winbase.h
|
||||
if (strcmp(name, "GlobalAlloc") == 0) return (void *) kernel32::GlobalAlloc;
|
||||
|
||||
@ -13,8 +13,10 @@ namespace handles {
|
||||
TYPE_TOKEN,
|
||||
TYPE_MUTEX,
|
||||
TYPE_EVENT,
|
||||
TYPE_SEMAPHORE,
|
||||
TYPE_THREAD,
|
||||
TYPE_HEAP
|
||||
TYPE_HEAP,
|
||||
TYPE_REGISTRY_KEY
|
||||
};
|
||||
|
||||
struct Data {
|
||||
|
||||
@ -268,7 +268,8 @@ std::vector<std::filesystem::path> collectSearchDirectories(ModuleRegistry ®,
|
||||
addDirectory(std::filesystem::current_path());
|
||||
}
|
||||
|
||||
if (const char *envPath = std::getenv("WIBO_PATH")) {
|
||||
const auto addFromEnv = [&](const char *envVar) {
|
||||
if (const char *envPath = std::getenv(envVar)) {
|
||||
std::string pathList = envPath;
|
||||
size_t start = 0;
|
||||
while (start <= pathList.size()) {
|
||||
@ -279,14 +280,12 @@ std::vector<std::filesystem::path> collectSearchDirectories(ModuleRegistry ®,
|
||||
if (end > start) {
|
||||
auto piece = pathList.substr(start, end - start);
|
||||
if (!piece.empty()) {
|
||||
std::filesystem::path candidate(piece);
|
||||
if (piece.find(':') != std::string::npos || piece.find('\\') != std::string::npos) {
|
||||
auto converted = files::pathFromWindows(piece.c_str());
|
||||
if (!converted.empty()) {
|
||||
candidate = converted;
|
||||
}
|
||||
}
|
||||
auto candidate = files::pathFromWindows(piece.c_str());
|
||||
if (!candidate.empty()) {
|
||||
addDirectory(candidate);
|
||||
} else {
|
||||
addDirectory(std::filesystem::path(piece));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (end == pathList.size()) {
|
||||
@ -295,6 +294,10 @@ std::vector<std::filesystem::path> collectSearchDirectories(ModuleRegistry ®,
|
||||
start = end + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addFromEnv("WIBO_PATH");
|
||||
addFromEnv("WINEPATH"); // Wine compatibility
|
||||
|
||||
return dirs;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user