cl.exe works! but I didn't review most of this code

This commit is contained in:
Luke Street 2025-09-26 17:38:24 -06:00
parent b4ea1da959
commit f23224bbcc
9 changed files with 1658 additions and 84 deletions

View File

@ -24,6 +24,7 @@ add_executable(wibo
dll/mscoree.cpp
dll/msvcrt.cpp
dll/ntdll.cpp
dll/rpcrt4.cpp
dll/ole32.cpp
dll/user32.cpp
dll/vcruntime.cpp

View File

@ -64,6 +64,7 @@ typedef unsigned char BYTE;
#define ERROR_INVALID_PARAMETER 87
#define ERROR_BUFFER_OVERFLOW 111
#define ERROR_INSUFFICIENT_BUFFER 122
#define ERROR_NONE_MAPPED 1332
#define ERROR_RESOURCE_DATA_NOT_FOUND 1812
#define ERROR_RESOURCE_TYPE_NOT_FOUND 1813
#define ERROR_RESOURCE_NAME_NOT_FOUND 1814
@ -72,6 +73,7 @@ typedef unsigned char BYTE;
#define ERROR_NEGATIVE_SEEK 131
#define ERROR_BAD_EXE_FORMAT 193
#define ERROR_ALREADY_EXISTS 183
#define ERROR_NOT_OWNER 288
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
#define INVALID_HANDLE_VALUE ((HANDLE)-1)

View File

@ -1,5 +1,287 @@
#include "common.h"
#include "handles.h"
#include <sys/random.h>
#include <cwchar>
#include <vector>
namespace {
using ALG_ID = unsigned int;
constexpr ALG_ID CALG_MD5 = 0x00008003;
constexpr ALG_ID CALG_SHA1 = 0x00008004;
constexpr DWORD HP_ALGID = 0x00000001;
constexpr DWORD HP_HASHVAL = 0x00000002;
constexpr DWORD HP_HASHSIZE = 0x00000004;
struct HashObject {
ALG_ID algid = 0;
std::vector<uint8_t> data;
std::vector<uint8_t> digest;
bool digestComputed = false;
};
struct TokenObject {
HANDLE processHandle = nullptr;
DWORD desiredAccess = 0;
};
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 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;
};
static inline uint32_t leftRotate(uint32_t value, uint32_t bits) {
return (value << bits) | (value >> (32 - bits));
}
static std::vector<uint8_t> computeMD5(const std::vector<uint8_t> &input) {
static const uint32_t s[64] = {
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
};
static const uint32_t K[64] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};
std::vector<uint8_t> data = input;
uint64_t bitLen = static_cast<uint64_t>(data.size()) * 8ULL;
data.push_back(0x80);
while ((data.size() % 64) != 56) {
data.push_back(0);
}
for (int i = 0; i < 8; ++i) {
data.push_back(static_cast<uint8_t>((bitLen >> (8 * i)) & 0xFF));
}
uint32_t A = 0x67452301;
uint32_t B = 0xEFCDAB89;
uint32_t C = 0x98BADCFE;
uint32_t D = 0x10325476;
for (size_t offset = 0; offset < data.size(); offset += 64) {
uint32_t M[16];
for (int i = 0; i < 16; ++i) {
M[i] = static_cast<uint32_t>(data[offset + i * 4]) |
(static_cast<uint32_t>(data[offset + i * 4 + 1]) << 8) |
(static_cast<uint32_t>(data[offset + i * 4 + 2]) << 16) |
(static_cast<uint32_t>(data[offset + i * 4 + 3]) << 24);
}
uint32_t a = A;
uint32_t b = B;
uint32_t c = C;
uint32_t d = D;
for (int i = 0; i < 64; ++i) {
uint32_t F;
int g;
if (i < 16) {
F = (b & c) | ((~b) & d);
g = i;
} else if (i < 32) {
F = (d & b) | ((~d) & c);
g = (5 * i + 1) % 16;
} else if (i < 48) {
F = b ^ c ^ d;
g = (3 * i + 5) % 16;
} else {
F = c ^ (b | (~d));
g = (7 * i) % 16;
}
uint32_t temp = d;
d = c;
c = b;
uint32_t rotateVal = a + F + K[i] + M[g];
b = b + leftRotate(rotateVal, s[i]);
a = temp;
}
A += a;
B += b;
C += c;
D += d;
}
std::vector<uint8_t> digest(16);
uint32_t output[4] = {A, B, C, D};
for (int i = 0; i < 4; ++i) {
digest[i * 4] = static_cast<uint8_t>(output[i] & 0xFF);
digest[i * 4 + 1] = static_cast<uint8_t>((output[i] >> 8) & 0xFF);
digest[i * 4 + 2] = static_cast<uint8_t>((output[i] >> 16) & 0xFF);
digest[i * 4 + 3] = static_cast<uint8_t>((output[i] >> 24) & 0xFF);
}
return digest;
}
static std::vector<uint8_t> computeSHA1(const std::vector<uint8_t> &input) {
std::vector<uint8_t> data = input;
uint64_t bitLen = static_cast<uint64_t>(data.size()) * 8ULL;
data.push_back(0x80);
while ((data.size() % 64) != 56) {
data.push_back(0);
}
for (int i = 7; i >= 0; --i) {
data.push_back(static_cast<uint8_t>((bitLen >> (8 * i)) & 0xFF));
}
uint32_t h0 = 0x67452301;
uint32_t h1 = 0xEFCDAB89;
uint32_t h2 = 0x98BADCFE;
uint32_t h3 = 0x10325476;
uint32_t h4 = 0xC3D2E1F0;
for (size_t offset = 0; offset < data.size(); offset += 64) {
uint32_t w[80];
for (int i = 0; i < 16; ++i) {
w[i] = (static_cast<uint32_t>(data[offset + i * 4]) << 24) |
(static_cast<uint32_t>(data[offset + i * 4 + 1]) << 16) |
(static_cast<uint32_t>(data[offset + i * 4 + 2]) << 8) |
static_cast<uint32_t>(data[offset + i * 4 + 3]);
}
for (int i = 16; i < 80; ++i) {
w[i] = leftRotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
}
uint32_t a = h0;
uint32_t b = h1;
uint32_t c = h2;
uint32_t d = h3;
uint32_t e = h4;
for (int i = 0; i < 80; ++i) {
uint32_t f;
uint32_t k;
if (i < 20) {
f = (b & c) | ((~b) & d);
k = 0x5A827999;
} else if (i < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
uint32_t temp = leftRotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = leftRotate(b, 30);
b = a;
a = temp;
}
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
std::vector<uint8_t> digest(20);
uint32_t output[5] = {h0, h1, h2, h3, h4};
for (int i = 0; i < 5; ++i) {
digest[i * 4] = static_cast<uint8_t>((output[i] >> 24) & 0xFF);
digest[i * 4 + 1] = static_cast<uint8_t>((output[i] >> 16) & 0xFF);
digest[i * 4 + 2] = static_cast<uint8_t>((output[i] >> 8) & 0xFF);
digest[i * 4 + 3] = static_cast<uint8_t>(output[i] & 0xFF);
}
return digest;
}
static bool computeDigest(HashObject &hash) {
if (hash.digestComputed) {
return true;
}
switch (hash.algid) {
case CALG_MD5:
hash.digest = computeMD5(hash.data);
hash.digestComputed = true;
return true;
case CALG_SHA1:
hash.digest = computeSHA1(hash.data);
hash.digestComputed = true;
return true;
default:
return false;
}
}
}
namespace advapi32 {
unsigned int WIN_FUNC RegOpenKeyExA(void *hKey, const char *lpSubKey, unsigned int ulOptions, void *samDesired, void **phkResult) {
@ -36,6 +318,262 @@ namespace advapi32 {
return TRUE;
}
BOOL WIN_FUNC CryptCreateHash(void* hProv, unsigned int Algid, void* hKey, unsigned int dwFlags, void** phHash) {
DEBUG_LOG("CryptCreateHash(Algid=0x%x)\n", Algid);
(void)hProv;
if (!phHash) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (dwFlags != 0) {
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
if (hKey != nullptr) {
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
if (Algid != CALG_MD5 && Algid != CALG_SHA1) {
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
auto *hash = new HashObject;
hash->algid = Algid;
hash->digestComputed = false;
hash->data.clear();
hash->digest.clear();
*phHash = hash;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC CryptHashData(void* hHash, const unsigned char* pbData, unsigned int dwDataLen, unsigned int dwFlags) {
DEBUG_LOG("CryptHashData(%p, %u bytes)\n", hHash, dwDataLen);
if (!hHash || (dwDataLen && !pbData) || dwFlags != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *hash = reinterpret_cast<HashObject *>(hHash);
if (pbData && dwDataLen) {
hash->data.insert(hash->data.end(), pbData, pbData + dwDataLen);
hash->digestComputed = false;
hash->digest.clear();
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC CryptGetHashParam(void* hHash, unsigned int dwParam, unsigned char* pbData, unsigned int* pdwDataLen, unsigned int dwFlags) {
DEBUG_LOG("CryptGetHashParam(%p, param=0x%x)\n", hHash, dwParam);
if (!hHash || !pdwDataLen || dwFlags != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
auto *hash = reinterpret_cast<HashObject *>(hHash);
switch (dwParam) {
case HP_ALGID: {
unsigned int required = sizeof(ALG_ID);
if (!pbData) {
*pdwDataLen = required;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (*pdwDataLen < required) {
*pdwDataLen = required;
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
memcpy(pbData, &hash->algid, required);
*pdwDataLen = required;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
case HP_HASHSIZE: {
unsigned int size = 0;
switch (hash->algid) {
case CALG_MD5:
size = 16;
break;
case CALG_SHA1:
size = 20;
break;
default:
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
if (!pbData) {
*pdwDataLen = sizeof(unsigned int);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (*pdwDataLen < sizeof(unsigned int)) {
*pdwDataLen = sizeof(unsigned int);
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
memcpy(pbData, &size, sizeof(unsigned int));
*pdwDataLen = sizeof(unsigned int);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
case HP_HASHVAL: {
if (!computeDigest(*hash)) {
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
unsigned int required = hash->digest.size();
if (!pbData) {
*pdwDataLen = required;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
if (*pdwDataLen < required) {
*pdwDataLen = required;
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
memcpy(pbData, hash->digest.data(), required);
*pdwDataLen = required;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
default:
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
}
BOOL WIN_FUNC CryptDestroyHash(void* hHash) {
DEBUG_LOG("CryptDestroyHash(%p)\n", hHash);
if (!hHash) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
delete reinterpret_cast<HashObject *>(hHash);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, HANDLE *TokenHandle) {
DEBUG_LOG("OpenProcessToken(process=%p, access=0x%x)\n", ProcessHandle, DesiredAccess);
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, class=%u, len=%u)\n", TokenHandle, TokenInformationClass, TokenInformationLength);
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
if (TokenInformationClass == TokenUserClass) {
constexpr size_t sidSize = sizeof(Sid);
constexpr size_t tokenUserSize = sizeof(TokenUserData);
const unsigned int 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);
memset(stats, 0, required);
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;
}
wibo::lastError = ERROR_NOT_SUPPORTED;
return FALSE;
}
BOOL WIN_FUNC LookupAccountSidW(const wchar_t *lpSystemName, const void *sidPointer, wchar_t *Name, unsigned long *cchName, wchar_t *ReferencedDomainName, unsigned long *cchReferencedDomainName, SID_NAME_USE *peUse) {
DEBUG_LOG("LookupAccountSidW(system=%ls, sid=%p)\n", lpSystemName ? lpSystemName : L"(null)", sidPointer);
(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;
}
const wchar_t *accountName = L"SYSTEM";
const wchar_t *domainName = L"NT AUTHORITY";
unsigned long requiredAccount = static_cast<unsigned long>(std::wcslen(accountName) + 1);
unsigned long requiredDomain = static_cast<unsigned long>(std::wcslen(domainName) + 1);
if (!Name || *cchName < requiredAccount || !ReferencedDomainName || *cchReferencedDomainName < requiredDomain) {
*cchName = requiredAccount;
*cchReferencedDomainName = requiredDomain;
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
std::wmemcpy(Name, accountName, requiredAccount);
std::wmemcpy(ReferencedDomainName, domainName, requiredDomain);
*peUse = SidTypeWellKnownGroup;
*cchName = requiredAccount - 1;
*cchReferencedDomainName = requiredDomain - 1;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
}
static void *resolveByName(const char *name) {
@ -43,6 +581,13 @@ static void *resolveByName(const char *name) {
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;
return nullptr;
}

View File

@ -9,6 +9,7 @@
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <cwctype>
#include <filesystem>
#include <fnmatch.h>
#include <string>
@ -19,6 +20,7 @@
#include <stdarg.h>
#include <system_error>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/wait.h>
@ -26,8 +28,56 @@
#include <unistd.h>
#include <vector>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#include <mutex>
#include <unordered_map>
namespace advapi32 {
void releaseToken(void *tokenPtr);
}
namespace {
struct MappingObject;
struct ViewInfo {
void *mapBase = nullptr;
size_t mapLength = 0;
MappingObject *owner = nullptr;
};
struct MappingObject {
int fd = -1;
size_t maxSize = 0;
unsigned int protect = 0;
bool anonymous = false;
bool closed = false;
size_t refCount = 0;
};
void closeMappingIfPossible(MappingObject *mapping);
void tryReleaseMapping(MappingObject *mapping);
std::unordered_map<void *, ViewInfo> g_viewInfo;
void closeMappingIfPossible(MappingObject *mapping) {
if (!mapping) {
return;
}
if (mapping->fd != -1) {
close(mapping->fd);
mapping->fd = -1;
}
delete mapping;
}
void tryReleaseMapping(MappingObject *mapping) {
if (!mapping) {
return;
}
if (mapping->closed && mapping->refCount == 0) {
closeMappingIfPossible(mapping);
}
}
using DWORD_PTR = uintptr_t;
constexpr WORD PROCESSOR_ARCHITECTURE_INTEL = 0;
@ -107,6 +157,44 @@ namespace kernel32 {
return ret;
}
struct MutexObject {
pthread_mutex_t mutex;
bool ownerValid = false;
pthread_t owner = 0;
unsigned int recursionCount = 0;
std::u16string name;
int refCount = 1;
};
static std::mutex mutexRegistryLock;
static std::unordered_map<std::u16string, MutexObject *> namedMutexes;
static std::u16string makeMutexName(LPCWSTR name) {
if (!name) {
return std::u16string();
}
size_t len = wstrlen(reinterpret_cast<const uint16_t *>(name));
return std::u16string(reinterpret_cast<const char16_t *>(name), len);
}
static void releaseMutexObject(MutexObject *obj) {
if (!obj) {
return;
}
std::lock_guard<std::mutex> lock(mutexRegistryLock);
obj->refCount--;
if (obj->refCount == 0) {
if (!obj->name.empty()) {
auto it = namedMutexes.find(obj->name);
if (it != namedMutexes.end() && it->second == obj) {
namedMutexes.erase(it);
}
}
pthread_mutex_destroy(&obj->mutex);
delete obj;
}
}
static int doCompareString(const std::string &a, const std::string &b, unsigned int dwCmpFlags) {
for (size_t i = 0; ; i++) {
if (i == a.size()) {
@ -173,6 +261,28 @@ namespace kernel32 {
wibo::lastError = dwErrCode;
}
BOOL WIN_FUNC Wow64DisableWow64FsRedirection(void **OldValue) {
DEBUG_LOG("Wow64DisableWow64FsRedirection\n");
if (OldValue) {
*OldValue = nullptr;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC Wow64RevertWow64FsRedirection(void *OldValue) {
DEBUG_LOG("Wow64RevertWow64FsRedirection\n");
(void) OldValue;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
void WIN_FUNC RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG_PTR *lpArguments) {
DEBUG_LOG("RaiseException(code=0x%x, flags=0x%x, args=%u)\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments);
(void)lpArguments;
exit(static_cast<int>(dwExceptionCode));
}
PVOID WIN_FUNC AddVectoredExceptionHandler(ULONG first, PVECTORED_EXCEPTION_HANDLER handler) {
DEBUG_LOG("STUB: AddVectoredExceptionHandler(%u, %p)\n", first, handler);
return (PVOID)handler;
@ -374,30 +484,107 @@ namespace kernel32 {
return 1;
}
BOOL WIN_FUNC CreateProcessW(
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
void *lpProcessAttributes,
void *lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
void *lpStartupInfo,
PROCESS_INFORMATION *lpProcessInformation
) {
std::string applicationUtf8;
if (lpApplicationName) {
applicationUtf8 = wideStringToString(lpApplicationName);
}
std::string commandUtf8;
if (lpCommandLine) {
commandUtf8 = wideStringToString(lpCommandLine);
}
std::string directoryUtf8;
if (lpCurrentDirectory) {
directoryUtf8 = wideStringToString(lpCurrentDirectory);
}
DEBUG_LOG("CreateProcessW %s \"%s\" %p %p %d 0x%x %p %s %p %p\n",
applicationUtf8.empty() ? "<null>" : applicationUtf8.c_str(),
commandUtf8.empty() ? "<null>" : commandUtf8.c_str(),
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
directoryUtf8.empty() ? "<none>" : directoryUtf8.c_str(),
lpStartupInfo,
lpProcessInformation
);
std::vector<char> commandBuffer;
if (!commandUtf8.empty()) {
commandBuffer.assign(commandUtf8.begin(), commandUtf8.end());
commandBuffer.push_back('\0');
}
LPSTR commandPtr = commandBuffer.empty() ? nullptr : commandBuffer.data();
LPCSTR applicationPtr = applicationUtf8.empty() ? nullptr : applicationUtf8.c_str();
LPCSTR directoryPtr = directoryUtf8.empty() ? nullptr : directoryUtf8.c_str();
return CreateProcessA(
applicationPtr,
commandPtr,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
directoryPtr,
lpStartupInfo,
lpProcessInformation
);
}
unsigned int WIN_FUNC WaitForSingleObject(void *hHandle, unsigned int dwMilliseconds) {
DEBUG_LOG("WaitForSingleObject (%u)\n", dwMilliseconds);
// TODO - wait on other objects?
// TODO: wait for less than forever
assert(dwMilliseconds == 0xffffffff);
processes::Process* process = processes::processFromHandle(hHandle, false);
int status;
waitpid(process->pid, &status, 0);
if (WIFEXITED(status)) {
process->exitCode = WEXITSTATUS(status);
} else {
// If we're here, *something* has caused our child process to exit abnormally
// Specific exit codes don't really map onto any of these situations - we just know it's bad.
// Specify a non-zero exit code to alert our parent process something's gone wrong.
DEBUG_LOG("WaitForSingleObject: Child process exited abnormally - returning exit code 1.");
process->exitCode = 1;
handles::Data data = handles::dataFromHandle(hHandle, false);
switch (data.type) {
case handles::TYPE_PROCESS: {
// TODO: wait for less than forever
assert(dwMilliseconds == 0xffffffff);
processes::Process *process = reinterpret_cast<processes::Process *>(data.ptr);
int status;
waitpid(process->pid, &status, 0);
if (WIFEXITED(status)) {
process->exitCode = WEXITSTATUS(status);
} else {
DEBUG_LOG("WaitForSingleObject: Child process exited abnormally - returning exit code 1.\n");
process->exitCode = 1;
}
wibo::lastError = ERROR_SUCCESS;
return 0;
}
case handles::TYPE_MUTEX: {
MutexObject *obj = reinterpret_cast<MutexObject *>(data.ptr);
if (dwMilliseconds != 0xffffffff) {
DEBUG_LOG("WaitForSingleObject: timeout for mutex not supported\n");
wibo::lastError = ERROR_NOT_SUPPORTED;
return 0xFFFFFFFF;
}
pthread_mutex_lock(&obj->mutex);
pthread_t self = pthread_self();
if (obj->ownerValid && pthread_equal(obj->owner, self)) {
obj->recursionCount++;
} else {
obj->owner = self;
obj->ownerValid = true;
obj->recursionCount = 1;
}
wibo::lastError = ERROR_SUCCESS;
return 0;
}
default:
DEBUG_LOG("WaitForSingleObject: unsupported handle type %d\n", data.type);
wibo::lastError = ERROR_INVALID_HANDLE;
return 0xFFFFFFFF;
}
return 0;
}
int WIN_FUNC GetSystemDefaultLangID() {
@ -680,12 +867,18 @@ namespace kernel32 {
if (!(fp == stdin || fp == stdout || fp == stderr)) {
fclose(fp);
}
} else if (data.type == handles::TYPE_MAPPED) {
if (data.ptr != (void *) 0x1) {
munmap(data.ptr, data.size);
}
} else if (data.type == handles::TYPE_PROCESS) {
} else if (data.type == handles::TYPE_MAPPED) {
auto *mapping = reinterpret_cast<MappingObject *>(data.ptr);
if (mapping) {
mapping->closed = true;
tryReleaseMapping(mapping);
}
} else if (data.type == handles::TYPE_PROCESS) {
delete (processes::Process*) data.ptr;
} else if (data.type == handles::TYPE_TOKEN) {
advapi32::releaseToken(data.ptr);
} else if (data.type == handles::TYPE_MUTEX) {
releaseMutexObject(reinterpret_cast<MutexObject *>(data.ptr));
}
return TRUE;
}
@ -717,21 +910,37 @@ namespace kernel32 {
}
DWORD WIN_FUNC GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart) {
const auto fileName = wideStringToString(lpFileName);
DEBUG_LOG("GetFullPathNameW(%s) ", fileName.c_str());
std::string narrowName = wideStringToString(lpFileName);
DEBUG_LOG("GetFullPathNameW(%s) ", narrowName.c_str());
const auto lpFileNameA = wideStringToString(lpFileName);
std::filesystem::path absPath = std::filesystem::absolute(files::pathFromWindows(lpFileNameA.c_str()));
std::filesystem::path absPath = std::filesystem::absolute(files::pathFromWindows(narrowName.c_str()));
std::string absStr = files::pathToWindows(absPath);
const auto absStrW = stringToWideString(absStr.c_str());
auto absStrW = stringToWideString(absStr.c_str());
DEBUG_LOG("-> %s\n", absStr.c_str());
const auto len = wstrlen(absStrW.data());
if (nBufferLength < len + 1) {
size_t len = wstrlen(absStrW.data());
if (nBufferLength == 0 || nBufferLength <= len) {
if (lpFilePart) {
*lpFilePart = nullptr;
}
return len + 1;
}
wstrncpy(lpBuffer, absStrW.data(), len + 1);
assert(!lpFilePart);
if (lpFilePart) {
*lpFilePart = nullptr;
std::error_code ec;
bool pathIsDir = std::filesystem::is_directory(absPath, ec) && !ec;
if (!pathIsDir) {
uint16_t *lastSlash = wstrrchr(lpBuffer, '\\');
if (lastSlash && *(lastSlash + 1) != 0) {
*lpFilePart = lastSlash + 1;
} else if (!lastSlash && len > 0) {
*lpFilePart = lpBuffer;
}
}
}
wibo::lastError = ERROR_SUCCESS;
return len;
}
@ -759,6 +968,21 @@ namespace kernel32 {
}
}
DWORD WIN_FUNC GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer) {
std::string longPath = wideStringToString(lpszLongPath);
DEBUG_LOG("GetShortPathNameW(%s)\n", longPath.c_str());
std::filesystem::path absPath = std::filesystem::absolute(files::pathFromWindows(longPath.c_str()));
std::string absStr = files::pathToWindows(absPath);
auto absStrW = stringToWideString(absStr.c_str());
size_t len = wstrlen(absStrW.data());
if (cchBuffer == 0 || cchBuffer <= len) {
return len + 1;
}
wstrncpy(lpszShortPath, absStrW.data(), len + 1);
wibo::lastError = ERROR_SUCCESS;
return len;
}
using random_shorts_engine = std::independent_bits_engine<std::default_random_engine, sizeof(unsigned short) * 8, unsigned short>;
unsigned int WIN_FUNC GetTempFileNameA(LPSTR lpPathName, LPSTR lpPrefixString, unsigned int uUnique, LPSTR lpTempFileName) {
@ -826,6 +1050,29 @@ namespace kernel32 {
(unsigned int)(UNIX_TIME_ZERO >> 32)
};
static FILETIME fileTimeFromDuration(uint64_t ticks100ns) {
FILETIME result;
result.dwLowDateTime = (unsigned int)(ticks100ns & 0xFFFFFFFF);
result.dwHighDateTime = (unsigned int)(ticks100ns >> 32);
return result;
}
static FILETIME fileTimeFromTimeval(const struct timeval &value) {
uint64_t total = 0;
if (value.tv_sec > 0 || value.tv_usec > 0) {
total = (uint64_t)value.tv_sec * 10000000ULL + (uint64_t)value.tv_usec * 10ULL;
}
return fileTimeFromDuration(total);
}
static FILETIME fileTimeFromTimespec(const struct timespec &value) {
uint64_t total = 0;
if (value.tv_sec > 0 || value.tv_nsec > 0) {
total = (uint64_t)value.tv_sec * 10000000ULL + (uint64_t)value.tv_nsec / 100ULL;
}
return fileTimeFromDuration(total);
}
template<typename CharType>
struct WIN32_FIND_DATA {
uint32_t dwFileAttributes;
@ -1227,62 +1474,219 @@ namespace kernel32 {
unsigned int dwMaximumSizeHigh,
unsigned int dwMaximumSizeLow,
const char *lpName) {
DEBUG_LOG("CreateFileMappingA(%p, %p, %u, %u, %u, %s)\n", hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
DEBUG_LOG("CreateFileMappingA(%p, %p, %u, %u, %u, %s)\n", hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ? lpName : "(null)");
(void) lpFileMappingAttributes;
(void) lpName;
int64_t size = (int64_t) dwMaximumSizeHigh << 32 | dwMaximumSizeLow;
auto mapping = new MappingObject();
mapping->protect = flProtect;
void *mmapped;
if (hFile == (void*) -1) { // INVALID_HANDLE_VALUE
if (size == 0) {
mmapped = (void *) 0x1;
} else {
mmapped = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
}
} else {
int fd = fileno(files::fpFromHandle(hFile));
if (size == 0) {
size = getFileSize(hFile);
if (size == -1) {
return (void*) -1;
}
}
if (size == 0) {
mmapped = (void *) 0x1;
} else {
mmapped = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
}
uint64_t size = ((uint64_t) dwMaximumSizeHigh << 32) | dwMaximumSizeLow;
if (flProtect != 0x02 /* PAGE_READONLY */ && flProtect != 0x04 /* PAGE_READWRITE */ && flProtect != 0x08 /* PAGE_WRITECOPY */) {
DEBUG_LOG("CreateFileMappingA: unsupported protection 0x%x\n", flProtect);
wibo::lastError = ERROR_INVALID_PARAMETER;
closeMappingIfPossible(mapping);
return nullptr;
}
assert(mmapped != MAP_FAILED);
return handles::allocDataHandle({handles::TYPE_MAPPED, mmapped, (unsigned int) size});
if (hFile == (void *) -1) {
mapping->anonymous = true;
mapping->fd = -1;
if (size == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
closeMappingIfPossible(mapping);
return nullptr;
}
mapping->maxSize = size;
} else {
FILE *fp = files::fpFromHandle(hFile);
if (!fp) {
wibo::lastError = ERROR_INVALID_HANDLE;
closeMappingIfPossible(mapping);
return nullptr;
}
int originalFd = fileno(fp);
if (originalFd == -1) {
setLastErrorFromErrno();
closeMappingIfPossible(mapping);
return nullptr;
}
int dupFd = fcntl(originalFd, F_DUPFD_CLOEXEC, 0);
if (dupFd == -1) {
setLastErrorFromErrno();
closeMappingIfPossible(mapping);
return nullptr;
}
mapping->fd = dupFd;
if (size == 0) {
int64_t fileSize = getFileSize(hFile);
if (fileSize < 0) {
closeMappingIfPossible(mapping);
return nullptr;
}
size = static_cast<uint64_t>(fileSize);
}
mapping->maxSize = size;
}
wibo::lastError = ERROR_SUCCESS;
return handles::allocDataHandle({handles::TYPE_MAPPED, mapping, static_cast<size_t>(mapping->maxSize)});
}
void *WIN_FUNC CreateFileMappingW(
void *hFile,
void *lpFileMappingAttributes,
unsigned int flProtect,
unsigned int dwMaximumSizeHigh,
unsigned int dwMaximumSizeLow,
const uint16_t *lpName) {
std::string name = wideStringToString(lpName);
return CreateFileMappingA(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName ? name.c_str() : nullptr);
}
constexpr unsigned int FILE_MAP_COPY = 0x00000001;
constexpr unsigned int FILE_MAP_WRITE = 0x00000002;
constexpr unsigned int FILE_MAP_READ = 0x00000004;
constexpr unsigned int FILE_MAP_EXECUTE = 0x00000020;
void *WIN_FUNC MapViewOfFile(
void *hFileMappingObject,
unsigned int dwDesiredAccess,
unsigned int dwFileOffsetHigh,
unsigned int dwFileOffsetLow,
unsigned int dwNumberOfBytesToMap) {
DEBUG_LOG("MapViewOfFile(%p, %u, %u, %u, %u)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap);
DEBUG_LOG("MapViewOfFile(%p, 0x%x, %u, %u, %u)\n", hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap);
handles::Data data = handles::dataFromHandle(hFileMappingObject, false);
assert(data.type == handles::TYPE_MAPPED);
return (void*)((unsigned int) data.ptr + dwFileOffsetLow);
if (data.type != handles::TYPE_MAPPED) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
auto *mapping = reinterpret_cast<MappingObject *>(data.ptr);
if (!mapping) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
if (mapping->closed) {
wibo::lastError = ERROR_INVALID_HANDLE;
return nullptr;
}
uint64_t offset = ((uint64_t) dwFileOffsetHigh << 32) | dwFileOffsetLow;
if (mapping->anonymous && offset != 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
size_t maxSize = mapping->maxSize;
uint64_t length = dwNumberOfBytesToMap;
if (length == 0) {
if (maxSize == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
if (offset > maxSize) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
length = maxSize - offset;
}
if (length == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
if (maxSize && offset + length > maxSize) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
int prot = PROT_READ;
bool wantWrite = (dwDesiredAccess & FILE_MAP_WRITE) != 0;
bool wantExecute = (dwDesiredAccess & FILE_MAP_EXECUTE) != 0;
if (mapping->protect == 0x04 /* PAGE_READWRITE */) {
if (wantWrite) {
prot |= PROT_WRITE;
}
} else { // read-only or write copy
if (wantWrite && !(dwDesiredAccess & FILE_MAP_COPY)) {
wibo::lastError = ERROR_ACCESS_DENIED;
return nullptr;
}
}
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));
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 - alignedOffset);
size_t mapLength = static_cast<size_t>(length + offsetDelta);
if (mapLength < length) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return nullptr;
}
int mmapFd = mapping->anonymous ? -1 : mapping->fd;
void *mapBase = mmap(nullptr, mapLength, prot, flags, mmapFd, alignedOffset);
if (mapBase == MAP_FAILED) {
setLastErrorFromErrno();
return nullptr;
}
void *viewPtr = static_cast<uint8_t *>(mapBase) + offsetDelta;
g_viewInfo[viewPtr] = ViewInfo{mapBase, mapLength, mapping};
mapping->refCount++;
wibo::lastError = ERROR_SUCCESS;
return viewPtr;
}
int WIN_FUNC UnmapViewOfFile(void *lpBaseAddress) {
DEBUG_LOG("UnmapViewOfFile(%p)\n", lpBaseAddress);
auto it = g_viewInfo.find(lpBaseAddress);
if (it == g_viewInfo.end()) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return 0;
}
ViewInfo info = it->second;
g_viewInfo.erase(it);
if (info.mapBase && info.mapLength) {
munmap(info.mapBase, info.mapLength);
}
if (info.owner && info.owner->refCount > 0) {
info.owner->refCount--;
tryReleaseMapping(info.owner);
}
wibo::lastError = ERROR_SUCCESS;
return 1;
}
int WIN_FUNC DeleteFileA(const char* lpFileName) {
BOOL WIN_FUNC DeleteFileA(const char* lpFileName) {
if (!lpFileName) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
std::string path = files::pathFromWindows(lpFileName);
DEBUG_LOG("DeleteFileA %s (%s)\n", lpFileName, path.c_str());
unlink(path.c_str());
return 1;
if (unlink(path.c_str()) == 0) {
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
setLastErrorFromErrno();
return FALSE;
}
BOOL WIN_FUNC DeleteFileW(const uint16_t *lpFileName) {
if (!lpFileName) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
std::string name = wideStringToString(lpFileName);
return DeleteFileA(name.c_str());
}
DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
@ -2159,6 +2563,132 @@ namespace kernel32 {
return S_OK;
}
HANDLE WIN_FUNC CreateMutexW(void *lpMutexAttributes, BOOL bInitialOwner, LPCWSTR lpName) {
std::string nameLog;
if (lpName) {
nameLog = wideStringToString(reinterpret_cast<const uint16_t *>(lpName));
} else {
nameLog = "<unnamed>";
}
DEBUG_LOG("CreateMutexW(name=%s, initialOwner=%d)\n", nameLog.c_str(), bInitialOwner);
(void)lpMutexAttributes;
std::u16string name = makeMutexName(lpName);
MutexObject *obj = nullptr;
bool alreadyExists = false;
{
std::lock_guard<std::mutex> lock(mutexRegistryLock);
if (!name.empty()) {
auto it = namedMutexes.find(name);
if (it != namedMutexes.end()) {
obj = it->second;
obj->refCount++;
alreadyExists = true;
}
}
if (!obj) {
obj = new MutexObject();
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&obj->mutex, &attr);
pthread_mutexattr_destroy(&attr);
obj->ownerValid = false;
obj->recursionCount = 0;
obj->name = name;
obj->refCount = 1;
if (!name.empty()) {
namedMutexes[name] = obj;
}
}
}
if (!alreadyExists && bInitialOwner) {
pthread_mutex_lock(&obj->mutex);
obj->owner = pthread_self();
obj->ownerValid = true;
obj->recursionCount = 1;
}
HANDLE handle = handles::allocDataHandle({handles::TYPE_MUTEX, obj, 0});
wibo::lastError = alreadyExists ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS;
return handle;
}
BOOL WIN_FUNC ReleaseMutex(HANDLE hMutex) {
DEBUG_LOG("ReleaseMutex(%p)\n", hMutex);
auto data = handles::dataFromHandle(hMutex, false);
if (data.type != handles::TYPE_MUTEX) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
auto *obj = reinterpret_cast<MutexObject *>(data.ptr);
pthread_t self = pthread_self();
if (!obj->ownerValid || !pthread_equal(obj->owner, self)) {
wibo::lastError = ERROR_NOT_OWNER;
return FALSE;
}
if (obj->recursionCount > 0) {
obj->recursionCount--;
}
if (obj->recursionCount == 0) {
obj->ownerValid = false;
}
pthread_mutex_unlock(&obj->mutex);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
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);
if (!lpKernelTime || !lpUserTime) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
bool isPseudoCurrentThread = hThread == (HANDLE)0x100007 || hThread == (HANDLE)0xFFFFFFFE || hThread == (HANDLE)0 || hThread == (HANDLE)0xFFFFFFFF;
if (!isPseudoCurrentThread) {
DEBUG_LOG("GetThreadTimes: unsupported handle %p\n", hThread);
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
if (lpCreationTime) {
*lpCreationTime = defaultFiletime;
}
if (lpExitTime) {
lpExitTime->dwLowDateTime = 0;
lpExitTime->dwHighDateTime = 0;
}
struct rusage usage;
if (getrusage(RUSAGE_THREAD, &usage) == 0) {
*lpKernelTime = fileTimeFromTimeval(usage.ru_stime);
*lpUserTime = fileTimeFromTimeval(usage.ru_utime);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
struct timespec cpuTime;
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &cpuTime) == 0) {
*lpKernelTime = fileTimeFromDuration(0);
*lpUserTime = fileTimeFromTimespec(cpuTime);
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
setLastErrorFromErrno();
*lpKernelTime = fileTimeFromDuration(0);
*lpUserTime = fileTimeFromDuration(0);
return FALSE;
}
unsigned short WIN_FUNC GetFileType(void *hFile) {
DEBUG_LOG("GetFileType %p\n", hFile);
return 1; // FILE_TYPE_DISK
@ -2529,13 +3059,61 @@ namespace kernel32 {
return FALSE; // We're not multibyte (yet?)
}
constexpr unsigned int LCMAP_LOWERCASE = 0x00000100;
constexpr unsigned int LCMAP_UPPERCASE = 0x00000200;
constexpr unsigned int LCMAP_SORTKEY = 0x00000400;
constexpr unsigned int LCMAP_BYTEREV = 0x00000800;
constexpr unsigned int LCMAP_LINGUISTIC_CASING = 0x01000000;
int WIN_FUNC LCMapStringW(int Locale, unsigned int dwMapFlags, const uint16_t* lpSrcStr, int cchSrc, uint16_t* lpDestStr, int cchDest) {
DEBUG_LOG("LCMapStringW: (locale=%i, flags=%u, src=%p, dest=%p)\n", Locale, dwMapFlags, cchSrc, cchDest);
if (cchSrc < 0) {
cchSrc = wstrlen(lpSrcStr) + 1;
DEBUG_LOG("LCMapStringW(locale=%i, flags=0x%x, src=%p, dest=%p, cchSrc=%d, cchDest=%d)\n", Locale, dwMapFlags, lpSrcStr, lpDestStr, cchSrc, cchDest);
(void) Locale;
if (!lpSrcStr || cchSrc == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return 0;
}
// DEBUG_LOG("lpSrcStr: %s\n", lpSrcStr);
return 1; // success
bool nullTerminated = cchSrc < 0;
size_t srcLen = nullTerminated ? (wstrlen(lpSrcStr) + 1) : static_cast<size_t>(cchSrc);
if (srcLen == 0) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return 0;
}
if (!lpDestStr || cchDest == 0) {
// Caller is asking for the required length.
wibo::lastError = ERROR_SUCCESS;
return static_cast<int>(srcLen);
}
if (cchDest < static_cast<int>(srcLen)) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return 0;
}
unsigned int casingFlags = dwMapFlags & (LCMAP_UPPERCASE | LCMAP_LOWERCASE);
unsigned int ignoredFlags = dwMapFlags & (LCMAP_LINGUISTIC_CASING);
(void) ignoredFlags;
if (dwMapFlags & (LCMAP_SORTKEY | LCMAP_BYTEREV)) {
DEBUG_LOG("LCMapStringW: unsupported mapping flags 0x%x\n", dwMapFlags);
wibo::lastError = ERROR_INVALID_PARAMETER;
return 0;
}
std::vector<uint16_t> buffer(srcLen, 0);
for (size_t i = 0; i < srcLen; ++i) {
uint16_t ch = lpSrcStr[i];
if (casingFlags == LCMAP_UPPERCASE) {
buffer[i] = static_cast<uint16_t>(std::towupper(static_cast<wint_t>(ch)));
} else if (casingFlags == LCMAP_LOWERCASE) {
buffer[i] = static_cast<uint16_t>(std::towlower(static_cast<wint_t>(ch)));
} else {
buffer[i] = ch;
}
}
std::memcpy(lpDestStr, buffer.data(), srcLen * sizeof(uint16_t));
wibo::lastError = ERROR_SUCCESS;
return static_cast<int>(srcLen);
}
int WIN_FUNC LCMapStringA(int Locale, unsigned int dwMapFlags, const char* lpSrcStr, int cchSrc, char* lpDestStr, int cchDest) {
@ -2592,17 +3170,31 @@ namespace kernel32 {
return len;
}
unsigned int WIN_FUNC SetEnvironmentVariableA(const char *lpName, const char *lpValue) {
DEBUG_LOG("SetEnvironmentVariableA: %s=%s\n", lpName, lpValue ? lpValue : "<null>");
if (!lpName) {
return 0;
BOOL WIN_FUNC SetEnvironmentVariableA(const char *lpName, const char *lpValue) {
DEBUG_LOG("SetEnvironmentVariableA: %s=%s\n", lpName ? lpName : "(null)", lpValue ? lpValue : "(null)");
if (!lpName || std::strchr(lpName, '=')) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
int rc = 0;
if (!lpValue) {
return unsetenv(lpName);
rc = unsetenv(lpName);
if (rc != 0) {
setLastErrorFromErrno();
return FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
std::string hostValue = convertEnvValueToHost(lpName, lpValue);
const char *valuePtr = hostValue.empty() ? lpValue : hostValue.c_str();
return setenv(lpName, valuePtr, 1 /* OVERWRITE */);
rc = setenv(lpName, valuePtr, 1 /* overwrite */);
if (rc != 0) {
setLastErrorFromErrno();
return FALSE;
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
DWORD WIN_FUNC GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize) {
@ -2623,6 +3215,16 @@ namespace kernel32 {
return len - 1;
}
BOOL WIN_FUNC SetEnvironmentVariableW(const uint16_t *lpName, const uint16_t *lpValue) {
if (!lpName) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
std::string name = wideStringToString(lpName);
std::string value = lpValue ? wideStringToString(lpValue) : std::string();
return SetEnvironmentVariableA(name.c_str(), lpValue ? value.c_str() : nullptr);
}
unsigned int WIN_FUNC QueryPerformanceCounter(unsigned long int *lpPerformanceCount) {
DEBUG_LOG("QueryPerformanceCounter\n");
*lpPerformanceCount = 0;
@ -2785,6 +3387,9 @@ static void *resolveByName(const char *name) {
// errhandlingapi.h
if (strcmp(name, "GetLastError") == 0) return (void *) kernel32::GetLastError;
if (strcmp(name, "SetLastError") == 0) return (void *) kernel32::SetLastError;
if (strcmp(name, "Wow64DisableWow64FsRedirection") == 0) return (void *) kernel32::Wow64DisableWow64FsRedirection;
if (strcmp(name, "Wow64RevertWow64FsRedirection") == 0) return (void *) kernel32::Wow64RevertWow64FsRedirection;
if (strcmp(name, "RaiseException") == 0) return (void *) kernel32::RaiseException;
if (strcmp(name, "AddVectoredExceptionHandler") == 0) return (void *) kernel32::AddVectoredExceptionHandler;
// processthreadsapi.h
@ -2794,6 +3399,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "GetCurrentThreadId") == 0) return (void *) kernel32::GetCurrentThreadId;
if (strcmp(name, "ExitProcess") == 0) return (void *) kernel32::ExitProcess;
if (strcmp(name, "GetExitCodeProcess") == 0) return (void *) kernel32::GetExitCodeProcess;
if (strcmp(name, "CreateProcessW") == 0) return (void *) kernel32::CreateProcessW;
if (strcmp(name, "CreateProcessA") == 0) return (void *) kernel32::CreateProcessA;
if (strcmp(name, "TlsAlloc") == 0) return (void *) kernel32::TlsAlloc;
if (strcmp(name, "TlsFree") == 0) return (void *) kernel32::TlsFree;
@ -2803,6 +3409,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "GetStartupInfoW") == 0) return (void *) kernel32::GetStartupInfoW;
if (strcmp(name, "SetThreadStackGuarantee") == 0) return (void *) kernel32::SetThreadStackGuarantee;
if (strcmp(name, "GetCurrentThread") == 0) return (void *) kernel32::GetCurrentThread;
if (strcmp(name, "GetThreadTimes") == 0) return (void *) kernel32::GetThreadTimes;
if (strcmp(name, "SetThreadDescription") == 0) return (void *) kernel32::SetThreadDescription;
// winnls.h
@ -2836,6 +3443,8 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "ReleaseSRWLockExclusive") == 0) return (void *) kernel32::ReleaseSRWLockExclusive;
if (strcmp(name, "TryAcquireSRWLockExclusive") == 0) return (void *) kernel32::TryAcquireSRWLockExclusive;
if (strcmp(name, "WaitForSingleObject") == 0) return (void *) kernel32::WaitForSingleObject;
if (strcmp(name, "CreateMutexW") == 0) return (void *) kernel32::CreateMutexW;
if (strcmp(name, "ReleaseMutex") == 0) return (void *) kernel32::ReleaseMutex;
// winbase.h
if (strcmp(name, "GlobalAlloc") == 0) return (void *) kernel32::GlobalAlloc;
@ -2867,6 +3476,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "FreeEnvironmentStringsW") == 0) return (void *) kernel32::FreeEnvironmentStringsW;
if (strcmp(name, "GetEnvironmentVariableA") == 0) return (void *) kernel32::GetEnvironmentVariableA;
if (strcmp(name, "SetEnvironmentVariableA") == 0) return (void *) kernel32::SetEnvironmentVariableA;
if (strcmp(name, "SetEnvironmentVariableW") == 0) return (void *) kernel32::SetEnvironmentVariableW;
if (strcmp(name, "GetEnvironmentVariableW") == 0) return (void *) kernel32::GetEnvironmentVariableW;
// console api
@ -2884,6 +3494,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "GetFullPathNameA") == 0) return (void *) kernel32::GetFullPathNameA;
if (strcmp(name, "GetFullPathNameW") == 0) return (void *) kernel32::GetFullPathNameW;
if (strcmp(name, "GetShortPathNameA") == 0) return (void *) kernel32::GetShortPathNameA;
if (strcmp(name, "GetShortPathNameW") == 0) return (void *) kernel32::GetShortPathNameW;
if (strcmp(name, "FindFirstFileA") == 0) return (void *) kernel32::FindFirstFileA;
if (strcmp(name, "FindFirstFileW") == 0) return (void *) kernel32::FindFirstFileW;
if (strcmp(name, "FindFirstFileExA") == 0) return (void *) kernel32::FindFirstFileExA;
@ -2896,9 +3507,11 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "CreateFileA") == 0) return (void *) kernel32::CreateFileA;
if (strcmp(name, "CreateFileW") == 0) return (void *) kernel32::CreateFileW;
if (strcmp(name, "CreateFileMappingA") == 0) return (void *) kernel32::CreateFileMappingA;
if (strcmp(name, "CreateFileMappingW") == 0) return (void *) kernel32::CreateFileMappingW;
if (strcmp(name, "MapViewOfFile") == 0) return (void *) kernel32::MapViewOfFile;
if (strcmp(name, "UnmapViewOfFile") == 0) return (void *) kernel32::UnmapViewOfFile;
if (strcmp(name, "DeleteFileA") == 0) return (void *) kernel32::DeleteFileA;
if (strcmp(name, "DeleteFileW") == 0) return (void *) kernel32::DeleteFileW;
if (strcmp(name, "SetFilePointer") == 0) return (void *) kernel32::SetFilePointer;
if (strcmp(name, "SetFilePointerEx") == 0) return (void *) kernel32::SetFilePointerEx;
if (strcmp(name, "SetEndOfFile") == 0) return (void *) kernel32::SetEndOfFile;

67
dll/psapi.cpp Normal file
View File

@ -0,0 +1,67 @@
#include "common.h"
#include "handles.h"
namespace psapi {
BOOL WIN_FUNC EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, DWORD *lpcbNeeded) {
DEBUG_LOG("EnumProcessModules(hProcess=%p, cb=%u)\n", hProcess, cb);
bool recognizedHandle = false;
if (hProcess == (HANDLE)0xFFFFFFFF) {
recognizedHandle = true;
} else {
auto data = handles::dataFromHandle(hProcess, false);
recognizedHandle = (data.type == handles::TYPE_PROCESS);
}
if (!recognizedHandle) {
wibo::lastError = ERROR_ACCESS_DENIED;
return FALSE;
}
HMODULE currentModule = wibo::mainModule ? reinterpret_cast<HMODULE>(wibo::mainModule->imageBuffer) : nullptr;
DWORD required = currentModule ? sizeof(HMODULE) : 0;
if (lpcbNeeded) {
*lpcbNeeded = required;
}
if (required == 0) {
wibo::lastError = ERROR_INVALID_HANDLE;
return FALSE;
}
if (!lphModule || cb < required) {
wibo::lastError = ERROR_INSUFFICIENT_BUFFER;
return FALSE;
}
lphModule[0] = currentModule;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
}
static void *resolveByName(const char *name) {
DEBUG_LOG("psapi resolveByName(%s)\n", name);
if (strcmp(name, "EnumProcessModules") == 0) return (void *) psapi::EnumProcessModules;
if (strcmp(name, "K32EnumProcessModules") == 0) return (void *) psapi::EnumProcessModules;
return nullptr;
}
static void *resolveByOrdinal(uint16_t ordinal) {
DEBUG_LOG("psapi resolveByOrdinal(%u)\n", ordinal);
switch (ordinal) {
case 4: // EnumProcessModules
return (void *) psapi::EnumProcessModules;
default:
return nullptr;
}
}
wibo::Module lib_psapi = {
(const char *[]){
"psapi",
"psapi.dll",
nullptr,
},
resolveByName,
resolveByOrdinal,
};

295
dll/rpcrt4.cpp Normal file
View File

@ -0,0 +1,295 @@
#include "common.h"
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <unordered_map>
namespace {
using RPC_STATUS = unsigned long;
using RPC_WSTR = uint16_t *;
using RPC_BINDING_HANDLE = void *;
using RPC_AUTH_IDENTITY_HANDLE = void *;
using LONG_PTR = intptr_t;
using PMIDL_STUB_DESC = void *;
using PFORMAT_STRING = unsigned char *;
using PRPC_MESSAGE = void *;
constexpr RPC_STATUS RPC_S_OK = 0;
constexpr RPC_STATUS RPC_S_INVALID_STRING_BINDING = 1700;
constexpr RPC_STATUS RPC_S_INVALID_BINDING = 1702;
constexpr RPC_STATUS RPC_S_SERVER_UNAVAILABLE = 1722;
constexpr RPC_STATUS RPC_S_INVALID_ARG = 87;
constexpr RPC_STATUS RPC_S_OUT_OF_MEMORY = 14;
struct RPC_SECURITY_QOS {
unsigned long Version = 0;
unsigned long Capabilities = 0;
unsigned long IdentityTracking = 0;
unsigned long ImpersonationType = 0;
void *AdditionalSecurityInfo = nullptr;
};
struct BindingComponents {
std::u16string objectUuid;
std::u16string protocolSequence;
std::u16string networkAddress;
std::u16string endpoint;
std::u16string options;
};
struct BindingHandleData {
BindingComponents components;
std::u16string bindingString;
std::u16string serverPrincipalName;
unsigned long authnLevel = 0;
unsigned long authnService = 0;
RPC_AUTH_IDENTITY_HANDLE authIdentity = nullptr;
unsigned long authzService = 0;
bool hasAuthInfo = false;
bool hasSecurityQos = false;
RPC_SECURITY_QOS securityQos = {};
bool serverReachable = false;
};
union CLIENT_CALL_RETURN {
void *Pointer;
LONG_PTR Simple;
};
std::unordered_map<RPC_WSTR, BindingComponents> g_stringBindings;
std::unordered_map<RPC_BINDING_HANDLE, std::unique_ptr<BindingHandleData>> g_bindingHandles;
std::u16string toU16(RPC_WSTR str) {
if (!str) {
return {};
}
auto *ptr = reinterpret_cast<const char16_t *>(str);
size_t length = 0;
while (ptr[length] != 0) {
++length;
}
return std::u16string(ptr, ptr + length);
}
std::string narrow(const std::u16string &value) {
std::string out;
out.reserve(value.size());
for (char16_t ch : value) {
if (ch <= 0x7F) {
out.push_back(static_cast<char>(ch));
} else {
out.push_back('?');
}
}
return out;
}
std::u16string composeString(const BindingComponents &components) {
std::u16string result;
if (!components.objectUuid.empty()) {
result += components.objectUuid;
result += u"@";
}
if (!components.protocolSequence.empty()) {
result += components.protocolSequence;
}
if (!components.networkAddress.empty()) {
if (!components.protocolSequence.empty()) {
result += u":";
}
result += components.networkAddress;
}
if (!components.endpoint.empty()) {
result += u"[";
result += components.endpoint;
result += u"]";
}
if (!components.options.empty()) {
result += u"{";
result += components.options;
result += u"}";
}
return result;
}
BindingHandleData *getBinding(RPC_BINDING_HANDLE handle) {
auto it = g_bindingHandles.find(handle);
if (it == g_bindingHandles.end()) {
return nullptr;
}
return it->second.get();
}
} // namespace
extern "C" {
RPC_STATUS WIN_FUNC RpcStringBindingComposeW(
RPC_WSTR objUuid,
RPC_WSTR protSeq,
RPC_WSTR networkAddr,
RPC_WSTR endpoint,
RPC_WSTR options,
RPC_WSTR *stringBinding
) {
BindingComponents components;
components.objectUuid = toU16(objUuid);
components.protocolSequence = toU16(protSeq);
components.networkAddress = toU16(networkAddr);
components.endpoint = toU16(endpoint);
components.options = toU16(options);
std::u16string encoded = composeString(components);
DEBUG_LOG("RpcStringBindingComposeW -> %s\n", narrow(encoded).c_str());
if (stringBinding) {
size_t length = encoded.size();
auto *buffer = static_cast<char16_t *>(std::malloc((length + 1) * sizeof(char16_t)));
if (!buffer) {
return RPC_S_OUT_OF_MEMORY;
}
if (length > 0) {
std::memcpy(buffer, encoded.data(), length * sizeof(char16_t));
}
buffer[length] = 0;
RPC_WSTR result = reinterpret_cast<RPC_WSTR>(buffer);
g_stringBindings[result] = components;
*stringBinding = result;
}
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding) {
if (!binding) {
return RPC_S_INVALID_ARG;
}
*binding = nullptr;
if (!stringBinding) {
return RPC_S_INVALID_STRING_BINDING;
}
auto it = g_stringBindings.find(stringBinding);
if (it == g_stringBindings.end()) {
return RPC_S_INVALID_STRING_BINDING;
}
auto handleData = std::make_unique<BindingHandleData>();
handleData->components = it->second;
handleData->bindingString = composeString(handleData->components);
handleData->serverReachable = false;
RPC_BINDING_HANDLE handle = reinterpret_cast<RPC_BINDING_HANDLE>(handleData.get());
g_bindingHandles.emplace(handle, std::move(handleData));
*binding = handle;
DEBUG_LOG("RpcBindingFromStringBindingW(handle=%p)\n", handle);
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcBindingSetAuthInfoExW(
RPC_BINDING_HANDLE binding,
RPC_WSTR serverPrincName,
unsigned long authnLevel,
unsigned long authnSvc,
RPC_AUTH_IDENTITY_HANDLE authIdentity,
unsigned long authzSvc,
RPC_SECURITY_QOS *securityQos
) {
BindingHandleData *data = getBinding(binding);
if (!data) {
return RPC_S_INVALID_BINDING;
}
data->serverPrincipalName = toU16(serverPrincName);
data->authnLevel = authnLevel;
data->authnService = authnSvc;
data->authIdentity = authIdentity;
data->authzService = authzSvc;
data->hasAuthInfo = true;
if (securityQos) {
data->securityQos = *securityQos;
data->hasSecurityQos = true;
} else {
data->hasSecurityQos = false;
}
DEBUG_LOG("RpcBindingSetAuthInfoExW(handle=%p, authnSvc=%lu, authnLevel=%lu)\n", binding, authnSvc, authnLevel);
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcBindingFree(RPC_BINDING_HANDLE *binding) {
if (!binding) {
return RPC_S_INVALID_ARG;
}
RPC_BINDING_HANDLE handle = *binding;
if (!handle) {
return RPC_S_INVALID_BINDING;
}
auto it = g_bindingHandles.find(handle);
if (it == g_bindingHandles.end()) {
return RPC_S_INVALID_BINDING;
}
g_bindingHandles.erase(it);
*binding = nullptr;
DEBUG_LOG("RpcBindingFree\n");
return RPC_S_OK;
}
RPC_STATUS WIN_FUNC RpcStringFreeW(RPC_WSTR *string) {
if (!string) {
return RPC_S_INVALID_ARG;
}
RPC_WSTR value = *string;
if (!value) {
return RPC_S_OK;
}
auto it = g_stringBindings.find(value);
if (it != g_stringBindings.end()) {
g_stringBindings.erase(it);
}
std::free(reinterpret_cast<void *>(value));
*string = nullptr;
return RPC_S_OK;
}
CLIENT_CALL_RETURN __attribute__((force_align_arg_pointer, callee_pop_aggregate_return(0), cdecl))
NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...) {
DEBUG_LOG("STUB: NdrClientCall2 stubDescriptor=%p format=%p\n", stubDescriptor, format);
CLIENT_CALL_RETURN result = {};
result.Simple = RPC_S_SERVER_UNAVAILABLE;
DEBUG_LOG("NdrClientCall2 returning RPC_S_SERVER_UNAVAILABLE\n");
return result;
}
void WIN_FUNC NdrServerCall2(PRPC_MESSAGE message) {
DEBUG_LOG("STUB: NdrServerCall2 message=%p\n", message);
}
} // extern "C"
namespace {
void *resolveByName(const char *name) {
if (std::strcmp(name, "RpcStringBindingComposeW") == 0)
return (void *) RpcStringBindingComposeW;
if (std::strcmp(name, "RpcBindingFromStringBindingW") == 0)
return (void *) RpcBindingFromStringBindingW;
if (std::strcmp(name, "RpcStringFreeW") == 0)
return (void *) RpcStringFreeW;
if (std::strcmp(name, "RpcBindingFree") == 0)
return (void *) RpcBindingFree;
if (std::strcmp(name, "RpcBindingSetAuthInfoExW") == 0)
return (void *) RpcBindingSetAuthInfoExW;
if (std::strcmp(name, "NdrClientCall2") == 0)
return (void *) NdrClientCall2;
if (std::strcmp(name, "NdrServerCall2") == 0)
return (void *) NdrServerCall2;
return nullptr;
}
} // namespace
wibo::Module lib_rpcrt4 = {
(const char *[]){"rpcrt4", "rpcrt4.dll", nullptr},
resolveByName,
nullptr,
};

View File

@ -4,10 +4,12 @@
namespace handles {
enum Type {
TYPE_UNUSED,
TYPE_UNUSED,
TYPE_FILE,
TYPE_MAPPED,
TYPE_PROCESS
TYPE_PROCESS,
TYPE_TOKEN,
TYPE_MUTEX
};
struct Data {

View File

@ -92,6 +92,17 @@ struct PEHintNameTableEntry {
char name[1]; // variable length
};
struct PEDelayImportDescriptor {
uint32_t attributes;
uint32_t name;
uint32_t moduleHandle;
uint32_t importAddressTable;
uint32_t importNameTable;
uint32_t boundImportAddressTable;
uint32_t unloadInformationTable;
uint32_t timeStamp;
};
struct PEBaseRelocationBlock {
uint32_t virtualAddress;
uint32_t sizeOfBlock;
@ -279,12 +290,16 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) {
// Import by ordinal
uint16_t ordinal = lookup & 0xFFFF;
DEBUG_LOG(" Ordinal: %d\n", ordinal);
*addressTable = reinterpret_cast<uintptr_t>(resolveFuncByOrdinal(module, ordinal));
void *func = resolveFuncByOrdinal(module, ordinal);
DEBUG_LOG(" -> %p\n", func);
*addressTable = reinterpret_cast<uintptr_t>(func);
} else {
// Import by name
PEHintNameTableEntry *hintName = fromRVA<PEHintNameTableEntry>(lookup);
DEBUG_LOG(" Name: %s\n", hintName->name);
*addressTable = reinterpret_cast<uintptr_t>(resolveFuncByName(module, hintName->name));
DEBUG_LOG(" Name: %s (IAT=%p)\n", hintName->name, addressTable);
void *func = resolveFuncByName(module, hintName->name);
DEBUG_LOG(" -> %p\n", func);
*addressTable = reinterpret_cast<uintptr_t>(func);
}
++lookupTable;
++addressTable;
@ -292,6 +307,39 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) {
++dir;
}
if (header32.delayImportDescriptor.virtualAddress) {
DEBUG_LOG("Processing delay import table at RVA %x\n", header32.delayImportDescriptor.virtualAddress);
PEDelayImportDescriptor *delay = fromRVA<PEDelayImportDescriptor>(header32.delayImportDescriptor.virtualAddress);
while (delay->name) {
char *dllName = fromRVA<char>(delay->name);
DEBUG_LOG("Delay DLL Name: %s\n", dllName);
uint32_t *lookupTable = fromRVA<uint32_t>(delay->importNameTable);
uint32_t *addressTable = fromRVA<uint32_t>(delay->importAddressTable);
HMODULE module = loadModule(dllName);
while (*lookupTable) {
uint32_t lookup = *lookupTable;
if (lookup & 0x80000000) {
uint16_t ordinal = lookup & 0xFFFF;
DEBUG_LOG(" Ordinal: %d (IAT=%p)\n", ordinal, addressTable);
*addressTable = reinterpret_cast<uintptr_t>(resolveFuncByOrdinal(module, ordinal));
} else {
PEHintNameTableEntry *hintName = fromRVA<PEHintNameTableEntry>(lookup);
DEBUG_LOG(" Name: %s\n", hintName->name);
*addressTable = reinterpret_cast<uintptr_t>(resolveFuncByName(module, hintName->name));
}
++lookupTable;
++addressTable;
}
if (delay->moduleHandle) {
HMODULE *moduleSlot = fromRVA<HMODULE>(delay->moduleHandle);
if (moduleSlot) {
*moduleSlot = module;
}
}
++delay;
}
}
entryPoint = header32.addressOfEntryPoint ? fromRVA<void>(header32.addressOfEntryPoint) : nullptr;
return true;

View File

@ -23,6 +23,7 @@ extern const wibo::Module lib_lmgr;
extern const wibo::Module lib_mscoree;
extern const wibo::Module lib_msvcrt;
extern const wibo::Module lib_ntdll;
extern const wibo::Module lib_rpcrt4;
extern const wibo::Module lib_ole32;
extern const wibo::Module lib_user32;
extern const wibo::Module lib_vcruntime;
@ -405,7 +406,7 @@ void ensureInitialized() {
const wibo::Module *builtins[] = {
&lib_advapi32, &lib_bcrypt, &lib_crt, &lib_kernel32, &lib_lmgr, &lib_mscoree, &lib_msvcrt,
&lib_ntdll, &lib_ole32, &lib_user32, &lib_vcruntime, &lib_version, nullptr,
&lib_ntdll, &lib_ole32, &lib_rpcrt4, &lib_user32, &lib_vcruntime, &lib_version, nullptr,
};
for (const wibo::Module **module = builtins; *module; ++module) {