Split advapi32 into separate files (part 2) & more impls for ee-gcc/cygwin

This commit is contained in:
Luke Street 2025-10-02 09:05:27 -06:00
parent 79e1dbf523
commit 3249ebf4bf
24 changed files with 1500 additions and 581 deletions

View File

@ -33,8 +33,12 @@ FetchContent_MakeAvailable(mimalloc)
include_directories(.)
add_executable(wibo
dll/advapi32.cpp
dll/advapi32/winreg.cpp
dll/advapi32/internal.cpp
dll/advapi32/processthreadsapi.cpp
dll/advapi32/securitybaseapi.cpp
dll/advapi32/winbase.cpp
dll/advapi32/wincrypt.cpp
dll/advapi32/winreg.cpp
dll/bcrypt.cpp
dll/crt.cpp
dll/kernel32.cpp

View File

@ -42,6 +42,7 @@ using HGLOBAL = HANDLE;
using HLOCAL = HANDLE;
using HRSRC = HANDLE;
using LPHANDLE = HANDLE *;
using PHANDLE = HANDLE *;
using PVOID = void *;
using LPVOID = void *;
using LPCVOID = const void *;
@ -56,6 +57,12 @@ using LONG = int32_t;
using PLONG = LONG *;
using ULONG = uint32_t;
using PULONG = ULONG *;
struct LUID {
DWORD LowPart;
LONG HighPart;
};
using PLUID = LUID *;
using LPLUID = LUID *;
using LARGE_INTEGER = int64_t;
using PLARGE_INTEGER = LARGE_INTEGER *;
using ULONG_PTR = uintptr_t;
@ -84,6 +91,7 @@ using BOOLEAN = unsigned char;
using UINT = unsigned int;
using HKEY = void *;
using PHKEY = HKEY *;
using PSID = void *;
using REGSAM = DWORD;
using LSTATUS = LONG;
using LCID = DWORD;

View File

@ -1,540 +1,106 @@
#include "common.h"
#include "advapi32/winreg.h"
#include "advapi32/processthreadsapi.h"
#include "advapi32/securitybaseapi.h"
#include "advapi32/winbase.h"
#include "advapi32/wincrypt.h"
#include "errors.h"
#include "handles.h"
#include "strutil.h"
#include "advapi32/winreg.h"
#include "common.h"
#include <algorithm>
#include <cctype>
#include <cstring>
#include <mutex>
#include <string>
#include <unordered_map>
namespace {
struct Luid;
static std::mutex privilegeMapMutex;
static std::unordered_map<std::string, Luid> privilegeLuidCache;
constexpr DWORD SECURITY_DESCRIPTOR_REVISION = 1;
constexpr uint16_t SE_DACL_PRESENT = 0x0004;
constexpr uint16_t SE_DACL_DEFAULTED = 0x0008;
void *resolveByName(const char *name) {
// processthreadsapi.h
if (strcmp(name, "OpenProcessToken") == 0)
return (void *)advapi32::OpenProcessToken;
struct SecurityDescriptor {
uint8_t Revision = 0;
uint8_t Sbz1 = 0;
uint16_t Control = 0;
void *Owner = nullptr;
void *Group = nullptr;
void *Sacl = nullptr;
void *Dacl = nullptr;
};
// securitybaseapi.h
if (strcmp(name, "InitializeAcl") == 0)
return (void *)advapi32::InitializeAcl;
if (strcmp(name, "AddAccessAllowedAce") == 0)
return (void *)advapi32::AddAccessAllowedAce;
if (strcmp(name, "FindFirstFreeAce") == 0)
return (void *)advapi32::FindFirstFreeAce;
if (strcmp(name, "GetSidIdentifierAuthority") == 0)
return (void *)advapi32::GetSidIdentifierAuthority;
if (strcmp(name, "GetSidSubAuthorityCount") == 0)
return (void *)advapi32::GetSidSubAuthorityCount;
if (strcmp(name, "GetSidSubAuthority") == 0)
return (void *)advapi32::GetSidSubAuthority;
if (strcmp(name, "ImpersonateLoggedOnUser") == 0)
return (void *)advapi32::ImpersonateLoggedOnUser;
if (strcmp(name, "DuplicateTokenEx") == 0)
return (void *)advapi32::DuplicateTokenEx;
if (strcmp(name, "CopySid") == 0)
return (void *)advapi32::CopySid;
if (strcmp(name, "GetSecurityDescriptorDacl") == 0)
return (void *)advapi32::GetSecurityDescriptorDacl;
if (strcmp(name, "SetKernelObjectSecurity") == 0)
return (void *)advapi32::SetKernelObjectSecurity;
if (strcmp(name, "InitializeSecurityDescriptor") == 0)
return (void *)advapi32::InitializeSecurityDescriptor;
if (strcmp(name, "SetSecurityDescriptorDacl") == 0)
return (void *)advapi32::SetSecurityDescriptorDacl;
if (strcmp(name, "GetTokenInformation") == 0)
return (void *)advapi32::GetTokenInformation;
if (strcmp(name, "AdjustTokenPrivileges") == 0)
return (void *)advapi32::AdjustTokenPrivileges;
if (strcmp(name, "SetTokenInformation") == 0)
return (void *)advapi32::SetTokenInformation;
struct TokenObject {
HANDLE processHandle = nullptr;
DWORD desiredAccess = 0;
};
// winbase.h
if (strcmp(name, "LookupAccountSidW") == 0)
return (void *)advapi32::LookupAccountSidW;
if (strcmp(name, "LookupPrivilegeValueA") == 0)
return (void *)advapi32::LookupPrivilegeValueA;
if (strcmp(name, "LookupPrivilegeValueW") == 0)
return (void *)advapi32::LookupPrivilegeValueW;
if (strcmp(name, "GetUserNameA") == 0)
return (void *)advapi32::GetUserNameA;
if (strcmp(name, "GetUserNameW") == 0)
return (void *)advapi32::GetUserNameW;
struct SidIdentifierAuthority {
uint8_t Value[6] = {0};
};
struct Sid {
uint8_t Revision = 1;
uint8_t SubAuthorityCount = 0;
SidIdentifierAuthority IdentifierAuthority = {};
uint32_t SubAuthority[1] = {0};
};
struct SidAndAttributes {
Sid *SidPtr = nullptr;
DWORD Attributes = 0;
};
struct TokenUserData {
SidAndAttributes User;
};
enum SID_NAME_USE {
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer,
SidTypeLabel
};
bool isLocalSystemSid(const Sid *sid) {
if (!sid) {
return false;
}
static const uint8_t ntAuthority[6] = {0, 0, 0, 0, 0, 5};
if (sid->Revision != 1 || sid->SubAuthorityCount != 1) {
return false;
}
for (size_t i = 0; i < 6; ++i) {
if (sid->IdentifierAuthority.Value[i] != ntAuthority[i]) {
return false;
}
}
return sid->SubAuthority[0] == 18; // SECURITY_LOCAL_SYSTEM_RID
}
struct Luid {
uint32_t LowPart = 0;
int32_t HighPart = 0;
};
struct LuidAndAttributes {
Luid value;
DWORD Attributes = 0;
};
struct TokenStatisticsData {
Luid tokenId;
Luid authenticationId;
int64_t expirationTime = 0;
uint32_t tokenType = 0;
uint32_t impersonationLevel = 0;
uint32_t dynamicCharged = 0;
uint32_t dynamicAvailable = 0;
uint32_t groupCount = 0;
uint32_t privilegeCount = 0;
Luid modifiedId;
};
}
namespace advapi32 {
BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle) {
DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle);
if (!TokenHandle) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *token = new TokenObject;
token->processHandle = ProcessHandle;
token->desiredAccess = DesiredAccess;
handles::Data data;
data.type = handles::TYPE_TOKEN;
data.ptr = token;
data.size = 0;
*TokenHandle = handles::allocDataHandle(data);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
void releaseToken(void *tokenPtr) {
delete reinterpret_cast<TokenObject *>(tokenPtr);
}
BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, unsigned int TokenInformationClass, void *TokenInformation, unsigned int TokenInformationLength, unsigned int *ReturnLength) {
DEBUG_LOG("GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation,
TokenInformationLength, ReturnLength);
if (!ReturnLength) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto data = handles::dataFromHandle(TokenHandle, false);
if (data.type != handles::TYPE_TOKEN) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
constexpr unsigned int TokenUserClass = 1; // TokenUser
constexpr unsigned int TokenStatisticsClass = 10; // TokenStatistics
constexpr unsigned int TokenElevationClass = 20; // TokenElevation
constexpr unsigned int TokenPrimaryGroupClass = 5; // TokenPrimaryGroup
if (TokenInformationClass == TokenUserClass) {
constexpr size_t sidSize = sizeof(Sid);
constexpr size_t tokenUserSize = sizeof(TokenUserData);
const auto required = static_cast<unsigned int>(tokenUserSize + sidSize);
*ReturnLength = required;
if (!TokenInformation || TokenInformationLength < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
auto *tokenUser = reinterpret_cast<TokenUserData *>(TokenInformation);
auto *sid = reinterpret_cast<Sid *>(reinterpret_cast<uint8_t *>(TokenInformation) + tokenUserSize);
SidIdentifierAuthority ntAuthority = {{0, 0, 0, 0, 0, 5}};
sid->Revision = 1;
sid->SubAuthorityCount = 1;
sid->IdentifierAuthority = ntAuthority;
sid->SubAuthority[0] = 18; // SECURITY_LOCAL_SYSTEM_RID
tokenUser->User.SidPtr = sid;
tokenUser->User.Attributes = 0;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (TokenInformationClass == TokenStatisticsClass) {
const unsigned int required = sizeof(TokenStatisticsData);
*ReturnLength = required;
if (!TokenInformation || TokenInformationLength < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
auto *stats = reinterpret_cast<TokenStatisticsData *>(TokenInformation);
*stats = {};
stats->tokenType = 1; // TokenPrimary
stats->impersonationLevel = 0; // SecurityAnonymous
stats->tokenId.LowPart = 1;
stats->authenticationId.LowPart = 1;
stats->modifiedId.LowPart = 1;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (TokenInformationClass == TokenElevationClass) {
const unsigned int required = sizeof(DWORD);
*ReturnLength = required;
if (!TokenInformation || TokenInformationLength < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
*reinterpret_cast<DWORD *>(TokenInformation) = 0; // not elevated
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (TokenInformationClass == TokenPrimaryGroupClass) {
struct TokenPrimaryGroupStub {
Sid *PrimaryGroup;
};
constexpr size_t sidSize = sizeof(Sid);
constexpr size_t headerSize = sizeof(TokenPrimaryGroupStub);
const unsigned int required = static_cast<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;
}
BOOL WIN_FUNC LookupAccountSidW(const uint16_t *lpSystemName, const void *sidPointer, uint16_t *Name,
unsigned long *cchName, uint16_t *ReferencedDomainName,
unsigned long *cchReferencedDomainName, SID_NAME_USE *peUse) {
std::string systemName = lpSystemName ? wideStringToString(lpSystemName) : std::string("(null)");
DEBUG_LOG("LookupAccountSidW(%s, %p, %p, %p, %p, %p, %p)\n", systemName.c_str(), sidPointer, Name, cchName,
ReferencedDomainName, cchReferencedDomainName, peUse);
(void) lpSystemName; // Only local lookup supported
if (!sidPointer || !cchName || !cchReferencedDomainName || !peUse) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *sid = reinterpret_cast<const Sid *>(sidPointer);
if (!isLocalSystemSid(sid)) {
wibo::lastError = ERROR_NONE_MAPPED;
return FALSE;
}
static constexpr uint16_t accountName[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'};
static constexpr uint16_t domainName[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'};
unsigned long requiredAccount = wstrlen(accountName) + 1;
unsigned long requiredDomain = wstrlen(domainName) + 1;
if (!Name || *cchName < requiredAccount || !ReferencedDomainName || *cchReferencedDomainName < requiredDomain) {
*cchName = requiredAccount;
*cchReferencedDomainName = requiredDomain;
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
std::copy_n(accountName, requiredAccount, Name);
std::copy_n(domainName, requiredDomain, ReferencedDomainName);
*peUse = SidTypeWellKnownGroup;
*cchName = requiredAccount - 1;
*cchReferencedDomainName = requiredDomain - 1;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
static Luid generateDeterministicLuid(const std::string &normalizedName) {
uint32_t hash = 2166136261u;
for (unsigned char ch : normalizedName) {
hash ^= ch;
hash *= 16777619u;
}
if (hash == 0) {
hash = 1;
}
Luid result{};
result.LowPart = hash;
result.HighPart = 0;
return result;
}
static std::string normalizePrivilegeName(const std::string &name) {
std::string normalized;
normalized.reserve(name.size());
for (unsigned char ch : name) {
if (ch == '\r' || ch == '\n' || ch == '\t') {
continue;
}
normalized.push_back(static_cast<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) {
// winreg.h
if (strcmp(name, "RegOpenKeyExA") == 0) return (void *) advapi32::RegOpenKeyExA;
if (strcmp(name, "RegOpenKeyExW") == 0) return (void *) advapi32::RegOpenKeyExW;
if (strcmp(name, "RegCloseKey") == 0) return (void *) advapi32::RegCloseKey;
// wincrypt.h
if (strcmp(name, "CryptReleaseContext") == 0) return (void*) advapi32::CryptReleaseContext;
if (strcmp(name, "CryptAcquireContextW") == 0) return (void*) advapi32::CryptAcquireContextW;
if (strcmp(name, "CryptGenRandom") == 0) return (void*) advapi32::CryptGenRandom;
if (strcmp(name, "CryptCreateHash") == 0) return (void*) advapi32::CryptCreateHash;
if (strcmp(name, "CryptHashData") == 0) return (void*) advapi32::CryptHashData;
if (strcmp(name, "CryptGetHashParam") == 0) return (void*) advapi32::CryptGetHashParam;
if (strcmp(name, "CryptDestroyHash") == 0) return (void*) advapi32::CryptDestroyHash;
if (strcmp(name, "OpenProcessToken") == 0) return (void*) advapi32::OpenProcessToken;
if (strcmp(name, "GetTokenInformation") == 0) return (void*) advapi32::GetTokenInformation;
if (strcmp(name, "LookupAccountSidW") == 0) return (void*) advapi32::LookupAccountSidW;
if (strcmp(name, "InitializeSecurityDescriptor") == 0) return (void*) advapi32::InitializeSecurityDescriptor;
if (strcmp(name, "SetSecurityDescriptorDacl") == 0) return (void*) advapi32::SetSecurityDescriptorDacl;
if (strcmp(name, "LookupPrivilegeValueA") == 0) return (void*) advapi32::LookupPrivilegeValueA;
if (strcmp(name, "LookupPrivilegeValueW") == 0) return (void*) advapi32::LookupPrivilegeValueW;
if (strcmp(name, "AdjustTokenPrivileges") == 0) return (void*) advapi32::AdjustTokenPrivileges;
if (strcmp(name, "GetUserNameA") == 0) return (void*) advapi32::GetUserNameA;
if (strcmp(name, "GetUserNameW") == 0) return (void*) advapi32::GetUserNameW;
if (strcmp(name, "SetTokenInformation") == 0) return (void*) advapi32::SetTokenInformation;
if (strcmp(name, "CryptReleaseContext") == 0)
return (void *)advapi32::CryptReleaseContext;
if (strcmp(name, "CryptAcquireContextW") == 0)
return (void *)advapi32::CryptAcquireContextW;
if (strcmp(name, "CryptGenRandom") == 0)
return (void *)advapi32::CryptGenRandom;
if (strcmp(name, "CryptCreateHash") == 0)
return (void *)advapi32::CryptCreateHash;
if (strcmp(name, "CryptHashData") == 0)
return (void *)advapi32::CryptHashData;
if (strcmp(name, "CryptGetHashParam") == 0)
return (void *)advapi32::CryptGetHashParam;
if (strcmp(name, "CryptDestroyHash") == 0)
return (void *)advapi32::CryptDestroyHash;
// winreg.h
if (strcmp(name, "RegCreateKeyExA") == 0)
return (void *)advapi32::RegCreateKeyExA;
if (strcmp(name, "RegCreateKeyExW") == 0)
return (void *)advapi32::RegCreateKeyExW;
if (strcmp(name, "RegOpenKeyExA") == 0)
return (void *)advapi32::RegOpenKeyExA;
if (strcmp(name, "RegOpenKeyExW") == 0)
return (void *)advapi32::RegOpenKeyExW;
if (strcmp(name, "RegQueryValueExA") == 0)
return (void *)advapi32::RegQueryValueExA;
if (strcmp(name, "RegQueryValueExW") == 0)
return (void *)advapi32::RegQueryValueExW;
if (strcmp(name, "RegEnumKeyExA") == 0)
return (void *)advapi32::RegEnumKeyExA;
if (strcmp(name, "RegEnumKeyExW") == 0)
return (void *)advapi32::RegEnumKeyExW;
if (strcmp(name, "RegCloseKey") == 0)
return (void *)advapi32::RegCloseKey;
return nullptr;
}
} // namespace
wibo::Module lib_advapi32 = {
(const char *[]){
"advapi32",

98
dll/advapi32/internal.cpp Normal file
View File

@ -0,0 +1,98 @@
#include "internal.h"
#include <cctype>
#include <mutex>
#include <unordered_map>
namespace {
constexpr DWORD SECURITY_LOCAL_SYSTEM_RID = 18;
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
std::mutex privilegeMapMutex;
std::unordered_map<std::string, LUID> privilegeLuidCache;
LUID generateDeterministicLuid(const std::string &normalizedName) {
uint32_t hash = 2166136261u;
for (unsigned char ch : normalizedName) {
hash ^= ch;
hash *= 16777619u;
}
if (hash == 0) {
hash = 1;
}
LUID luid{};
luid.LowPart = hash;
luid.HighPart = 0;
return luid;
}
} // namespace
namespace advapi32 {
bool isLocalSystemSid(const Sid *sid) {
if (!sid) {
return false;
}
if (sid->Revision != 1 || sid->SubAuthorityCount != 1) {
return false;
}
for (size_t i = 0; i < std::size(kNtAuthority); ++i) {
if (sid->IdentifierAuthority.Value[i] != kNtAuthority[i]) {
return false;
}
}
return sid->SubAuthority[0] == SECURITY_LOCAL_SYSTEM_RID;
}
bool writeLocalSystemSid(Sid *sid) {
if (!sid) {
return false;
}
sid->Revision = 1;
sid->SubAuthorityCount = 1;
SidIdentifierAuthority authority{};
for (size_t i = 0; i < std::size(kNtAuthority); ++i) {
authority.Value[i] = kNtAuthority[i];
}
sid->IdentifierAuthority = authority;
sid->SubAuthority[0] = SECURITY_LOCAL_SYSTEM_RID;
return true;
}
std::string normalizePrivilegeName(const std::string &name) {
std::string normalized;
normalized.reserve(name.size());
for (unsigned char ch : name) {
normalized.push_back(static_cast<char>(std::tolower(ch)));
}
return normalized;
}
LUID lookupOrGeneratePrivilegeLuid(const std::string &normalizedName) {
std::lock_guard<std::mutex> lock(privilegeMapMutex);
static const std::unordered_map<std::string, uint32_t> predefined = {
{"se_debug_name", 0x14},
{"se_shutdown_name", 0x13},
};
auto it = privilegeLuidCache.find(normalizedName);
if (it != privilegeLuidCache.end()) {
return it->second;
}
LUID luid{};
auto predefinedIt = predefined.find(normalizedName);
if (predefinedIt != predefined.end()) {
luid.LowPart = predefinedIt->second;
luid.HighPart = 0;
} else {
luid = generateDeterministicLuid(normalizedName);
}
privilegeLuidCache[normalizedName] = luid;
return luid;
}
void releaseToken(void *tokenPtr) { delete reinterpret_cast<TokenObject *>(tokenPtr); }
} // namespace advapi32

30
dll/advapi32/internal.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#include "common.h"
#include "securitybaseapi.h"
#include <string>
namespace advapi32 {
struct TokenObject {
HANDLE processHandle;
DWORD desiredAccess;
};
using SidIdentifierAuthority = SID_IDENTIFIER_AUTHORITY;
struct Sid {
BYTE Revision;
BYTE SubAuthorityCount;
SidIdentifierAuthority IdentifierAuthority;
DWORD SubAuthority[1];
};
bool isLocalSystemSid(const Sid *sid);
bool writeLocalSystemSid(Sid *sid);
std::string normalizePrivilegeName(const std::string &name);
LUID lookupOrGeneratePrivilegeLuid(const std::string &normalizedName);
void releaseToken(void *tokenPtr);
} // namespace advapi32

View File

@ -0,0 +1,27 @@
#include "processthreadsapi.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"
namespace advapi32 {
BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle) {
DEBUG_LOG("OpenProcessToken(%p, %u, %p)\n", ProcessHandle, DesiredAccess, TokenHandle);
if (!TokenHandle) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *token = new TokenObject;
token->processHandle = ProcessHandle;
token->desiredAccess = DesiredAccess;
handles::Data data;
data.type = handles::TYPE_TOKEN;
data.ptr = token;
data.size = sizeof(TokenObject);
*TokenHandle = handles::allocDataHandle(data);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
} // namespace advapi32

View File

@ -0,0 +1,9 @@
#pragma once
#include "common.h"
namespace advapi32 {
BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
} // namespace advapi32

View File

@ -0,0 +1,518 @@
#include "securitybaseapi.h"
#include "errors.h"
#include "handles.h"
#include "internal.h"
#include <algorithm>
#include <cstring>
#include <limits>
namespace {
using advapi32::Sid;
constexpr size_t kAceAlignment = 4;
constexpr DWORD ERROR_REVISION_MISMATCH = 1306;
constexpr DWORD ERROR_INVALID_ACL = 1336;
constexpr DWORD ERROR_INVALID_SID = 1337;
constexpr DWORD ERROR_ALLOTTED_SPACE_EXCEEDED = 1344;
constexpr DWORD ERROR_INVALID_SECURITY_DESCR = 1338;
size_t alignToDword(size_t value) { return (value + (kAceAlignment - 1)) & ~(kAceAlignment - 1); }
size_t sidLength(const Sid *sid) {
if (!sid) {
return 0;
}
if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
return 0;
}
size_t base = sizeof(Sid) - sizeof(DWORD);
size_t extra = static_cast<size_t>(sid->SubAuthorityCount) * sizeof(DWORD);
return base + extra;
}
bool computeAclUsedSize(const ACL *acl, size_t capacity, size_t &used) {
if (!acl || capacity < sizeof(ACL)) {
return false;
}
size_t offset = sizeof(ACL);
const BYTE *base = reinterpret_cast<const BYTE *>(acl);
for (WORD i = 0; i < acl->AceCount; ++i) {
if (offset + sizeof(ACE_HEADER) > capacity) {
return false;
}
const auto *header = reinterpret_cast<const ACE_HEADER *>(base + offset);
if (header->AceSize < sizeof(ACE_HEADER)) {
return false;
}
size_t aceSize = header->AceSize;
if (offset + aceSize > capacity) {
return false;
}
offset += aceSize;
}
used = offset;
return true;
}
struct SidAndAttributes {
Sid *SidPtr;
DWORD Attributes;
};
struct TokenUserData {
SidAndAttributes User;
};
struct TokenStatisticsData {
LUID tokenId{};
LUID authenticationId{};
LARGE_INTEGER expirationTime{};
DWORD tokenType = 0;
DWORD impersonationLevel = 0;
DWORD dynamicCharged = 0;
DWORD dynamicAvailable = 0;
DWORD groupCount = 0;
DWORD privilegeCount = 0;
LUID modifiedId{};
};
struct TokenPrimaryGroupStub {
Sid *PrimaryGroup;
};
} // namespace
namespace advapi32 {
BOOL WIN_FUNC InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision) {
DEBUG_LOG("InitializeAcl(%p, %u, %u)\n", pAcl, nAclLength, dwAclRevision);
if (!pAcl) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (nAclLength < sizeof(ACL) || nAclLength > std::numeric_limits<WORD>::max() || (nAclLength & 0x3) != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
BYTE revision = static_cast<BYTE>(dwAclRevision);
switch (revision) {
case ACL_REVISION1:
case ACL_REVISION2:
case ACL_REVISION3:
case ACL_REVISION4:
break;
default:
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
pAcl->AclRevision = revision;
pAcl->Sbz1 = 0;
pAcl->AclSize = static_cast<WORD>(sizeof(ACL));
pAcl->AceCount = 0;
pAcl->Sbz2 = static_cast<WORD>(nAclLength);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid) {
DEBUG_LOG("AddAccessAllowedAce(%p, %u, 0x%x, %p)\n", pAcl, dwAceRevision, AccessMask, pSid);
if (!pAcl || !pSid) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
BYTE revision = static_cast<BYTE>(dwAceRevision);
switch (revision) {
case ACL_REVISION1:
case ACL_REVISION2:
case ACL_REVISION3:
case ACL_REVISION4:
break;
default:
wibo::lastError = ERROR_REVISION_MISMATCH;
return FALSE;
}
if (pAcl->AclRevision < revision) {
wibo::lastError = ERROR_REVISION_MISMATCH;
return FALSE;
}
if (pAcl->AceCount == std::numeric_limits<WORD>::max()) {
wibo::lastError = ERROR_ALLOTTED_SPACE_EXCEEDED;
return FALSE;
}
size_t capacity = pAcl->Sbz2 ? pAcl->Sbz2 : pAcl->AclSize;
if (capacity < sizeof(ACL)) {
wibo::lastError = ERROR_INVALID_ACL;
return FALSE;
}
size_t used = 0;
if (!computeAclUsedSize(pAcl, capacity, used)) {
wibo::lastError = ERROR_INVALID_ACL;
return FALSE;
}
if (used > pAcl->AclSize) {
// Clamp to the computed size to avoid propagating inconsistent data.
pAcl->AclSize = static_cast<WORD>(used);
}
const auto *sid = reinterpret_cast<const Sid *>(pSid);
size_t sidLen = sidLength(sid);
if (sidLen == 0 || sidLen > capacity) {
wibo::lastError = ERROR_INVALID_SID;
return FALSE;
}
size_t aceSize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + sidLen;
aceSize = alignToDword(aceSize);
if (aceSize > std::numeric_limits<WORD>::max()) {
wibo::lastError = ERROR_INVALID_SID;
return FALSE;
}
if (used + aceSize > capacity) {
wibo::lastError = ERROR_ALLOTTED_SPACE_EXCEEDED;
return FALSE;
}
auto *dest = reinterpret_cast<BYTE *>(pAcl) + used;
std::memset(dest, 0, aceSize);
auto *ace = reinterpret_cast<ACCESS_ALLOWED_ACE *>(dest);
ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
ace->Header.AceFlags = 0;
ace->Header.AceSize = static_cast<WORD>(aceSize);
ace->Mask = AccessMask;
std::memcpy(&ace->SidStart, sid, sidLen);
pAcl->AceCount = static_cast<WORD>(pAcl->AceCount + 1);
pAcl->AclSize = static_cast<WORD>(used + aceSize);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce);
if (!pAce) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
*pAce = nullptr;
if (!pAcl) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
size_t capacity = pAcl->Sbz2 ? pAcl->Sbz2 : pAcl->AclSize;
size_t used = 0;
if (!computeAclUsedSize(pAcl, capacity, used)) {
wibo::lastError = ERROR_INVALID_ACL;
return FALSE;
}
*pAce = reinterpret_cast<BYTE *>(pAcl) + used;
pAcl->AclSize = static_cast<WORD>(std::max<size_t>(pAcl->AclSize, used));
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
LPBOOL lpbDaclDefaulted) {
DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl,
lpbDaclDefaulted);
if (!pSecurityDescriptor) {
wibo::lastError = ERROR_INVALID_SECURITY_DESCR;
return FALSE;
}
if (!lpbDaclPresent) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
wibo::lastError = ERROR_INVALID_SECURITY_DESCR;
return FALSE;
}
BOOL hasDacl = (pSecurityDescriptor->Control & SE_DACL_PRESENT) ? TRUE : FALSE;
*lpbDaclPresent = hasDacl;
if (!hasDacl) {
if (pDacl) {
*pDacl = nullptr;
}
if (lpbDaclDefaulted) {
*lpbDaclDefaulted = FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (pDacl) {
*pDacl = pSecurityDescriptor->Dacl;
}
if (lpbDaclDefaulted) {
*lpbDaclDefaulted = (pSecurityDescriptor->Control & SE_DACL_DEFAULTED) ? TRUE : FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
PSID_IDENTIFIER_AUTHORITY WIN_FUNC GetSidIdentifierAuthority(PSID pSid) {
DEBUG_LOG("GetSidIdentifierAuthority(%p)\n", pSid);
if (!pSid) {
wibo::lastError = ERROR_INVALID_SID;
return nullptr;
}
auto *sid = reinterpret_cast<Sid *>(pSid);
if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
wibo::lastError = ERROR_INVALID_SID;
return nullptr;
}
wibo::lastError = ERROR_SUCCESS;
return reinterpret_cast<PSID_IDENTIFIER_AUTHORITY>(&sid->IdentifierAuthority);
}
PUCHAR WIN_FUNC GetSidSubAuthorityCount(PSID pSid) {
DEBUG_LOG("GetSidSubAuthorityCount(%p)\n", pSid);
if (!pSid) {
wibo::lastError = ERROR_INVALID_SID;
return nullptr;
}
auto *sid = reinterpret_cast<Sid *>(pSid);
if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
wibo::lastError = ERROR_INVALID_SID;
return nullptr;
}
wibo::lastError = ERROR_SUCCESS;
return &sid->SubAuthorityCount;
}
PDWORD WIN_FUNC GetSidSubAuthority(PSID pSid, DWORD nSubAuthority) {
DEBUG_LOG("GetSidSubAuthority(%p, %u)\n", pSid, nSubAuthority);
if (!pSid) {
wibo::lastError = ERROR_INVALID_SID;
return nullptr;
}
auto *sid = reinterpret_cast<Sid *>(pSid);
if (sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES || nSubAuthority >= sid->SubAuthorityCount) {
wibo::lastError = ERROR_INVALID_SID;
return nullptr;
}
wibo::lastError = ERROR_SUCCESS;
return &sid->SubAuthority[nSubAuthority];
}
BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken) {
DEBUG_LOG("STUB: ImpersonateLoggedOnUser(%p)\n", hToken);
(void)hToken;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) {
DEBUG_LOG("DuplicateTokenEx(%p, 0x%x, %p, %u, %u, %p)\n", hExistingToken, dwDesiredAccess, lpTokenAttributes,
ImpersonationLevel, TokenType, phNewToken);
(void)lpTokenAttributes;
(void)ImpersonationLevel;
(void)TokenType;
if (!phNewToken) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
handles::Data existingData = handles::dataFromHandle(hExistingToken, false);
if (existingData.type != handles::TYPE_TOKEN || existingData.ptr == nullptr) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
auto *existingToken = static_cast<TokenObject *>(existingData.ptr);
auto *newToken = new TokenObject(*existingToken);
if (dwDesiredAccess != 0) {
newToken->desiredAccess = dwDesiredAccess;
}
handles::Data newData;
newData.type = handles::TYPE_TOKEN;
newData.ptr = newToken;
newData.size = sizeof(TokenObject);
*phNewToken = handles::allocDataHandle(newData);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid) {
DEBUG_LOG("CopySid(%u, %p, %p)\n", nDestinationSidLength, pDestinationSid, pSourceSid);
if (!pDestinationSid || !pSourceSid) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *source = reinterpret_cast<Sid *>(pSourceSid);
size_t required = sidLength(source);
if (required == 0 || required > nDestinationSidLength) {
wibo::lastError = ERROR_ALLOTTED_SPACE_EXCEEDED;
return FALSE;
}
std::memcpy(pDestinationSid, pSourceSid, required);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor) {
DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor);
(void)SecurityInformation;
if (!SecurityDescriptor) {
wibo::lastError = ERROR_INVALID_SECURITY_DESCR;
return FALSE;
}
auto data = handles::dataFromHandle(Handle, false);
if (data.type == handles::TYPE_UNUSED) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision) {
DEBUG_LOG("InitializeSecurityDescriptor(%p, %u)\n", pSecurityDescriptor, dwRevision);
if (!pSecurityDescriptor || dwRevision != SECURITY_DESCRIPTOR_REVISION) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
pSecurityDescriptor->Revision = static_cast<BYTE>(dwRevision);
pSecurityDescriptor->Sbz1 = 0;
pSecurityDescriptor->Control = 0;
pSecurityDescriptor->Owner = nullptr;
pSecurityDescriptor->Group = nullptr;
pSecurityDescriptor->Sacl = nullptr;
pSecurityDescriptor->Dacl = nullptr;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
BOOL bDaclDefaulted) {
DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted);
if (!pSecurityDescriptor || pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
WORD control = static_cast<WORD>(pSecurityDescriptor->Control & ~(SE_DACL_PRESENT | SE_DACL_DEFAULTED));
if (bDaclPresent) {
control = static_cast<WORD>(control | SE_DACL_PRESENT);
if (bDaclDefaulted) {
control = static_cast<WORD>(control | SE_DACL_DEFAULTED);
}
pSecurityDescriptor->Dacl = pDacl;
} else {
pSecurityDescriptor->Dacl = nullptr;
}
pSecurityDescriptor->Control = control;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) {
DEBUG_LOG("GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation,
TokenInformationLength, ReturnLength);
if (!ReturnLength) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto data = handles::dataFromHandle(TokenHandle, false);
if (data.type != handles::TYPE_TOKEN) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
*ReturnLength = 0;
if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenUser) {
constexpr size_t sidSize = sizeof(Sid);
constexpr size_t tokenUserSize = sizeof(TokenUserData);
DWORD required = static_cast<DWORD>(tokenUserSize + sidSize);
*ReturnLength = required;
if (!TokenInformation || TokenInformationLength < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
auto *tokenUser = reinterpret_cast<TokenUserData *>(TokenInformation);
auto *sid = reinterpret_cast<Sid *>(reinterpret_cast<BYTE *>(TokenInformation) + tokenUserSize);
if (!writeLocalSystemSid(sid)) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
tokenUser->User.SidPtr = sid;
tokenUser->User.Attributes = 0;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenStatistics) {
DWORD required = sizeof(TokenStatisticsData);
*ReturnLength = required;
if (!TokenInformation || TokenInformationLength < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
auto *stats = reinterpret_cast<TokenStatisticsData *>(TokenInformation);
*stats = TokenStatisticsData{};
stats->tokenType = 1; // TokenPrimary
stats->impersonationLevel = 0; // SecurityAnonymous
stats->tokenId.LowPart = 1;
stats->authenticationId.LowPart = 1;
stats->modifiedId.LowPart = 1;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenElevation) {
DWORD required = sizeof(DWORD);
*ReturnLength = required;
if (!TokenInformation || TokenInformationLength < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
*reinterpret_cast<DWORD *>(TokenInformation) = 0; // not elevated
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (TokenInformationClass == TOKEN_INFORMATION_CLASS::TokenPrimaryGroup) {
DWORD required = static_cast<DWORD>(sizeof(TokenPrimaryGroupStub) + sizeof(Sid));
*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<BYTE *>(TokenInformation) + sizeof(TokenPrimaryGroupStub));
if (!writeLocalSystemSid(sid)) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
groupInfo->PrimaryGroup = sid;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) {
DEBUG_LOG("AdjustTokenPrivileges(%p, %u, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, NewState,
BufferLength, PreviousState, ReturnLength);
(void)TokenHandle;
(void)DisableAllPrivileges;
(void)NewState;
(void)BufferLength;
(void)PreviousState;
(void)ReturnLength;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength) {
DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation,
TokenInformationLength);
(void)TokenInformationClass;
(void)TokenInformation;
(void)TokenInformationLength;
auto data = handles::dataFromHandle(TokenHandle, false);
if (data.type != handles::TYPE_TOKEN) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
} // namespace advapi32

View File

@ -0,0 +1,109 @@
#pragma once
#include "common.h"
struct ACL {
BYTE AclRevision;
BYTE Sbz1;
WORD AclSize;
WORD AceCount;
WORD Sbz2;
};
struct ACE_HEADER {
BYTE AceType;
BYTE AceFlags;
WORD AceSize;
};
struct ACCESS_ALLOWED_ACE {
ACE_HEADER Header;
DWORD Mask;
DWORD SidStart;
};
struct SID_IDENTIFIER_AUTHORITY {
BYTE Value[6];
};
struct SECURITY_DESCRIPTOR {
BYTE Revision;
BYTE Sbz1;
WORD Control;
void *Owner;
void *Group;
ACL *Sacl;
ACL *Dacl;
};
using PSECURITY_DESCRIPTOR = SECURITY_DESCRIPTOR *;
using PACL = ACL *;
using PSID_IDENTIFIER_AUTHORITY = SID_IDENTIFIER_AUTHORITY *;
using SECURITY_INFORMATION = DWORD;
constexpr DWORD SECURITY_DESCRIPTOR_REVISION = 1;
constexpr WORD SE_DACL_PRESENT = 0x0004;
constexpr WORD SE_DACL_DEFAULTED = 0x0008;
constexpr BYTE ACL_REVISION1 = 1;
constexpr BYTE ACL_REVISION2 = 2;
constexpr BYTE ACL_REVISION3 = 3;
constexpr BYTE ACL_REVISION4 = 4;
constexpr BYTE ACL_REVISION = ACL_REVISION2;
constexpr BYTE ACL_REVISION_DS = ACL_REVISION4;
constexpr BYTE ACCESS_ALLOWED_ACE_TYPE = 0x00;
constexpr BYTE SID_MAX_SUB_AUTHORITIES = 15;
struct TOKEN_PRIVILEGES;
using PTOKEN_PRIVILEGES = TOKEN_PRIVILEGES *;
enum TOKEN_INFORMATION_CLASS : DWORD {
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation = 20,
};
namespace advapi32 {
BOOL WIN_FUNC InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision);
BOOL WIN_FUNC AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid);
BOOL WIN_FUNC FindFirstFreeAce(PACL pAcl, LPVOID *pAce);
PSID_IDENTIFIER_AUTHORITY WIN_FUNC GetSidIdentifierAuthority(PSID pSid);
PUCHAR WIN_FUNC GetSidSubAuthorityCount(PSID pSid);
PDWORD WIN_FUNC GetSidSubAuthority(PSID pSid, DWORD nSubAuthority);
BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken);
BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken);
BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid);
BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
LPBOOL lpbDaclDefaulted);
BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor);
BOOL WIN_FUNC InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision);
BOOL WIN_FUNC SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
BOOL bDaclDefaulted);
BOOL WIN_FUNC GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength);
BOOL WIN_FUNC AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength);
BOOL WIN_FUNC SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
LPVOID TokenInformation, DWORD TokenInformationLength);
} // namespace advapi32

117
dll/advapi32/winbase.cpp Normal file
View File

@ -0,0 +1,117 @@
#include "winbase.h"
#include "errors.h"
#include "internal.h"
#include "strutil.h"
#include <algorithm>
#include <cstring>
namespace {
constexpr WCHAR kAccountSystem[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'};
constexpr WCHAR kDomainNtAuthority[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'};
} // namespace
namespace advapi32 {
BOOL WIN_FUNC LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse) {
std::string systemName = lpSystemName ? wideStringToString(lpSystemName) : std::string("(null)");
DEBUG_LOG("LookupAccountSidW(%s, %p, %p, %p, %p, %p, %p)\n", systemName.c_str(), Sid, Name, cchName,
ReferencedDomainName, cchReferencedDomainName, peUse);
if (!Sid || !cchName || !cchReferencedDomainName || !peUse) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *sidStruct = reinterpret_cast<const ::advapi32::Sid *>(Sid);
if (!isLocalSystemSid(sidStruct)) {
wibo::lastError = ERROR_NONE_MAPPED;
return FALSE;
}
DWORD requiredAccount = static_cast<DWORD>(wstrlen(kAccountSystem));
DWORD requiredDomain = static_cast<DWORD>(wstrlen(kDomainNtAuthority));
if (!Name || *cchName <= requiredAccount || !ReferencedDomainName || *cchReferencedDomainName <= requiredDomain) {
*cchName = requiredAccount + 1;
*cchReferencedDomainName = requiredDomain + 1;
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
std::copy_n(kAccountSystem, requiredAccount + 1, Name);
std::copy_n(kDomainNtAuthority, requiredDomain + 1, ReferencedDomainName);
*peUse = SidTypeWellKnownGroup;
*cchName = requiredAccount;
*cchReferencedDomainName = requiredDomain;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid) {
DEBUG_LOG("LookupPrivilegeValueA(%s, %s, %p)\n", lpSystemName ? lpSystemName : "(null)", lpName ? lpName : "(null)",
lpLuid);
(void)lpSystemName; // only local lookup supported
if (!lpName || !lpLuid) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
std::string normalized = normalizePrivilegeName(lpName);
LUID luid = lookupOrGeneratePrivilegeLuid(normalized);
*lpLuid = luid;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid) {
DEBUG_LOG("LookupPrivilegeValueW(%p, %p, %p)\n", lpSystemName, lpName, lpLuid);
(void)lpSystemName; // only local lookup supported
if (!lpName || !lpLuid) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
std::string ansiName = wideStringToString(lpName);
std::string normalized = normalizePrivilegeName(ansiName);
LUID luid = lookupOrGeneratePrivilegeLuid(normalized);
*lpLuid = luid;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer) {
DEBUG_LOG("GetUserNameA(%p, %p)\n", lpBuffer, pcbBuffer);
if (!pcbBuffer) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
const char *name = "SYSTEM";
size_t needed = std::strlen(name) + 1;
if (!lpBuffer || *pcbBuffer < needed) {
*pcbBuffer = static_cast<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(LPWSTR lpBuffer, LPDWORD pcbBuffer) {
DEBUG_LOG("GetUserNameW(%p, %p)\n", lpBuffer, pcbBuffer);
if (!pcbBuffer) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
size_t needed = wstrlen(kAccountSystem) + 1;
if (!lpBuffer || *pcbBuffer < needed) {
*pcbBuffer = static_cast<DWORD>(needed);
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
std::memcpy(lpBuffer, kAccountSystem, needed * sizeof(WCHAR));
*pcbBuffer = static_cast<DWORD>(needed);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
} // namespace advapi32

27
dll/advapi32/winbase.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "common.h"
enum SID_NAME_USE : DWORD {
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer,
SidTypeLabel
};
namespace advapi32 {
BOOL WIN_FUNC LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse);
BOOL WIN_FUNC LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid);
BOOL WIN_FUNC LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid);
BOOL WIN_FUNC GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer);
BOOL WIN_FUNC GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
} // namespace advapi32

View File

@ -33,11 +33,11 @@ constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = {
constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos);
std::mutex registryMutex;
bool predefinedHandlesInitialized = false;
RegistryKeyHandleData predefinedHandles[kPredefinedKeyCount];
bool registryInitialized = false;
std::unordered_set<std::u16string> existingKeys;
std::mutex g_registryMutex;
bool g_predefinedHandlesInitialized = false;
RegistryKeyHandleData g_predefinedHandles[kPredefinedKeyCount];
bool g_registryInitialized = false;
std::unordered_set<std::u16string> g_existingKeys;
std::u16string canonicalizeKeySegment(const std::u16string &input) {
std::u16string result;
@ -75,20 +75,20 @@ std::u16string canonicalizeKeySegment(LPCWSTR input) {
}
void initializePredefinedHandlesLocked() {
if (predefinedHandlesInitialized) {
if (g_predefinedHandlesInitialized) {
return;
}
for (size_t i = 0; i < kPredefinedKeyCount; ++i) {
predefinedHandles[i].canonicalPath = canonicalizeKeySegment(std::u16string(kPredefinedKeyInfos[i].name));
predefinedHandles[i].predefined = true;
g_predefinedHandles[i].canonicalPath = canonicalizeKeySegment(std::u16string(kPredefinedKeyInfos[i].name));
g_predefinedHandles[i].predefined = true;
}
predefinedHandlesInitialized = true;
g_predefinedHandlesInitialized = true;
}
RegistryKeyHandleData *predefinedHandleForValue(uintptr_t value) {
for (size_t i = 0; i < kPredefinedKeyCount; ++i) {
if (kPredefinedKeyInfos[i].value == value) {
return &predefinedHandles[i];
return &g_predefinedHandles[i];
}
}
return nullptr;
@ -121,20 +121,110 @@ bool isPredefinedKeyHandle(HKEY hKey) {
}
void ensureRegistryInitializedLocked() {
if (registryInitialized) {
if (g_registryInitialized) {
return;
}
initializePredefinedHandlesLocked();
for (size_t i = 0; i < kPredefinedKeyCount; ++i) {
existingKeys.insert(predefinedHandles[i].canonicalPath);
for (auto &g_predefinedHandle : g_predefinedHandles) {
g_existingKeys.insert(g_predefinedHandle.canonicalPath);
}
registryInitialized = true;
g_registryInitialized = true;
}
} // namespace
namespace advapi32 {
LSTATUS WIN_FUNC RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition) {
std::string subKeyString = lpSubKey ? wideStringToString(lpSubKey) : std::string("(null)");
std::string classString = lpClass ? wideStringToString(lpClass) : std::string("(null)");
DEBUG_LOG("RegCreateKeyExW(%p, %s, %u, %s, 0x%x, 0x%x, %p, %p, %p)\n", hKey, subKeyString.c_str(), Reserved,
classString.c_str(), dwOptions, samDesired, lpSecurityAttributes, phkResult, lpdwDisposition);
(void)lpClass;
(void)lpSecurityAttributes;
if (!phkResult) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
}
*phkResult = nullptr;
if (Reserved != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
}
if (dwOptions != 0) {
DEBUG_LOG("RegCreateKeyExW: unsupported options 0x%x\n", dwOptions);
wibo::lastError = ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
}
REGSAM sanitizedAccess = samDesired & ~(KEY_WOW64_64KEY | KEY_WOW64_32KEY);
if (sanitizedAccess != samDesired) {
DEBUG_LOG("RegCreateKeyExW: ignoring WOW64 access mask 0x%x\n", samDesired ^ sanitizedAccess);
}
std::lock_guard<std::mutex> lock(g_registryMutex);
ensureRegistryInitializedLocked();
RegistryKeyHandleData *baseHandle = handleDataFromHKeyLocked(hKey);
if (!baseHandle) {
wibo::lastError = ERROR_INVALID_HANDLE;
return ERROR_INVALID_HANDLE;
}
std::u16string targetPath = baseHandle->canonicalPath;
bool targetingBase = true;
if (lpSubKey && lpSubKey[0] != 0) {
std::u16string subComponent = canonicalizeKeySegment(lpSubKey);
if (!subComponent.empty()) {
targetingBase = false;
if (!targetPath.empty()) {
targetPath.push_back(u'\\');
}
targetPath.append(subComponent);
}
}
if (targetPath.empty()) {
wibo::lastError = ERROR_INVALID_HANDLE;
return ERROR_INVALID_HANDLE;
}
bool existed = g_existingKeys.find(targetPath) != g_existingKeys.end();
if (!existed) {
g_existingKeys.insert(targetPath);
}
if (lpdwDisposition) {
*lpdwDisposition = existed ? REG_OPENED_EXISTING_KEY : REG_CREATED_NEW_KEY;
}
if (targetingBase) {
*phkResult = hKey;
wibo::lastError = ERROR_SUCCESS;
return ERROR_SUCCESS;
}
auto *handleData = new RegistryKeyHandleData;
handleData->canonicalPath = targetPath;
handleData->predefined = false;
auto handle = handles::allocDataHandle({handles::TYPE_REGISTRY_KEY, handleData, sizeof(*handleData)});
*phkResult = reinterpret_cast<HKEY>(handle);
wibo::lastError = ERROR_SUCCESS;
return ERROR_SUCCESS;
}
LSTATUS WIN_FUNC RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition) {
DEBUG_LOG("RegCreateKeyExA(%p, %s, %u, %s, 0x%x, 0x%x, %p, %p, %p)\n", hKey, lpSubKey ? lpSubKey : "(null)",
Reserved, lpClass ? lpClass : "(null)", dwOptions, samDesired, lpSecurityAttributes, phkResult,
lpdwDisposition);
std::vector<uint16_t> subKeyWideStorage;
if (lpSubKey) {
subKeyWideStorage = stringToWideString(lpSubKey);
}
std::vector<uint16_t> classWideStorage;
if (lpClass) {
classWideStorage = stringToWideString(lpClass);
}
return RegCreateKeyExW(hKey, lpSubKey ? reinterpret_cast<LPCWSTR>(subKeyWideStorage.data()) : nullptr, Reserved,
lpClass ? reinterpret_cast<LPWSTR>(classWideStorage.data()) : nullptr, dwOptions, samDesired,
lpSecurityAttributes, phkResult, lpdwDisposition);
}
LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) {
std::string subKeyString = lpSubKey ? wideStringToString(lpSubKey) : std::string("(null)");
DEBUG_LOG("RegOpenKeyExW(%p, %s, %u, 0x%x, %p)\n", hKey, subKeyString.c_str(), ulOptions, samDesired, phkResult);
@ -155,7 +245,7 @@ LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REG
DEBUG_LOG("RegOpenKeyExW: ignoring WOW64 access mask 0x%x\n", samDesired ^ sanitizedAccess);
}
(void)sanitizedAccess;
std::lock_guard<std::mutex> lock(registryMutex);
std::lock_guard<std::mutex> lock(g_registryMutex);
ensureRegistryInitializedLocked();
RegistryKeyHandleData *baseHandle = handleDataFromHKeyLocked(hKey);
if (!baseHandle) {
@ -176,7 +266,7 @@ LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REG
wibo::lastError = ERROR_INVALID_HANDLE;
return ERROR_INVALID_HANDLE;
}
if (existingKeys.find(targetPath) == existingKeys.end()) {
if (g_existingKeys.find(targetPath) == g_existingKeys.end()) {
wibo::lastError = ERROR_FILE_NOT_FOUND;
return ERROR_FILE_NOT_FOUND;
}
@ -208,6 +298,93 @@ LSTATUS WIN_FUNC RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGS
return RegOpenKeyExW(hKey, widePtr, ulOptions, samDesired, phkResult);
}
LSTATUS WIN_FUNC RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData) {
std::string valueName = lpValueName ? wideStringToString(lpValueName) : std::string("(default)");
DEBUG_LOG("RegQueryValueExW(%p, %s, %p, %p, %p, %p)\n", hKey, valueName.c_str(), lpReserved, lpType, lpData,
lpcbData);
if (lpReserved) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
}
if (lpcbData) {
*lpcbData = 0;
}
if (lpType) {
*lpType = 0;
}
(void)hKey;
(void)lpData;
wibo::lastError = ERROR_FILE_NOT_FOUND;
return ERROR_FILE_NOT_FOUND;
}
LSTATUS WIN_FUNC RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData) {
DEBUG_LOG("RegQueryValueExA(%p, %s, %p, %p, %p, %p)\n", hKey, lpValueName ? lpValueName : "(null)", lpReserved,
lpType, lpData, lpcbData);
std::vector<uint16_t> valueWideStorage;
if (lpValueName) {
valueWideStorage = stringToWideString(lpValueName);
}
return RegQueryValueExW(hKey, lpValueName ? reinterpret_cast<LPCWSTR>(valueWideStorage.data()) : nullptr,
lpReserved, lpType, lpData, lpcbData);
}
LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime) {
DEBUG_LOG("RegEnumKeyExW(%p, %u, %p, %p, %p, %p, %p, %p)\n", hKey, dwIndex, lpName, lpcchName, lpReserved, lpClass,
lpcchClass, lpftLastWriteTime);
(void)hKey;
(void)dwIndex;
if (lpReserved) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
}
if (lpcchName) {
*lpcchName = 0;
}
if (lpName && lpcchName && *lpcchName > 0) {
lpName[0] = 0;
}
if (lpClass && lpcchClass && *lpcchClass > 0) {
lpClass[0] = 0;
}
if (lpcchClass) {
*lpcchClass = 0;
}
(void)lpftLastWriteTime;
wibo::lastError = ERROR_NO_MORE_ITEMS;
return ERROR_NO_MORE_ITEMS;
}
LSTATUS WIN_FUNC RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime) {
DEBUG_LOG("RegEnumKeyExA(%p, %u, %p, %p, %p, %p, %p, %p)\n", hKey, dwIndex, lpName, lpcchName, lpReserved, lpClass,
lpcchClass, lpftLastWriteTime);
(void)hKey;
(void)dwIndex;
if (lpReserved) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER;
}
if (lpcchName) {
*lpcchName = 0;
}
if (lpName && lpcchName && *lpcchName > 0) {
lpName[0] = '\0';
}
if (lpClass && lpcchClass && *lpcchClass > 0) {
lpClass[0] = '\0';
}
if (lpcchClass) {
*lpcchClass = 0;
}
(void)lpftLastWriteTime;
wibo::lastError = ERROR_NO_MORE_ITEMS;
return ERROR_NO_MORE_ITEMS;
}
LSTATUS WIN_FUNC RegCloseKey(HKEY hKey) {
DEBUG_LOG("RegCloseKey(%p)\n", hKey);
if (isPredefinedKeyHandle(hKey)) {

View File

@ -2,6 +2,8 @@
#include "common.h"
struct FILETIME;
#ifndef HKEY_CLASSES_ROOT
#define HKEY_CLASSES_ROOT ((HKEY)(uintptr_t)0x80000000u)
#endif
@ -23,13 +25,30 @@
constexpr DWORD REG_OPTION_OPEN_LINK = 0x00000008;
constexpr DWORD REG_CREATED_NEW_KEY = 0x00000001;
constexpr DWORD REG_OPENED_EXISTING_KEY = 0x00000002;
constexpr REGSAM KEY_WOW64_64KEY = 0x00000100;
constexpr REGSAM KEY_WOW64_32KEY = 0x00000200;
namespace advapi32 {
LSTATUS WIN_FUNC RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition);
LSTATUS WIN_FUNC RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
LPDWORD lpdwDisposition);
LSTATUS WIN_FUNC RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
LSTATUS WIN_FUNC RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
LSTATUS WIN_FUNC RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData);
LSTATUS WIN_FUNC RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
LPDWORD lpcbData);
LSTATUS WIN_FUNC RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
LSTATUS WIN_FUNC RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
LSTATUS WIN_FUNC RegCloseKey(HKEY hKey);
} // namespace advapi32

