Add CreatePipe, CON* support for CreateFileA, more for cygwin

This commit is contained in:
Luke Street 2025-10-02 09:47:41 -06:00
parent 694eb85deb
commit 8330f27479
20 changed files with 257 additions and 16 deletions

View File

@ -50,6 +50,7 @@ add_executable(wibo
dll/kernel32/interlockedapi.cpp
dll/kernel32/ioapiset.cpp
dll/kernel32/libloaderapi.cpp
dll/kernel32/namedpipeapi.cpp
dll/kernel32/memoryapi.cpp
dll/kernel32/processenv.cpp
dll/kernel32/processthreadsapi.cpp

View File

@ -43,6 +43,7 @@ using HLOCAL = HANDLE;
using HRSRC = HANDLE;
using LPHANDLE = HANDLE *;
using PHANDLE = HANDLE *;
using HKL = HANDLE;
using PVOID = void *;
using LPVOID = void *;
using LPCVOID = const void *;

View File

@ -33,6 +33,10 @@ void *resolveByName(const char *name) {
return (void *)advapi32::DuplicateTokenEx;
if (strcmp(name, "CopySid") == 0)
return (void *)advapi32::CopySid;
if (strcmp(name, "InitializeSid") == 0)
return (void *)advapi32::InitializeSid;
if (strcmp(name, "EqualSid") == 0)
return (void *)advapi32::EqualSid;
if (strcmp(name, "GetSecurityDescriptorDacl") == 0)
return (void *)advapi32::GetSecurityDescriptorDacl;
if (strcmp(name, "SetKernelObjectSecurity") == 0)

View File

@ -359,6 +359,50 @@ BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pS
return TRUE;
}
BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount) {
DEBUG_LOG("InitializeSid(%p, %p, %u)\n", sid, pIdentifierAuthority, nSubAuthorityCount);
if (!sid || !pIdentifierAuthority) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
if (nSubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
wibo::lastError = ERROR_INVALID_SID;
return FALSE;
}
auto *sidStruct = reinterpret_cast<Sid *>(sid);
sidStruct->Revision = SID_REVISION;
sidStruct->SubAuthorityCount = nSubAuthorityCount;
sidStruct->IdentifierAuthority = *pIdentifierAuthority;
if (nSubAuthorityCount > 0) {
std::memset(sidStruct->SubAuthority, 0, sizeof(DWORD) * nSubAuthorityCount);
}
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2) {
DEBUG_LOG("EqualSid(%p, %p)\n", pSid1, pSid2);
if (!pSid1 || !pSid2) {
wibo::lastError = ERROR_INVALID_SID;
return FALSE;
}
const auto *sid1 = reinterpret_cast<const Sid *>(pSid1);
const auto *sid2 = reinterpret_cast<const Sid *>(pSid2);
if (sid1->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES || sid2->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
wibo::lastError = ERROR_INVALID_SID;
return FALSE;
}
bool equal =
sid1->Revision == sid2->Revision &&
std::memcmp(&sid1->IdentifierAuthority, &sid2->IdentifierAuthority, sizeof(SidIdentifierAuthority)) == 0 &&
sid1->SubAuthorityCount == sid2->SubAuthorityCount;
if (equal && sid1->SubAuthorityCount > 0) {
equal = std::memcmp(sid1->SubAuthority, sid2->SubAuthority, sizeof(DWORD) * sid1->SubAuthorityCount) == 0;
}
wibo::lastError = ERROR_SUCCESS;
return equal ? TRUE : FALSE;
}
BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR SecurityDescriptor) {
DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor);

View File

@ -53,6 +53,7 @@ constexpr BYTE ACL_REVISION = ACL_REVISION2;
constexpr BYTE ACL_REVISION_DS = ACL_REVISION4;
constexpr BYTE ACCESS_ALLOWED_ACE_TYPE = 0x00;
constexpr BYTE SID_MAX_SUB_AUTHORITIES = 15;
constexpr BYTE SID_REVISION = 1;
struct TOKEN_PRIVILEGES;
using PTOKEN_PRIVILEGES = TOKEN_PRIVILEGES *;
@ -92,6 +93,8 @@ BOOL WIN_FUNC ImpersonateLoggedOnUser(HANDLE hToken);
BOOL WIN_FUNC DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken);
BOOL WIN_FUNC CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid);
BOOL WIN_FUNC InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount);
BOOL WIN_FUNC EqualSid(PSID pSid1, PSID pSid2);
BOOL WIN_FUNC GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
LPBOOL lpbDaclDefaulted);
BOOL WIN_FUNC SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,

