mirror of
https://github.com/decompals/wibo.git
synced 2025-10-16 23:25:11 +00:00
cl.exe works! but I didn't review most of this code
This commit is contained in:
parent
b4ea1da959
commit
f23224bbcc
@ -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
|
||||
|
2
common.h
2
common.h
@ -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)
|
||||
|
545
dll/advapi32.cpp
545
dll/advapi32.cpp
@ -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;
|
||||
}
|
||||
|
||||
|
769
dll/kernel32.cpp
769
dll/kernel32.cpp
@ -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
67
dll/psapi.cpp
Normal 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
295
dll/rpcrt4.cpp
Normal 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,
|
||||
};
|
@ -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 {
|
||||
|
54
loader.cpp
54
loader.cpp
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user