View File

@ -23,7 +23,9 @@
#include "kernel32/winnt.h"
#include "kernel32/wow64apiset.h"
static void *resolveByName(const char *name) {
namespace {
void *resolveByName(const char *name) {
// errhandlingapi.h
if (strcmp(name, "GetLastError") == 0)
return (void *)kernel32::GetLastError;
@ -97,6 +99,8 @@ static void *resolveByName(const char *name) {
return (void *)kernel32::SetThreadPriority;
if (strcmp(name, "GetThreadPriority") == 0)
return (void *)kernel32::GetThreadPriority;
if (strcmp(name, "GetPriorityClass") == 0)
return (void *)kernel32::GetPriorityClass;
if (strcmp(name, "GetProcessAffinityMask") == 0)
return (void *)kernel32::GetProcessAffinityMask;
if (strcmp(name, "SetProcessAffinityMask") == 0)
@ -293,6 +297,10 @@ static void *resolveByName(const char *name) {
return (void *)kernel32::WriteConsoleW;
if (strcmp(name, "GetConsoleOutputCP") == 0)
return (void *)kernel32::GetConsoleOutputCP;
if (strcmp(name, "GetConsoleTitleA") == 0)
return (void *)kernel32::GetConsoleTitleA;
if (strcmp(name, "GetConsoleTitleW") == 0)
return (void *)kernel32::GetConsoleTitleW;
if (strcmp(name, "PeekConsoleInputA") == 0)
return (void *)kernel32::PeekConsoleInputA;
if (strcmp(name, "ReadConsoleInputA") == 0)
@ -323,6 +331,18 @@ static void *resolveByName(const char *name) {
return (void *)kernel32::GetFileAttributesA;
if (strcmp(name, "GetFileAttributesW") == 0)
return (void *)kernel32::GetFileAttributesW;
if (strcmp(name, "GetDriveTypeA") == 0)
return (void *)kernel32::GetDriveTypeA;
if (strcmp(name, "GetDriveTypeW") == 0)
return (void *)kernel32::GetDriveTypeW;
if (strcmp(name, "GetVolumeInformationA") == 0)
return (void *)kernel32::GetVolumeInformationA;
if (strcmp(name, "GetVolumeInformationW") == 0)
return (void *)kernel32::GetVolumeInformationW;
if (strcmp(name, "CompareFileTime") == 0)
return (void *)kernel32::CompareFileTime;
if (strcmp(name, "GetFileAttributesW") == 0)
return (void *)kernel32::GetFileAttributesW;
if (strcmp(name, "WriteFile") == 0)
return (void *)kernel32::WriteFile;
if (strcmp(name, "FlushFileBuffers") == 0)
@ -339,6 +359,8 @@ static void *resolveByName(const char *name) {
return (void *)kernel32::CreateFileMappingW;
if (strcmp(name, "MapViewOfFile") == 0)
return (void *)kernel32::MapViewOfFile;
if (strcmp(name, "MapViewOfFileEx") == 0)
return (void *)kernel32::MapViewOfFileEx;
if (strcmp(name, "UnmapViewOfFile") == 0)
return (void *)kernel32::UnmapViewOfFile;
if (strcmp(name, "DeleteFileA") == 0)
@ -541,6 +563,8 @@ static void *resolveByName(const char *name) {
return 0;
}
} // namespace
wibo::Module lib_kernel32 = {
(const char *[]){
"kernel32",

View File

@ -288,6 +288,100 @@ DWORD WIN_FUNC GetFileAttributesW(LPCWSTR lpFileName) {
return GetFileAttributesA(str.c_str());
}
UINT WIN_FUNC GetDriveTypeA(LPCSTR lpRootPathName) {
DEBUG_LOG("STUB: GetDriveTypeA(%s)\n", lpRootPathName ? lpRootPathName : "(null)");
(void)lpRootPathName;
wibo::lastError = ERROR_SUCCESS;
return DRIVE_FIXED;
}
UINT WIN_FUNC GetDriveTypeW(LPCWSTR lpRootPathName) {
DEBUG_LOG("STUB: GetDriveTypeW(%p)\n", lpRootPathName);
(void)lpRootPathName;
wibo::lastError = ERROR_SUCCESS;
return DRIVE_FIXED;
}
BOOL WIN_FUNC GetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize) {
DEBUG_LOG("STUB: GetVolumeInformationA(%s)\n", lpRootPathName ? lpRootPathName : "(null)");
if (lpVolumeNameBuffer && nVolumeNameSize > 0) {
lpVolumeNameBuffer[0] = '\0';
}
if (lpVolumeSerialNumber) {
*lpVolumeSerialNumber = 0x12345678;
}
if (lpMaximumComponentLength) {
*lpMaximumComponentLength = 255;
}
if (lpFileSystemFlags) {
*lpFileSystemFlags = 0;
}
if (lpFileSystemNameBuffer) {
if (nFileSystemNameSize > 0) {
const char *fsName = "NTFS";
size_t copyLen = std::min<size_t>(std::strlen(fsName), nFileSystemNameSize - 1);
std::memcpy(lpFileSystemNameBuffer, fsName, copyLen);
lpFileSystemNameBuffer[copyLen] = '\0';
}
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC GetVolumeInformationW(LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize) {
DEBUG_LOG("STUB: GetVolumeInformationW(%p)\n", lpRootPathName);
if (lpVolumeNameBuffer && nVolumeNameSize > 0) {
lpVolumeNameBuffer[0] = 0;
}
if (lpVolumeSerialNumber) {
*lpVolumeSerialNumber = 0x12345678;
}
if (lpMaximumComponentLength) {
*lpMaximumComponentLength = 255;
}
if (lpFileSystemFlags) {
*lpFileSystemFlags = 0;
}
if (lpFileSystemNameBuffer) {
if (nFileSystemNameSize > 0) {
std::vector<uint16_t> fsWide = stringToWideString("NTFS");
size_t copyLen = std::min<size_t>(fsWide.size() > 0 ? fsWide.size() - 1 : 0, nFileSystemNameSize - 1);
for (size_t i = 0; i < copyLen; ++i) {
lpFileSystemNameBuffer[i] = static_cast<uint16_t>(fsWide[i]);
}
lpFileSystemNameBuffer[copyLen] = 0;
}
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
LONG WIN_FUNC CompareFileTime(const FILETIME *lpFileTime1, const FILETIME *lpFileTime2) {
DEBUG_LOG("CompareFileTime(%p, %p)\n", lpFileTime1, lpFileTime2);
auto toInt64 = [](const FILETIME *ft) -> int64_t {
if (!ft) {
return 0;
}
uint64_t combined = (static_cast<uint64_t>(ft->dwHighDateTime) << 32) | ft->dwLowDateTime;
return static_cast<int64_t>(combined);
};
int64_t value1 = toInt64(lpFileTime1);
int64_t value2 = toInt64(lpFileTime2);
if (value1 < value2) {
return -1;
}
if (value1 > value2) {
return 1;
}
return 0;
}
BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped) {
DEBUG_LOG("WriteFile(%p, %u)\n", hFile, nNumberOfBytesToWrite);

View File

@ -47,6 +47,14 @@ constexpr DWORD FILE_ATTRIBUTE_OFFLINE = 0x00001000;
constexpr DWORD FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000;
constexpr DWORD FILE_ATTRIBUTE_ENCRYPTED = 0x00004000;
constexpr UINT DRIVE_UNKNOWN = 0;
constexpr UINT DRIVE_NO_ROOT_DIR = 1;
constexpr UINT DRIVE_REMOVABLE = 2;
constexpr UINT DRIVE_FIXED = 3;
constexpr UINT DRIVE_REMOTE = 4;
constexpr UINT DRIVE_CDROM = 5;
constexpr UINT DRIVE_RAMDISK = 6;
constexpr DWORD FILE_TYPE_UNKNOWN = 0x0000;
constexpr DWORD FILE_TYPE_DISK = 0x0001;
constexpr DWORD FILE_TYPE_CHAR = 0x0002;
@ -72,6 +80,8 @@ BOOL WIN_FUNC FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData)
BOOL WIN_FUNC FindClose(HANDLE hFindFile);
DWORD WIN_FUNC GetFileAttributesA(LPCSTR lpFileName);
DWORD WIN_FUNC GetFileAttributesW(LPCWSTR lpFileName);
UINT WIN_FUNC GetDriveTypeA(LPCSTR lpRootPathName);
UINT WIN_FUNC GetDriveTypeW(LPCWSTR lpRootPathName);
BOOL WIN_FUNC WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
BOOL WIN_FUNC ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
@ -101,5 +111,13 @@ BOOL WIN_FUNC SetFileTime(HANDLE hFile, const FILETIME *lpCreationTime, const FI
const FILETIME *lpLastWriteTime);
BOOL WIN_FUNC GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation);
DWORD WIN_FUNC GetFileType(HANDLE hFile);
LONG WIN_FUNC CompareFileTime(const FILETIME *lpFileTime1, const FILETIME *lpFileTime2);
BOOL WIN_FUNC GetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer, DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags, LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize);
BOOL WIN_FUNC GetVolumeInformationW(LPCWSTR lpRootPathName, LPWSTR lpVolumeNameBuffer, DWORD nVolumeNameSize,
LPDWORD lpVolumeSerialNumber, LPDWORD lpMaximumComponentLength,
LPDWORD lpFileSystemFlags, LPWSTR lpFileSystemNameBuffer,
DWORD nFileSystemNameSize);
} // namespace kernel32

View File

@ -1,5 +1,6 @@
#include "handleapi.h"
#include "dll/advapi32/internal.h"
#include "errors.h"
#include "files.h"
#include "handles.h"
@ -9,10 +10,6 @@
#include <pthread.h>
#include <unistd.h>
namespace advapi32 {
void releaseToken(void *tokenPtr);
}
namespace kernel32 {
BOOL WIN_FUNC DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle,
@ -151,12 +148,7 @@ BOOL WIN_FUNC CloseHandle(HANDLE hObject) {
success = false;
}
} else if (data.type == handles::TYPE_PROCESS) {
auto *proc = reinterpret_cast<processes::Process *>(data.ptr);
if (proc) {
delete proc;
} else {
success = false;
}
delete reinterpret_cast<processes::Process *>(data.ptr);
} else if (data.type == handles::TYPE_TOKEN) {
advapi32::releaseToken(data.ptr);
} else if (data.type == handles::TYPE_MUTEX) {

View File

@ -303,17 +303,8 @@ HANDLE WIN_FUNC CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap
lpName ? name.c_str() : nullptr);
}
LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) {
DEBUG_LOG("MapViewOfFile(%p, 0x%x, %u, %u, %zu)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
dwFileOffsetLow, dwNumberOfBytesToMap);
handles::Data data = handles::dataFromHandle(hFileMappingObject, false);
if (data.type != handles::TYPE_MAPPED) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
auto *mapping = reinterpret_cast<MappingObject *>(data.ptr);
static LPVOID mapViewOfFileInternal(MappingObject *mapping, DWORD dwDesiredAccess, uint64_t offset,
SIZE_T dwNumberOfBytesToMap, LPVOID baseAddress) {
if (!mapping) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
@ -322,8 +313,6 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess,
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
uint64_t offset = (static_cast<uint64_t>(dwFileOffsetHigh) << 32) | dwFileOffsetLow;
if (mapping->anonymous && offset != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
@ -331,11 +320,7 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess,
size_t maxSize = mapping->maxSize;
uint64_t length = static_cast<uint64_t>(dwNumberOfBytesToMap);
if (length == 0) {
if (maxSize == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
if (offset > maxSize) {
if (maxSize == 0 || offset > maxSize) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
@ -353,28 +338,27 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess,
int prot = PROT_READ;
bool wantWrite = (dwDesiredAccess & FILE_MAP_WRITE) != 0;
bool wantExecute = (dwDesiredAccess & FILE_MAP_EXECUTE) != 0;
bool wantCopy = (dwDesiredAccess & FILE_MAP_COPY) != 0;
if (mapping->protect == PAGE_READWRITE) {
if (wantWrite) {
if (wantWrite || wantCopy) {
prot |= PROT_WRITE;
}
} else {
if (wantWrite && (dwDesiredAccess & FILE_MAP_COPY) == 0) {
if (wantWrite && !wantCopy) {
wibo::lastError = ERROR_ACCESS_DENIED;
return nullptr;
}
if (wantCopy) {
prot |= PROT_WRITE;
}
}
if (wantExecute) {
prot |= PROT_EXEC;
}
int flags = 0;
if (mapping->anonymous) {
flags |= MAP_ANONYMOUS;
}
flags |= (dwDesiredAccess & FILE_MAP_COPY) ? MAP_PRIVATE : MAP_SHARED;
size_t pageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));
int flags = (mapping->anonymous ? MAP_ANONYMOUS : 0) | (wantCopy ? MAP_PRIVATE : MAP_SHARED);
const size_t pageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));
off_t alignedOffset = mapping->anonymous ? 0 : static_cast<off_t>(offset & ~static_cast<uint64_t>(pageSize - 1));
size_t offsetDelta = static_cast<size_t>(offset - static_cast<uint64_t>(alignedOffset));
uint64_t requestedLength = length + offsetDelta;
@ -389,18 +373,84 @@ LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess,
}
int mmapFd = mapping->anonymous ? -1 : mapping->fd;
void *mapBase = mmap(nullptr, mapLength, prot, flags, mmapFd, alignedOffset);
void *requestedBase = nullptr;
int mapFlags = flags;
if (baseAddress) {
uintptr_t baseAddr = reinterpret_cast<uintptr_t>(baseAddress);
if (baseAddr == 0 || (baseAddr % kVirtualAllocationGranularity) != 0) {
wibo::lastError = ERROR_INVALID_ADDRESS;
return nullptr;
}
if (offsetDelta > baseAddr) {
wibo::lastError = ERROR_INVALID_ADDRESS;
return nullptr;
}
uintptr_t mapBaseAddr = baseAddr - offsetDelta;
if ((mapBaseAddr & (pageSize - 1)) != 0) {
wibo::lastError = ERROR_INVALID_ADDRESS;
return nullptr;
}
requestedBase = reinterpret_cast<void *>(mapBaseAddr);
#ifdef MAP_FIXED_NOREPLACE
mapFlags |= MAP_FIXED_NOREPLACE;
#else
mapFlags |= MAP_FIXED;
#endif
}
errno = 0;
void *mapBase = mmap(requestedBase, mapLength, prot, mapFlags, mmapFd, alignedOffset);
if (mapBase == MAP_FAILED) {
setLastErrorFromErrno();
int err = errno;
if (baseAddress && (err == ENOMEM || err == EEXIST || err == EINVAL || err == EPERM)) {
wibo::lastError = ERROR_INVALID_ADDRESS;
} else {
wibo::lastError = wibo::winErrorFromErrno(err);
}
return nullptr;
}
void *viewPtr = static_cast<uint8_t *>(mapBase) + offsetDelta;
if (baseAddress && viewPtr != baseAddress) {
munmap(mapBase, mapLength);
wibo::lastError = ERROR_INVALID_ADDRESS;
return nullptr;
}
g_viewInfo[viewPtr] = ViewInfo{mapBase, mapLength, mapping};
mapping->refCount++;
wibo::lastError = ERROR_SUCCESS;
return viewPtr;
}
LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) {
DEBUG_LOG("MapViewOfFile(%p, 0x%x, %u, %u, %zu)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
dwFileOffsetLow, dwNumberOfBytesToMap);
handles::Data data = handles::dataFromHandle(hFileMappingObject, false);
if (data.type != handles::TYPE_MAPPED) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
auto *mapping = reinterpret_cast<MappingObject *>(data.ptr);
uint64_t offset = (static_cast<uint64_t>(dwFileOffsetHigh) << 32) | dwFileOffsetLow;
return mapViewOfFileInternal(mapping, dwDesiredAccess, offset, dwNumberOfBytesToMap, nullptr);
}
LPVOID WIN_FUNC MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) {
DEBUG_LOG("MapViewOfFileEx(%p, 0x%x, %u, %u, %zu, %p)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress);
handles::Data data = handles::dataFromHandle(hFileMappingObject, false);
if (data.type != handles::TYPE_MAPPED) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
auto *mapping = reinterpret_cast<MappingObject *>(data.ptr);
uint64_t offset = (static_cast<uint64_t>(dwFileOffsetHigh) << 32) | dwFileOffsetLow;
return mapViewOfFileInternal(mapping, dwDesiredAccess, offset, dwNumberOfBytesToMap, lpBaseAddress);
}
BOOL WIN_FUNC UnmapViewOfFile(LPCVOID lpBaseAddress) {
DEBUG_LOG("UnmapViewOfFile(%p)\n", lpBaseAddress);
auto it = g_viewInfo.find(const_cast<void *>(lpBaseAddress));

View File

@ -53,6 +53,8 @@ HANDLE WIN_FUNC CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMap
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName);
LPVOID WIN_FUNC MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap);
LPVOID WIN_FUNC MapViewOfFileEx(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress);
BOOL WIN_FUNC UnmapViewOfFile(LPCVOID lpBaseAddress);
LPVOID WIN_FUNC VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);

View File

@ -625,6 +625,13 @@ int WIN_FUNC GetThreadPriority(HANDLE hThread) {
return 0;
}
DWORD WIN_FUNC GetPriorityClass(HANDLE hProcess) {
DEBUG_LOG("GetPriorityClass(%p)\n", hProcess);
(void)hProcess;
wibo::lastError = ERROR_SUCCESS;
return NORMAL_PRIORITY_CLASS;
}
BOOL WIN_FUNC GetThreadTimes(HANDLE hThread, FILETIME *lpCreationTime, FILETIME *lpExitTime, FILETIME *lpKernelTime,
FILETIME *lpUserTime) {
DEBUG_LOG("GetThreadTimes(%p, %p, %p, %p, %p)\n", hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime);

View File

@ -61,6 +61,7 @@ struct STARTUPINFOW {
using LPSTARTUPINFOW = STARTUPINFOW *;
constexpr DWORD TLS_OUT_OF_INDEXES = 0xFFFFFFFFu;
constexpr DWORD NORMAL_PRIORITY_CLASS = 0x00000020;
typedef DWORD(WIN_FUNC *LPTHREAD_START_ROUTINE)(LPVOID);
@ -91,6 +92,7 @@ void WIN_FUNC ExitThread(DWORD dwExitCode);
BOOL WIN_FUNC GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode);
BOOL WIN_FUNC SetThreadPriority(HANDLE hThread, int nPriority);
int WIN_FUNC GetThreadPriority(HANDLE hThread);
DWORD WIN_FUNC GetPriorityClass(HANDLE hProcess);
BOOL WIN_FUNC GetThreadTimes(HANDLE hThread, FILETIME *lpCreationTime, FILETIME *lpExitTime, FILETIME *lpKernelTime,
FILETIME *lpUserTime);
BOOL WIN_FUNC CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,

View File

@ -83,6 +83,24 @@ BOOL WIN_FUNC WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumb
return FALSE;
}
DWORD WIN_FUNC GetConsoleTitleA(LPSTR lpConsoleTitle, DWORD nSize) {
DEBUG_LOG("GetConsoleTitleA(%p, %u)\n", lpConsoleTitle, nSize);
if (lpConsoleTitle && nSize > 0) {
lpConsoleTitle[0] = '\0';
}
wibo::lastError = ERROR_SUCCESS;
return 0;
}
DWORD WIN_FUNC GetConsoleTitleW(LPWSTR lpConsoleTitle, DWORD nSize) {
DEBUG_LOG("GetConsoleTitleW(%p, %u)\n", lpConsoleTitle, nSize);
if (lpConsoleTitle && nSize > 0) {
lpConsoleTitle[0] = 0;
}
wibo::lastError = ERROR_SUCCESS;
return 0;
}
BOOL WIN_FUNC PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
LPDWORD lpNumberOfEventsRead) {
DEBUG_LOG("STUB: PeekConsoleInputA(%p, %p, %u)\n", hConsoleInput, lpBuffer, nLength);

View File

@ -35,6 +35,8 @@ BOOL WIN_FUNC SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add);
BOOL WIN_FUNC GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO *lpConsoleScreenBufferInfo);
BOOL WIN_FUNC WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved);
DWORD WIN_FUNC GetConsoleTitleA(LPSTR lpConsoleTitle, DWORD nSize);
DWORD WIN_FUNC GetConsoleTitleW(LPWSTR lpConsoleTitle, DWORD nSize);
BOOL WIN_FUNC PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
LPDWORD lpNumberOfEventsRead);
BOOL WIN_FUNC ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,

View File

@ -9,6 +9,7 @@
#define ERROR_INVALID_HANDLE 6
#define ERROR_NOT_ENOUGH_MEMORY 8
#define ERROR_NO_MORE_FILES 18
#define ERROR_NO_MORE_ITEMS 259
#define ERROR_FILE_EXISTS 80
#define ERROR_READ_FAULT 30
#define ERROR_HANDLE_EOF 38