View File

@ -9,6 +9,7 @@
#include "kernel32/interlockedapi.h"
#include "kernel32/ioapiset.h"
#include "kernel32/libloaderapi.h"
#include "kernel32/namedpipeapi.h"
#include "kernel32/memoryapi.h"
#include "kernel32/processenv.h"
#include "kernel32/processthreadsapi.h"
@ -192,6 +193,10 @@ void *resolveByName(const char *name) {
if (strcmp(name, "Sleep") == 0)
return (void *)kernel32::Sleep;
// namedpipeapi.h
if (strcmp(name, "CreatePipe") == 0)
return (void *)kernel32::CreatePipe;
// winbase.h
if (strcmp(name, "GlobalAlloc") == 0)
return (void *)kernel32::GlobalAlloc;
@ -289,6 +294,8 @@ void *resolveByName(const char *name) {
return (void *)kernel32::GetConsoleMode;
if (strcmp(name, "SetConsoleMode") == 0)
return (void *)kernel32::SetConsoleMode;
if (strcmp(name, "GetConsoleCP") == 0)
return (void *)kernel32::GetConsoleCP;
if (strcmp(name, "SetConsoleCtrlHandler") == 0)
return (void *)kernel32::SetConsoleCtrlHandler;
if (strcmp(name, "GetConsoleScreenBufferInfo") == 0)

View File

@ -13,4 +13,3 @@ PVOID WIN_FUNC FlsGetValue(DWORD dwFlsIndex);
BOOL WIN_FUNC FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData);
} // namespace kernel32

View File

@ -220,6 +220,53 @@ bool initializeEnumeration(const std::filesystem::path &parent, const std::strin
return nextMatch(handle, firstMatch);
}
std::optional<DWORD> stdHandleForConsoleDevice(const std::string &name, DWORD desiredAccess) {
std::string lowered = stringToLower(name);
if (lowered == "conin$") {
return STD_INPUT_HANDLE;
}
if (lowered == "conout$") {
return STD_OUTPUT_HANDLE;
}
if (lowered == "conerr$") {
return STD_ERROR_HANDLE;
}
if (lowered == "con") {
if ((desiredAccess & GENERIC_WRITE) != 0) {
return STD_OUTPUT_HANDLE;
}
return STD_INPUT_HANDLE;
}
return std::nullopt;
}
bool tryOpenConsoleDevice(DWORD dwDesiredAccess, DWORD dwShareMode, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE &outHandle, const std::string &originalName) {
(void)dwShareMode;
(void)dwCreationDisposition;
(void)dwFlagsAndAttributes;
auto stdHandleKind = stdHandleForConsoleDevice(originalName, dwDesiredAccess);
if (!stdHandleKind) {
return false;
}
HANDLE baseHandle = files::getStdHandle(*stdHandleKind);
auto *baseFile = files::fileHandleFromHandle(baseHandle);
if (!baseFile) {
wibo::lastError = ERROR_INVALID_HANDLE;
outHandle = INVALID_HANDLE_VALUE;
return true;
}
HANDLE duplicated = files::duplicateFileHandle(baseFile, false);
if (!duplicated) {
wibo::lastError = ERROR_INVALID_HANDLE;
outHandle = INVALID_HANDLE_VALUE;
return true;
}
wibo::lastError = ERROR_SUCCESS;
outHandle = duplicated;
return true;
}
} // namespace
namespace kernel32 {
@ -548,6 +595,13 @@ HANDLE WIN_FUNC CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwSh
wibo::lastError = ERROR_INVALID_PARAMETER;
return INVALID_HANDLE_VALUE;
}
HANDLE consoleHandle = INVALID_HANDLE_VALUE;
if (tryOpenConsoleDevice(dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes, consoleHandle,
std::string(lpFileName))) {
DEBUG_LOG("CreateFileA(console=%s, desiredAccess=0x%x, shareMode=%u, flags=0x%x) -> %p\n", lpFileName,
dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, consoleHandle);
return consoleHandle;
}
std::string path = files::pathFromWindows(lpFileName);
DEBUG_LOG("CreateFileA(filename=%s (%s), desiredAccess=0x%x, shareMode=%u, securityAttributes=%p, "
"creationDisposition=%u, flagsAndAttributes=%u)\n",
@ -629,6 +683,13 @@ HANDLE WIN_FUNC CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwS
return INVALID_HANDLE_VALUE;
}
std::string lpFileNameA = wideStringToString(lpFileName);
HANDLE consoleHandle = INVALID_HANDLE_VALUE;
if (tryOpenConsoleDevice(dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes, consoleHandle,
lpFileNameA)) {
DEBUG_LOG("CreateFileW(console=%s, desiredAccess=0x%x, shareMode=%u, flags=0x%x) -> %p\n", lpFileNameA.c_str(),
dwDesiredAccess, dwShareMode, dwFlagsAndAttributes, consoleHandle);
return consoleHandle;
}
return CreateFileA(lpFileNameA.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
}

View File

@ -46,4 +46,3 @@ BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWO
}
} // namespace kernel32

View File

@ -9,4 +9,3 @@ BOOL WIN_FUNC GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWO
BOOL bWait);
} // namespace kernel32

View File

@ -0,0 +1,98 @@
#include "namedpipeapi.h"
#include "errors.h"
#include "fileapi.h"
#include "files.h"
#include "handles.h"
#include "internal.h"
#include <cerrno>
#include <cstdio>
#include <fcntl.h>
#include <unistd.h>
namespace kernel32 {
namespace {
void configureInheritability(int fd, bool inherit) {
if (fd < 0) {
return;
}
int flags = fcntl(fd, F_GETFD);
if (flags == -1) {
return;
}
if (inherit) {
flags &= ~FD_CLOEXEC;
} else {
flags |= FD_CLOEXEC;
}
fcntl(fd, F_SETFD, flags);
}
} // namespace
BOOL WIN_FUNC CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize) {
DEBUG_LOG("CreatePipe(%p, %p, %p, %u)\n", hReadPipe, hWritePipe, lpPipeAttributes, nSize);
if (!hReadPipe || !hWritePipe) {
wibo::lastError = ERROR_INVALID_PARAMETER;
return FALSE;
}
*hReadPipe = nullptr;
*hWritePipe = nullptr;
int pipeFds[2];
if (pipe(pipeFds) != 0) {
setLastErrorFromErrno();
return FALSE;
}
bool inheritHandles = lpPipeAttributes && lpPipeAttributes->bInheritHandle;
configureInheritability(pipeFds[0], inheritHandles);
configureInheritability(pipeFds[1], inheritHandles);
if (nSize != 0) {
// Best-effort adjustment; ignore failures as recommended by docs.
fcntl(pipeFds[0], F_SETPIPE_SZ, static_cast<int>(nSize));
fcntl(pipeFds[1], F_SETPIPE_SZ, static_cast<int>(nSize));
}
FILE *readStream = fdopen(pipeFds[0], "rb");
if (!readStream) {
int savedErrno = errno ? errno : EINVAL;
close(pipeFds[0]);
close(pipeFds[1]);
errno = savedErrno;
setLastErrorFromErrno();
return FALSE;
}
FILE *writeStream = fdopen(pipeFds[1], "wb");
if (!writeStream) {
int savedErrno = errno ? errno : EINVAL;
fclose(readStream);
close(pipeFds[1]);
errno = savedErrno;
setLastErrorFromErrno();
return FALSE;
}
setvbuf(readStream, nullptr, _IONBF, 0);
setvbuf(writeStream, nullptr, _IONBF, 0);
HANDLE readHandle = files::allocFpHandle(readStream, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, true);
HANDLE writeHandle = files::allocFpHandle(writeStream, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, true);
if (!readHandle || !writeHandle) {
fclose(readStream);
fclose(writeStream);
wibo::lastError = ERROR_NOT_ENOUGH_MEMORY;
return FALSE;
}
*hReadPipe = readHandle;
*hWritePipe = writeHandle;
wibo::lastError = ERROR_SUCCESS;
return TRUE;
}
} // namespace kernel32

View File

@ -0,0 +1,10 @@
#pragma once
#include "common.h"
#include "minwinbase.h"
namespace kernel32 {
BOOL WIN_FUNC CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize);
} // namespace kernel32

View File

@ -53,12 +53,12 @@ LPWSTR WIN_FUNC GetCommandLineW() {
}
HANDLE WIN_FUNC GetStdHandle(DWORD nStdHandle) {
DEBUG_LOG("GetStdHandle(%u)\n", nStdHandle);
DEBUG_LOG("GetStdHandle(%d)\n", nStdHandle);
return files::getStdHandle(nStdHandle);
}
BOOL WIN_FUNC SetStdHandle(DWORD nStdHandle, HANDLE hHandle) {
DEBUG_LOG("SetStdHandle(%u, %p)\n", nStdHandle, hHandle);
DEBUG_LOG("SetStdHandle(%d, %p)\n", nStdHandle, hHandle);
return files::setStdHandle(nStdHandle, hHandle);
}

View File

@ -9,8 +9,8 @@
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <filesystem>
#include <limits>
@ -171,10 +171,10 @@ UINT WIN_FUNC SetHandleCount(UINT uNumber) {
return handles::MAX_HANDLES;
}
DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
LPSTR lpBuffer, DWORD nSize, va_list *Arguments) {
DEBUG_LOG("FormatMessageA(%u, %p, %u, %u, %p, %u, %p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId,
lpBuffer, nSize, Arguments);
DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer,
DWORD nSize, va_list *Arguments) {
DEBUG_LOG("FormatMessageA(%u, %p, %u, %u, %p, %u, %p)\n", dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer,
nSize, Arguments);
if (dwFlags & 0x00000100) {
// FORMAT_MESSAGE_ALLOCATE_BUFFER

View File

@ -9,8 +9,8 @@ namespace kernel32 {
BOOL WIN_FUNC IsBadReadPtr(LPCVOID lp, UINT_PTR ucb);
BOOL WIN_FUNC IsBadWritePtr(LPVOID lp, UINT_PTR ucb);
UINT WIN_FUNC SetHandleCount(UINT uNumber);
DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId,
LPSTR lpBuffer, DWORD nSize, va_list *Arguments);
DWORD WIN_FUNC FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer,
DWORD nSize, va_list *Arguments);
PVOID WIN_FUNC EncodePointer(PVOID Ptr);
PVOID WIN_FUNC DecodePointer(PVOID Ptr);
BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName);

View File

@ -25,6 +25,12 @@ BOOL WIN_FUNC SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode) {
return TRUE;
}
UINT WIN_FUNC GetConsoleCP() {
DEBUG_LOG("STUB: GetConsoleCP() -> 65001\n");
wibo::lastError = ERROR_SUCCESS;
return 65001; // UTF-8
}
UINT WIN_FUNC GetConsoleOutputCP() {
DEBUG_LOG("STUB: GetConsoleOutputCP() -> 65001\n");
wibo::lastError = ERROR_SUCCESS;

View File

@ -30,6 +30,7 @@ namespace kernel32 {
BOOL WIN_FUNC GetConsoleMode(HANDLE hConsoleHandle, LPDWORD lpMode);
BOOL WIN_FUNC SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode);
UINT WIN_FUNC GetConsoleCP();
UINT WIN_FUNC GetConsoleOutputCP();
BOOL WIN_FUNC SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add);
BOOL WIN_FUNC GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO *lpConsoleScreenBufferInfo);

View File

@ -10,4 +10,3 @@ void WIN_FUNC RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD Exc
}
} // namespace kernel32

View File

@ -8,4 +8,3 @@ namespace kernel32 {
void WIN_FUNC RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue);
} // namespace kernel32

View File

@ -1,8 +1,10 @@
#include "common.h"
#include "errors.h"
#include "strutil.h"
namespace user32 {
constexpr uint32_t RT_STRING_ID = 6;
constexpr uintptr_t kDefaultKeyboardLayout = 0x04090409;
int WIN_FUNC LoadStringA(void* hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax) {
DEBUG_LOG("LoadStringA(%p, %u, %p, %d)\n", hInstance, uID, lpBuffer, cchBufferMax);
@ -109,6 +111,13 @@ namespace user32 {
fflush(stdout);
return 1;
}
HKL WIN_FUNC GetKeyboardLayout(DWORD idThread) {
DEBUG_LOG("GetKeyboardLayout(%u)\n", idThread);
(void)idThread;
wibo::lastError = ERROR_SUCCESS;
return reinterpret_cast<HKL>(kDefaultKeyboardLayout);
}
}
@ -116,6 +125,7 @@ static void *resolveByName(const char *name) {
if (strcmp(name, "LoadStringA") == 0) return (void *) user32::LoadStringA;
if (strcmp(name, "LoadStringW") == 0) return (void *) user32::LoadStringW;
if (strcmp(name, "MessageBoxA") == 0) return (void *) user32::MessageBoxA;
if (strcmp(name, "GetKeyboardLayout") == 0) return (void *) user32::GetKeyboardLayout;
return nullptr;
}