Everything needed to run simple Rust programs (#40)

* Everything needed to run simple Rust programs

* Add IsDBCSLeadByte implementation

* Address PR comments
This commit is contained in:
Luke Street 2023-09-09 23:07:23 -04:00 committed by GitHub
parent 6e18120410
commit 94b44fd697
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1106 additions and 151 deletions

6
.clang-format Normal file
View File

@ -0,0 +1,6 @@
---
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Always
ColumnLimit: 120

146
.clang-tidy Normal file
View File

@ -0,0 +1,146 @@
---
Checks: '-*,
bugprone-argument-comment,
bugprone-assert-side-effect,
bugprone-bad-signal-to-kill-thread,
bugprone-branch-clone,
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-dynamic-static-initializers,
bugprone-fold-init-type,
bugprone-forward-declaration-namespace,
bugprone-forwarding-reference-overload,
bugprone-inaccurate-erase,
bugprone-incorrect-roundings,
bugprone-integer-division,
bugprone-lambda-function-name,
bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-pointer-arithmetic-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-move-forwarding-reference,
bugprone-multiple-statement-macro,
bugprone-no-escape,
bugprone-not-null-terminated-result,
bugprone-parent-virtual-call,
bugprone-posix-return,
bugprone-sizeof-container,
bugprone-sizeof-expression,
bugprone-spuriously-wake-up-functions,
bugprone-string-constructor,
bugprone-string-integer-assignment,
bugprone-string-literal-with-embedded-nul,
bugprone-suspicious-enum-usage,
bugprone-suspicious-include,
bugprone-suspicious-memset-usage,
bugprone-suspicious-missing-comma,
bugprone-suspicious-semicolon,
bugprone-suspicious-string-compare,
bugprone-suspicious-memory-comparison,
bugprone-suspicious-realloc-usage,
bugprone-swapped-arguments,
bugprone-terminating-continue,
bugprone-throw-keyword-missing,
bugprone-too-small-loop-variable,
bugprone-undefined-memory-manipulation,
bugprone-undelegated-constructor,
bugprone-unhandled-self-assignment,
bugprone-unused-raii,
bugprone-unused-return-value,
bugprone-use-after-move,
bugprone-virtual-near-miss,
cert-dcl21-cpp,
cert-dcl58-cpp,
cert-err34-c,
cert-err52-cpp,
cert-err60-cpp,
cert-flp30-c,
cert-msc50-cpp,
cert-msc51-cpp,
cert-str34-c,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing,
google-default-arguments,
google-explicit-constructor,
google-runtime-operator,
hicpp-exception-baseclass,
hicpp-multiway-paths-covered,
misc-misplaced-const,
misc-new-delete-overloads,
misc-no-recursion,
misc-non-copyable-objects,
misc-throw-by-value-catch-by-reference,
misc-unconventional-assign-operator,
misc-uniqueptr-reset-release,
modernize-avoid-bind,
modernize-concat-nested-namespaces,
modernize-deprecated-headers,
modernize-deprecated-ios-base-aliases,
modernize-loop-convert,
modernize-make-shared,
modernize-make-unique,
modernize-pass-by-value,
modernize-raw-string-literal,
modernize-redundant-void-arg,
modernize-replace-auto-ptr,
modernize-replace-disallow-copy-and-assign-macro,
modernize-replace-random-shuffle,
modernize-return-braced-init-list,
modernize-shrink-to-fit,
modernize-unary-static-assert,
modernize-use-auto,
modernize-use-bool-literals,
modernize-use-emplace,
modernize-use-equals-default,
modernize-use-equals-delete,
modernize-use-nodiscard,
modernize-use-noexcept,
modernize-use-nullptr,
modernize-use-override,
modernize-use-transparent-functors,
modernize-use-uncaught-exceptions,
mpi-buffer-deref,
mpi-type-mismatch,
openmp-use-default-none,
performance-faster-string-find,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
performance-inefficient-algorithm,
performance-inefficient-string-concatenation,
performance-inefficient-vector-operation,
performance-move-const-arg,
performance-move-constructor-init,
performance-no-automatic-move,
performance-noexcept-move-constructor,
performance-trivially-destructible,
performance-type-promotion-in-math-fn,
performance-unnecessary-copy-initialization,
performance-unnecessary-value-param,
portability-simd-intrinsics,
readability-avoid-const-params-in-decls,
readability-const-return-type,
readability-container-size-empty,
readability-convert-member-functions-to-static,
readability-delete-null-pointer,
readability-deleted-default,
readability-inconsistent-declaration-parameter-name,
readability-make-member-function-const,
readability-misleading-indentation,
readability-misplaced-array-index,
readability-non-const-parameter,
readability-redundant-control-flow,
readability-redundant-declaration,
readability-redundant-function-ptr-dereference,
readability-redundant-smartptr-get,
readability-redundant-string-cstr,
readability-redundant-string-init,
readability-simplify-subscript-expr,
readability-static-accessed-through-instance,
readability-static-definition-in-anonymous-namespace,
readability-string-compare,
readability-uniqueptr-delete-release,
readability-use-anyofallof'

View File

@ -16,10 +16,14 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -Wall")
include_directories(.)
add_executable(wibo
dll/advapi32.cpp
dll/bcrypt.cpp
dll/crt.cpp
dll/kernel32.cpp
dll/lmgr.cpp
dll/ntdll.cpp
dll/ole32.cpp
dll/user32.cpp
dll/vcruntime.cpp
dll/version.cpp
files.cpp
handles.cpp

View File

@ -1,10 +1,11 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <sys/stat.h>
#include <unistd.h>
#include <assert.h>
// On Windows, the incoming stack is aligned to a 4 byte boundary.
// force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment.
@ -12,25 +13,83 @@
#define WIN_FUNC WIN_ENTRY __attribute__((stdcall))
#define DEBUG_LOG(...) wibo::debug_log(__VA_ARGS__)
namespace user32 {
int WIN_FUNC MessageBoxA(void *hwnd, const char *lpText, const char *lpCaption, unsigned int uType);
}
typedef void *HANDLE;
typedef void *HMODULE;
typedef void *PVOID;
typedef void *LPVOID;
typedef void *FARPROC;
typedef uint32_t DWORD;
typedef DWORD *PDWORD;
typedef DWORD *LPDWORD;
typedef int32_t LONG;
typedef LONG *PLONG;
typedef uint32_t ULONG;
typedef ULONG *PULONG;
typedef int64_t LARGE_INTEGER;
typedef LARGE_INTEGER *PLARGE_INTEGER;
typedef uintptr_t ULONG_PTR;
typedef char *LPSTR;
typedef const char *LPCSTR;
typedef uint16_t *LPWSTR;
typedef const uint16_t *LPCWSTR;
typedef int BOOL;
typedef BOOL *PBOOL;
typedef unsigned char UCHAR;
typedef UCHAR *PUCHAR;
typedef size_t SIZE_T;
typedef SIZE_T *PSIZE_T;
typedef unsigned char BYTE;
#define TRUE 1
#define FALSE 0
#define ERROR_SUCCESS 0
#define ERROR_FILE_NOT_FOUND 2
#define ERROR_PATH_NOT_FOUND 3
#define ERROR_ACCESS_DENIED 5
#define ERROR_INVALID_HANDLE 6
#define ERROR_READ_FAULT 30
#define ERROR_HANDLE_EOF 38
#define ERROR_NOT_SUPPORTED 50
#define ERROR_INVALID_PARAMETER 87
#define ERROR_NEGATIVE_SEEK 131
#define ERROR_ALREADY_EXISTS 183
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
#define INVALID_HANDLE_VALUE ((HANDLE)-1)
typedef int NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008)
#define STATUS_END_OF_FILE ((NTSTATUS)0xC0000011)
#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BB)
#define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS)0xC00000E9)
typedef int HRESULT;
#define S_OK ((HRESULT)0x00000000)
namespace wibo {
extern uint32_t lastError;
extern char **argv;
extern int argc;
extern char *commandLine;
extern bool debugEnabled;
void debug_log(const char *fmt, ...);
void *resolveVersion(const char *name);
void *resolveKernel32(const char *name);
void *resolveUser32(const char *name);
void *resolveOle32(const char *name);
void *resolveAdvApi32(const char *name);
void *resolveLmgr(uint16_t ordinal);
void *resolveFuncByName(const char *dllName, const char *funcName);
void *resolveFuncByOrdinal(const char *dllName, uint16_t ordinal);
using ResolveByName = void *(*)(const char *);
using ResolveByOrdinal = void *(*)(uint16_t);
struct Module {
const char** names;
ResolveByName byName;
ResolveByOrdinal byOrdinal;
};
extern const Module *modules[];
HMODULE loadModule(const char *name);
void freeModule(HMODULE module);
void *resolveFuncByName(HMODULE module, const char *funcName);
void *resolveFuncByOrdinal(HMODULE module, uint16_t ordinal);
struct Executable {
Executable();

View File

@ -7,8 +7,17 @@ namespace advapi32 {
}
}
void *wibo::resolveAdvApi32(const char *name) {
static void *resolveByName(const char *name) {
if (strcmp(name, "RegOpenKeyExA") == 0) return (void *) advapi32::RegOpenKeyExA;
return 0;
return nullptr;
}
wibo::Module lib_advapi32 = {
(const char *[]){
"advapi32",
"advapi32.dll",
nullptr,
},
resolveByName,
nullptr,
};

38
dll/bcrypt.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "common.h"
#include <algorithm>
#include <climits>
#include <random>
typedef PVOID BCRYPT_ALG_HANDLE;
namespace bcrypt {
using random_bytes_engine = std::independent_bits_engine<std::default_random_engine, CHAR_BIT, unsigned char>;
NTSTATUS WIN_FUNC BCryptGenRandom(BCRYPT_ALG_HANDLE hAlgorithm, PUCHAR pbBuffer, ULONG cbBuffer, ULONG dwFlags) {
DEBUG_LOG("BCryptGenRandom(%p, %p, %lu, %lu)\n", hAlgorithm, pbBuffer, cbBuffer, dwFlags);
assert(hAlgorithm == nullptr);
assert(dwFlags == 0 || dwFlags == 2 /* BCRYPT_USE_SYSTEM_PREFERRED_RNG */);
random_bytes_engine rbe;
std::generate(pbBuffer, pbBuffer + cbBuffer, std::ref(rbe));
return STATUS_SUCCESS;
}
} // namespace bcrypt
static void *resolveByName(const char *name) {
if (strcmp(name, "BCryptGenRandom") == 0)
return (void *)bcrypt::BCryptGenRandom;
return nullptr;
}
wibo::Module lib_bcrypt = {
(const char *[]){
"bcrypt",
"bcrypt.dll",
nullptr,
},
resolveByName,
nullptr,
};

140
dll/crt.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "common.h"
typedef void (*_PVFV)();
typedef int (*_PIFV)();
typedef enum _crt_app_type {
_crt_unknown_app,
_crt_console_app,
_crt_gui_app,
} _crt_app_type;
typedef enum _crt_argv_mode {
_crt_argv_no_arguments,
_crt_argv_unexpanded_arguments,
_crt_argv_expanded_arguments,
} _crt_argv_mode;
namespace crt {
int _commode = 0;
void WIN_ENTRY _initterm(const _PVFV *ppfn, const _PVFV *end) {
do {
if (_PVFV pfn = *++ppfn) {
pfn();
}
} while (ppfn < end);
}
int WIN_ENTRY _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
do {
if (_PIFV pfn = *++ppfn) {
if (int err = pfn())
return err;
}
} while (ppfn < end);
return 0;
}
void WIN_ENTRY _set_app_type(_crt_app_type type) { DEBUG_LOG("STUB: _set_app_type(%i)\n", type); }
int WIN_ENTRY _set_fmode(int mode) {
DEBUG_LOG("STUB: _set_fmode(%i)\n", mode);
return 0;
}
int *WIN_ENTRY __p__commode() { return &_commode; }
int WIN_ENTRY _crt_atexit(void (*func)()) {
DEBUG_LOG("STUB: _crt_atexit(%p)\n", func);
return 0;
}
int WIN_ENTRY _configure_narrow_argv(_crt_argv_mode mode) {
DEBUG_LOG("STUB: _configure_narrow_argv(%i)\n", mode);
return 0;
}
int WIN_ENTRY _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask) {
DEBUG_LOG("STUB: _controlfp_s(%p, %u, %u)\n", currentControl, newControl, mask);
return 0;
}
int WIN_ENTRY _configthreadlocale(int per_thread_locale_type) {
DEBUG_LOG("STUB: _configthreadlocale(%i)\n", per_thread_locale_type);
return 0;
}
int WIN_ENTRY _initialize_narrow_environment() {
DEBUG_LOG("STUB: _initialize_narrow_environment()\n");
return 0;
}
int WIN_ENTRY _set_new_mode(int newhandlermode) {
DEBUG_LOG("STUB: _set_new_mode(%i)\n", newhandlermode);
return 0;
}
char **WIN_ENTRY _get_initial_narrow_environment() { return environ; }
char ***WIN_ENTRY __p___argv() { return &wibo::argv; }
int *WIN_ENTRY __p___argc() { return &wibo::argc; }
size_t WIN_ENTRY strlen(const char *str) { return ::strlen(str); }
} // namespace crt
static void *resolveByName(const char *name) {
if (strcmp(name, "_initterm") == 0)
return (void *)crt::_initterm;
if (strcmp(name, "_initterm_e") == 0)
return (void *)crt::_initterm_e;
if (strcmp(name, "_set_app_type") == 0)
return (void *)crt::_set_app_type;
if (strcmp(name, "_set_fmode") == 0)
return (void *)crt::_set_fmode;
if (strcmp(name, "__p__commode") == 0)
return (void *)crt::__p__commode;
if (strcmp(name, "_crt_atexit") == 0)
return (void *)crt::_crt_atexit;
if (strcmp(name, "_configure_narrow_argv") == 0)
return (void *)crt::_configure_narrow_argv;
if (strcmp(name, "_controlfp_s") == 0)
return (void *)crt::_controlfp_s;
if (strcmp(name, "_configthreadlocale") == 0)
return (void *)crt::_configthreadlocale;
if (strcmp(name, "_initialize_narrow_environment") == 0)
return (void *)crt::_initialize_narrow_environment;
if (strcmp(name, "_set_new_mode") == 0)
return (void *)crt::_set_new_mode;
if (strcmp(name, "_get_initial_narrow_environment") == 0)
return (void *)crt::_get_initial_narrow_environment;
if (strcmp(name, "__p___argv") == 0)
return (void *)crt::__p___argv;
if (strcmp(name, "__p___argc") == 0)
return (void *)crt::__p___argc;
if (strcmp(name, "strlen") == 0)
return (void *)crt::strlen;
return nullptr;
}
wibo::Module lib_crt = {
(const char *[]){
"api-ms-win-crt-heap-l1-1-0",
"api-ms-win-crt-heap-l1-1-0.dll",
"api-ms-win-crt-locale-l1-1-0",
"api-ms-win-crt-locale-l1-1-0.dll",
"api-ms-win-crt-runtime-l1-1-0",
"api-ms-win-crt-runtime-l1-1-0.dll",
"api-ms-win-crt-stdio-l1-1-0",
"api-ms-win-crt-stdio-l1-1-0.dll",
"api-ms-win-crt-string-l1-1-0",
"api-ms-win-crt-string-l1-1-0.dll",
nullptr,
},
resolveByName,
nullptr,
};

View File

@ -12,6 +12,27 @@
#include <sys/mman.h>
#include <sys/stat.h>
typedef union _RTL_RUN_ONCE {
PVOID Ptr;
} RTL_RUN_ONCE, *PRTL_RUN_ONCE;
typedef PRTL_RUN_ONCE LPINIT_ONCE;
#define EXCEPTION_MAXIMUM_PARAMETERS 15
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode;
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress;
DWORD NumberParameters;
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
typedef void *PCONTEXT;
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord;
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
typedef LONG (*PVECTORED_EXCEPTION_HANDLER)(PEXCEPTION_POINTERS ExceptionInfo);
namespace kernel32 {
static int wstrlen(const uint16_t *str) {
int len = 0;
@ -20,6 +41,17 @@ namespace kernel32 {
return len;
}
static int wstrncpy(uint16_t *dst, const uint16_t *src, int n) {
int i = 0;
while (i < n && src[i] != 0) {
dst[i] = src[i];
++i;
}
if (i < n)
dst[i] = 0;
return i;
}
static void *doAlloc(unsigned int dwBytes, bool zero) {
if (dwBytes == 0)
dwBytes = 1;
@ -99,15 +131,43 @@ namespace kernel32 {
return st.st_size;
}
void setLastErrorFromErrno() {
switch (errno) {
case 0:
wibo::lastError = ERROR_SUCCESS;
break;
case EACCES:
wibo::lastError = ERROR_ACCESS_DENIED;
break;
case EEXIST:
wibo::lastError = ERROR_ALREADY_EXISTS;
break;
case ENOENT:
wibo::lastError = ERROR_FILE_NOT_FOUND;
break;
case ENOTDIR:
wibo::lastError = ERROR_PATH_NOT_FOUND;
break;
default:
wibo::lastError = ERROR_NOT_SUPPORTED;
break;
}
}
uint32_t WIN_FUNC GetLastError() {
return wibo::lastError;
}
void WIN_FUNC SetLastError(unsigned int dwErrCode) {
// DEBUG_LOG("SetLastError %u\n", dwErrCode);
DEBUG_LOG("SetLastError(%u)\n", dwErrCode);
wibo::lastError = dwErrCode;
}
PVOID WIN_FUNC AddVectoredExceptionHandler(ULONG first, PVECTORED_EXCEPTION_HANDLER handler) {
DEBUG_LOG("STUB: AddVectoredExceptionHandler(%u, %p)\n", first, handler);
return (PVOID)handler;
}
// @brief returns a pseudo handle to the current process
void *WIN_FUNC GetCurrentProcess() {
// pseudo handle is always returned, and is -1 (a special constant)
@ -129,7 +189,7 @@ namespace kernel32 {
// Cast thread_id to unsigned int to fit a DWORD
unsigned int u_thread_id = (unsigned int) thread_id;
return u_thread_id;
}
@ -224,6 +284,24 @@ namespace kernel32 {
return 1;
}
int WIN_FUNC InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID* lpContext) {
DEBUG_LOG("STUB: InitOnceBeginInitialize\n");
return 1;
}
void WIN_FUNC AcquireSRWLockShared(void *SRWLock) { DEBUG_LOG("STUB: AcquireSRWLockShared(%p)\n", SRWLock); }
void WIN_FUNC ReleaseSRWLockShared(void *SRWLock) { DEBUG_LOG("STUB: ReleaseSRWLockShared(%p)\n", SRWLock); }
void WIN_FUNC AcquireSRWLockExclusive(void *SRWLock) { DEBUG_LOG("STUB: AcquireSRWLockExclusive(%p)\n", SRWLock); }
void WIN_FUNC ReleaseSRWLockExclusive(void *SRWLock) { DEBUG_LOG("STUB: ReleaseSRWLockExclusive(%p)\n", SRWLock); }
int WIN_FUNC TryAcquireSRWLockExclusive(void *SRWLock) {
DEBUG_LOG("STUB: TryAcquireSRWLockExclusive(%p)\n", SRWLock);
return 1;
}
/*
* TLS (Thread-Local Storage)
*/
@ -305,13 +383,13 @@ namespace kernel32 {
/*
* Environment
*/
char *WIN_FUNC GetCommandLineA() {
LPSTR WIN_FUNC GetCommandLineA() {
DEBUG_LOG("GetCommandLineA\n");
return wibo::commandLine;
}
uint16_t *WIN_FUNC GetCommandLineW() {
DEBUG_LOG("GetCommandLineW\n");
LPWSTR WIN_FUNC GetCommandLineW() {
DEBUG_LOG("GetCommandLineW -> ");
return stringToWideString(GetCommandLineA());
}
@ -408,8 +486,8 @@ namespace kernel32 {
assert(0);
}
int WIN_FUNC CloseHandle(void *hObject) {
DEBUG_LOG("CloseHandle %p\n", hObject);
BOOL WIN_FUNC CloseHandle(HANDLE hObject) {
DEBUG_LOG("CloseHandle(%p)\n", hObject);
auto data = handles::dataFromHandle(hObject, true);
if (data.type == handles::TYPE_FILE) {
FILE *fp = (FILE *) data.ptr;
@ -421,14 +499,14 @@ namespace kernel32 {
munmap(data.ptr, data.size);
}
}
return 1;
return TRUE;
}
unsigned int WIN_FUNC GetFullPathNameA(const char *lpFileName, unsigned int nBufferLength, char *lpBuffer, char **lpFilePart) {
DEBUG_LOG("GetFullPathNameA(%s)...\n", lpFileName);
DWORD WIN_FUNC GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart) {
DEBUG_LOG("GetFullPathNameA(%s) ", lpFileName);
std::filesystem::path absPath = std::filesystem::absolute(files::pathFromWindows(lpFileName));
std::string absStr = files::pathToWindows(absPath);
DEBUG_LOG("AbsPath: %s - %s\n", absPath.c_str(), absStr.c_str());
DEBUG_LOG("-> %s\n", absStr.c_str());
// Enough space?
if ((absStr.size() + 1) <= nBufferLength) {
@ -450,13 +528,36 @@ 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());
const auto lpFileNameA = wideStringToString(lpFileName);
std::filesystem::path absPath = std::filesystem::absolute(files::pathFromWindows(lpFileNameA.c_str()));
std::string absStr = files::pathToWindows(absPath);
const auto absStrW = stringToWideString(absStr.c_str());
DEBUG_LOG("-> %s\n", absStr.c_str());
const DWORD absStrWLen = wstrlen(absStrW);
const DWORD absStrWSize = absStrWLen * 2;
if ((absStrWSize + 2) <= nBufferLength) {
wstrncpy(lpBuffer, absStrW, (int)absStrWLen);
assert(!lpFilePart);
free(absStrW);
return absStrWSize;
} else {
free(absStrW);
return absStrWSize + 2;
}
}
/**
* @brief GetShortPathNameA: Retrieves the short path form of the specified path
*
*
* @param[in] lpszLongPath The path string
* @param[out] lpszShortPath A pointer to a buffer to receive
* @param[in] cchBuffer The size of the buffer that lpszShortPath points to
* @return unsigned int
* @return unsigned int
*/
unsigned int WIN_FUNC GetShortPathNameA(const char* lpszLongPath, char* lpszShortPath, unsigned int cchBuffer) {
DEBUG_LOG("GetShortPathNameA(%s)...\n",lpszShortPath);
@ -640,7 +741,7 @@ namespace kernel32 {
}
unsigned int WIN_FUNC WriteFile(void *hFile, const void *lpBuffer, unsigned int nNumberOfBytesToWrite, unsigned int *lpNumberOfBytesWritten, void *lpOverlapped) {
DEBUG_LOG("WriteFile %p %d\n", hFile, nNumberOfBytesToWrite);
DEBUG_LOG("WriteFile(%p, %d)\n", hFile, nNumberOfBytesToWrite);
assert(!lpOverlapped);
wibo::lastError = 0;
@ -704,27 +805,20 @@ namespace kernel32 {
DEBUG_LOG("-> %p\n", handle);
return handle;
} else {
switch (errno) {
case EACCES:
wibo::lastError = 5; // ERROR_ACCESS_DENIED
break;
case EEXIST:
wibo::lastError = 183; // ERROR_ALREADY_EXISTS
break;
case ENOENT:
wibo::lastError = 2; // ERROR_FILE_NOT_FOUND
break;
case ENOTDIR:
wibo::lastError = 3; // ERROR_PATH_NOT_FOUND
break;
default:
wibo::lastError = 50; // ERROR_NOT_SUPPORTED
break;
}
return (void *) 0xFFFFFFFF; // INVALID_HANDLE_VALUE
setLastErrorFromErrno();
return INVALID_HANDLE_VALUE;
}
}
void *WIN_FUNC CreateFileW(const uint16_t *lpFileName, unsigned int dwDesiredAccess, unsigned int dwShareMode,
void *lpSecurityAttributes, unsigned int dwCreationDisposition, unsigned int dwFlagsAndAttributes,
void *hTemplateFile) {
DEBUG_LOG("CreateFileW -> ");
const auto lpFileNameA = wideStringToString(lpFileName);
return CreateFileA(lpFileNameA.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
}
void *WIN_FUNC CreateFileMappingA(
void *hFile,
void *lpFileMappingAttributes,
@ -790,22 +884,19 @@ namespace kernel32 {
return 1;
}
unsigned int WIN_FUNC SetFilePointer(void *hFile, int lDistanceToMove, int *lpDistanceToMoveHigh, int dwMoveMethod) {
DEBUG_LOG("SetFilePointer %p %d %d\n", hFile, lDistanceToMove, dwMoveMethod);
assert(!lpDistanceToMoveHigh);
DWORD WIN_FUNC SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
DEBUG_LOG("SetFilePointer(%p, %d, %d)\n", hFile, lDistanceToMove, dwMoveMethod);
assert(!lpDistanceToMoveHigh || *lpDistanceToMoveHigh == 0);
FILE *fp = files::fpFromHandle(hFile);
wibo::lastError = 0;
int r = fseek(fp, lDistanceToMove,
dwMoveMethod == 0 ? SEEK_SET :
dwMoveMethod == 1 ? SEEK_CUR :
SEEK_END);
wibo::lastError = ERROR_SUCCESS;
int r = fseek(fp, lDistanceToMove, dwMoveMethod == 0 ? SEEK_SET : dwMoveMethod == 1 ? SEEK_CUR : SEEK_END);
if (r < 0) {
if (errno == EINVAL)
wibo::lastError = 131; // ERROR_NEGATIVE_SEEK
wibo::lastError = ERROR_NEGATIVE_SEEK;
else
wibo::lastError = 87; // ERROR_INVALID_PARAMETER
return 0xFFFFFFFF; // INVALID_SET_FILE_POINTER
wibo::lastError = ERROR_INVALID_PARAMETER;
return INVALID_SET_FILE_POINTER;
}
r = ftell(fp);
@ -813,6 +904,27 @@ namespace kernel32 {
return r;
}
BOOL WIN_FUNC SetFilePointerEx(HANDLE hFile, LARGE_INTEGER lDistanceToMove, PLARGE_INTEGER lpDistanceToMoveHigh,
DWORD dwMoveMethod) {
assert(!lpDistanceToMoveHigh || *lpDistanceToMoveHigh == 0);
DEBUG_LOG("SetFilePointerEx(%p, %ld, %d)\n", hFile, lDistanceToMove, dwMoveMethod);
FILE *fp = files::fpFromHandle(hFile);
wibo::lastError = ERROR_SUCCESS;
int r = fseeko64(fp, lDistanceToMove, dwMoveMethod == 0 ? SEEK_SET : dwMoveMethod == 1 ? SEEK_CUR : SEEK_END);
if (r < 0) {
if (errno == EINVAL)
wibo::lastError = ERROR_NEGATIVE_SEEK;
else
wibo::lastError = ERROR_INVALID_PARAMETER;
return INVALID_SET_FILE_POINTER;
}
r = ftell(fp);
assert(r >= 0);
return TRUE;
}
int WIN_FUNC SetEndOfFile(void *hFile) {
DEBUG_LOG("SetEndOfFile\n");
FILE *fp = files::fpFromHandle(hFile);
@ -931,6 +1043,53 @@ namespace kernel32 {
return 1;
}
struct BY_HANDLE_FILE_INFORMATION {
unsigned long dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
unsigned long dwVolumeSerialNumber;
unsigned long nFileSizeHigh;
unsigned long nFileSizeLow;
unsigned long nNumberOfLinks;
unsigned long nFileIndexHigh;
unsigned long nFileIndexLow;
};
int WIN_FUNC GetFileInformationByHandle(void *hFile, BY_HANDLE_FILE_INFORMATION *lpFileInformation) {
DEBUG_LOG("GetFileInformationByHandle(%p, %p)\n", hFile, lpFileInformation);
FILE* fp = files::fpFromHandle(hFile);
if (fp == nullptr) {
wibo::lastError = 6; // ERROR_INVALID_HANDLE
return 0;
}
struct stat64 st{};
if (fstat64(fileno(fp), &st)) {
setLastErrorFromErrno();
return 0;
}
if (lpFileInformation != nullptr) {
lpFileInformation->dwFileAttributes = 0;
if (S_ISDIR(st.st_mode)) {
lpFileInformation->dwFileAttributes |= 0x10;
}
if (S_ISREG(st.st_mode)) {
lpFileInformation->dwFileAttributes |= 0x80;
}
lpFileInformation->ftCreationTime = defaultFiletime;
lpFileInformation->ftLastAccessTime = defaultFiletime;
lpFileInformation->ftLastWriteTime = defaultFiletime;
lpFileInformation->dwVolumeSerialNumber = 0;
lpFileInformation->nFileSizeHigh = (unsigned long) (st.st_size >> 32);
lpFileInformation->nFileSizeLow = (unsigned long) st.st_size;
lpFileInformation->nNumberOfLinks = 0;
lpFileInformation->nFileIndexHigh = 0;
lpFileInformation->nFileIndexLow = 0;
}
return 1;
}
struct TIME_ZONE_INFORMATION {
int Bias;
short StandardName[32];
@ -951,7 +1110,7 @@ namespace kernel32 {
* Console Nonsense
*/
int WIN_FUNC GetConsoleMode(void *hConsoleHandle, unsigned int *lpMode) {
DEBUG_LOG("GetConsoleMode %p", hConsoleHandle);
DEBUG_LOG("GetConsoleMode(%p)\n", hConsoleHandle);
*lpMode = 0;
return 1;
}
@ -988,6 +1147,25 @@ namespace kernel32 {
return 1;
}
BOOL WIN_FUNC WriteConsoleW(HANDLE hConsoleOutput, LPCWSTR lpBuffer, DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten,
LPVOID lpReserved) {
DEBUG_LOG("WriteConsoleW(%p, %p, %u, %p, %p)\n", hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten,
lpReserved);
const auto str = wideStringToString(lpBuffer, nNumberOfCharsToWrite);
FILE *fp = files::fpFromHandle(hConsoleOutput);
if (fp == stdout || fp == stderr) {
fprintf(fp, "%s", str.c_str());
if (lpNumberOfCharsWritten) {
*lpNumberOfCharsWritten = nNumberOfCharsToWrite;
}
return TRUE;
}
if (lpNumberOfCharsWritten) {
*lpNumberOfCharsWritten = 0;
}
return FALSE;
}
unsigned int WIN_FUNC GetSystemDirectoryA(char *lpBuffer, unsigned int uSize) {
DEBUG_LOG("GetSystemDirectoryA(%p, %u)\n", lpBuffer, uSize);
if (lpBuffer == nullptr) {
@ -1056,8 +1234,8 @@ namespace kernel32 {
return path.size();
}
void* WIN_FUNC GetModuleHandleA(const char* lpModuleName) {
DEBUG_LOG("GetModuleHandleA %s\n", lpModuleName);
HMODULE WIN_FUNC GetModuleHandleA(LPCSTR lpModuleName) {
DEBUG_LOG("GetModuleHandleA(%s)\n", lpModuleName);
if (!lpModuleName) {
// If lpModuleName is NULL, GetModuleHandle returns a handle to the file
@ -1067,21 +1245,17 @@ namespace kernel32 {
}
// wibo::lastError = 0;
return (void*)0x100001;
return wibo::loadModule(lpModuleName);
}
void* WIN_FUNC GetModuleHandleW(const uint16_t* lpModuleName) {
if (wibo::debugEnabled) {
std::string moduleName = lpModuleName ? wideStringToString(lpModuleName) : "<null>";
DEBUG_LOG("GetModuleHandleW: %s\n", moduleName.c_str());
HMODULE WIN_FUNC GetModuleHandleW(LPCWSTR lpModuleName) {
DEBUG_LOG("GetModuleHandleW -> ");
if (lpModuleName) {
const auto lpModuleNameA = wideStringToString(lpModuleName);
return GetModuleHandleA(lpModuleNameA.c_str());
} else {
return GetModuleHandleA(nullptr);
}
if (!lpModuleName) {
return wibo::mainModule->imageBuffer;
}
// wibo::lastError = 0;
return (void*)0x100001;
}
unsigned int WIN_FUNC GetModuleFileNameA(void* hModule, char* lpFilename, unsigned int nSize) {
@ -1122,23 +1296,22 @@ namespace kernel32 {
return 0;
}
void* WIN_FUNC LoadLibraryA(const char* lpLibFileName) {
DEBUG_LOG("LoadLibraryA %s\n", lpLibFileName);
return (void*)0x100005;
HMODULE WIN_FUNC LoadLibraryA(LPCSTR lpLibFileName) {
DEBUG_LOG("LoadLibraryA(%s)\n", lpLibFileName);
return wibo::loadModule(lpLibFileName);
}
void* WIN_FUNC LoadLibraryExW(const uint16_t* lpLibFileName, void* hFile, unsigned int dwFlags) {
if (wibo::debugEnabled) {
std::string filename = wideStringToString(lpLibFileName);
DEBUG_LOG("LoadLibraryExW: %s\n", filename.c_str());
}
return (void*)0x100005;
HMODULE WIN_FUNC LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) {
assert(!hFile);
DEBUG_LOG("LoadLibraryExW(%x) -> ", dwFlags);
const auto filename = wideStringToString(lpLibFileName);
return LoadLibraryA(filename.c_str());
}
int WIN_FUNC FreeLibrary(void* hLibModule) {
DEBUG_LOG("FreeLibrary %p\n", hLibModule);
return 1;
BOOL WIN_FUNC FreeLibrary(HMODULE hLibModule) {
DEBUG_LOG("FreeLibrary(%p)\n", hLibModule);
wibo::freeModule(hLibModule);
return TRUE;
}
const unsigned int MAJOR_VER = 6, MINOR_VER = 2, BUILD_NUMBER = 0; // Windows 8
@ -1269,6 +1442,21 @@ namespace kernel32 {
memset(lpStartupInfo, 0, sizeof(_STARTUPINFOW));
}
BOOL WIN_FUNC SetThreadStackGuarantee(PULONG StackSizeInBytes) {
DEBUG_LOG("STUB: SetThreadStackGuarantee(%p)\n", StackSizeInBytes);
return TRUE;
}
HANDLE WIN_FUNC GetCurrentThread() {
DEBUG_LOG("STUB: GetCurrentThread\n");
return (HANDLE)0x100007;
}
HRESULT WIN_FUNC SetThreadDescription(HANDLE hThread, const void * /* PCWSTR */ lpThreadDescription) {
DEBUG_LOG("STUB: SetThreadDescription(%p, %p)\n", hThread, lpThreadDescription);
return S_OK;
}
unsigned short WIN_FUNC GetFileType(void *hFile) {
DEBUG_LOG("GetFileType %p\n", hFile);
return 1; // FILE_TYPE_DISK
@ -1392,32 +1580,32 @@ namespace kernel32 {
return 1;
}
void *WIN_FUNC GetProcAddress(void *hModule, char *lpProcName) {
DEBUG_LOG("GetProcAddress: %s from %p\n", lpProcName, hModule);
if (strcmp(lpProcName, "IsProcessorFeaturePresent") == 0) return (void *) IsProcessorFeaturePresent;
// if (strcmp(lpProcName, "InitializeCriticalSectionEx") == 0) return (void *) InitializeCriticalSectionEx;
// if (strcmp(lpProcName, "FlsSetValue") == 0) return (void *) FlsSetValue;
// if (strcmp(lpProcName, "FlsFree") == 0) return (void *) FlsFree;
// if (strcmp(lpProcName, "LCMapStringEx") == 0) return (void *) LCMapStringEx;
// if (strcmp(lpProcName, "LocaleNameToLCID") == 0) return (void *) LocaleNameToLCID;
if (strcmp(lpProcName, "MessageBoxA") == 0) return (void *) user32::MessageBoxA;
return NULL;
FARPROC WIN_FUNC GetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
FARPROC result;
const auto proc = reinterpret_cast<uintptr_t>(lpProcName);
if (proc & ~0xFFFF) {
DEBUG_LOG("GetProcAddress(%p, %s) ", hModule, lpProcName);
result = wibo::resolveFuncByName(hModule, lpProcName);
} else {
DEBUG_LOG("GetProcAddress(%p, %u) ", hModule, proc);
result = wibo::resolveFuncByOrdinal(hModule, static_cast<uint16_t>(proc));
}
DEBUG_LOG("-> %p\n", result);
return result;
}
void *WIN_FUNC HeapAlloc(void *hHeap, unsigned int dwFlags, size_t dwBytes) {
DEBUG_LOG("HeapAlloc(heap=%p, flags=%x, bytes=%u)\n", hHeap, dwFlags, dwBytes);
DEBUG_LOG("HeapAlloc(heap=%p, flags=%x, bytes=%u) ", hHeap, dwFlags, dwBytes);
void *mem = doAlloc(dwBytes, dwFlags & 8);
DEBUG_LOG("HeapAlloc returning %p\n", mem);
DEBUG_LOG("-> %p\n", mem);
return mem;
}
void *WIN_FUNC HeapReAlloc(void *hHeap, unsigned int dwFlags, void *lpMem, size_t dwBytes) {
DEBUG_LOG("HeapReAlloc(heap=%p, flags=%x, mem=%p, bytes=%u)\n", hHeap, dwFlags, lpMem, dwBytes);
DEBUG_LOG("HeapReAlloc(heap=%p, flags=%x, mem=%p, bytes=%u) ", hHeap, dwFlags, lpMem, dwBytes);
void *ret = doRealloc(lpMem, dwBytes, dwFlags & 8);
DEBUG_LOG("HeapReAlloc returning %p\n", ret);
DEBUG_LOG("-> %p\n", ret);
return ret;
}
@ -1488,6 +1676,11 @@ namespace kernel32 {
return Ptr;
}
BOOL WIN_FUNC SetDllDirectoryA(LPCSTR lpPathName) {
DEBUG_LOG("STUB: SetDllDirectoryA(%s)\n", lpPathName);
return TRUE;
}
int WIN_FUNC CompareStringA(int Locale, unsigned int dwCmpFlags, const char *lpString1, unsigned int cchCount1, const char *lpString2, unsigned int cchCount2) {
if (cchCount1 < 0)
cchCount1 = strlen(lpString1);
@ -1548,6 +1741,11 @@ namespace kernel32 {
return 1;
}
BOOL WIN_FUNC IsDBCSLeadByte(BYTE TestChar) {
DEBUG_LOG("IsDBCSLeadByte(%u)\n", TestChar);
return FALSE; // We're not multibyte (yet?)
}
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) {
@ -1566,11 +1764,47 @@ namespace kernel32 {
return 0; // fail
}
DWORD WIN_FUNC GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize) {
DEBUG_LOG("GetEnvironmentVariableA: %s\n", lpName);
const char *value = getenv(lpName);
if (!value) {
return 0;
}
unsigned int len = strlen(value);
if (nSize == 0) {
return len + 1;
}
if (nSize < len) {
return len;
}
memcpy(lpBuffer, value, len + 1);
return len;
}
unsigned int WIN_FUNC SetEnvironmentVariableA(const char *lpName, const char *lpValue) {
DEBUG_LOG("SetEnvironmentVariableA: %s=%s\n", lpName, lpValue);
return setenv(lpName, lpValue, 1 /* OVERWRITE */);
}
DWORD WIN_FUNC GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize) {
DEBUG_LOG("GetEnvironmentVariableW: %s\n", wideStringToString(lpName).c_str());
const char *value = getenv(wideStringToString(lpName).c_str());
if (!value) {
return 0;
}
unsigned int len = strlen(value) * 2;
if (nSize == 0) {
return len + 2;
}
if (nSize < len) {
return len;
}
const uint16_t *wideValue = stringToWideString(value);
memcpy(lpBuffer, wideValue, len + 2);
free((void *)wideValue);
return len;
}
unsigned int WIN_FUNC QueryPerformanceCounter(unsigned long int *lpPerformanceCount) {
DEBUG_LOG("QueryPerformanceCounter\n");
*lpPerformanceCount = 0;
@ -1653,10 +1887,11 @@ namespace kernel32 {
}
}
void *wibo::resolveKernel32(const char *name) {
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, "AddVectoredExceptionHandler") == 0) return (void *) kernel32::AddVectoredExceptionHandler;
// processthreadsapi.h
if (strcmp(name, "IsProcessorFeaturePresent") == 0) return (void *) kernel32::IsProcessorFeaturePresent;
@ -1671,6 +1906,9 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "TlsSetValue") == 0) return (void *) kernel32::TlsSetValue;
if (strcmp(name, "GetStartupInfoA") == 0) return (void *) kernel32::GetStartupInfoA;
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, "SetThreadDescription") == 0) return (void *) kernel32::SetThreadDescription;
// winnls.h
if (strcmp(name, "GetSystemDefaultLangID") == 0) return (void *) kernel32::GetSystemDefaultLangID;
@ -1684,6 +1922,7 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "LCMapStringA") == 0) return (void *) kernel32::LCMapStringA;
if (strcmp(name, "GetLocaleInfoA") == 0) return (void *) kernel32::GetLocaleInfoA;
if (strcmp(name, "GetUserDefaultLCID") == 0) return (void *) kernel32::GetUserDefaultLCID;
if (strcmp(name, "IsDBCSLeadByte") == 0) return (void *) kernel32::IsDBCSLeadByte;
// synchapi.h
if (strcmp(name, "InitializeCriticalSection") == 0) return (void *) kernel32::InitializeCriticalSection;
@ -1692,6 +1931,13 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "DeleteCriticalSection") == 0) return (void *) kernel32::DeleteCriticalSection;
if (strcmp(name, "EnterCriticalSection") == 0) return (void *) kernel32::EnterCriticalSection;
if (strcmp(name, "LeaveCriticalSection") == 0) return (void *) kernel32::LeaveCriticalSection;
if (strcmp(name, "InitOnceBeginInitialize") == 0) return (void *) kernel32::InitOnceBeginInitialize;
if (strcmp(name, "AcquireSRWLockShared") == 0) return (void *) kernel32::AcquireSRWLockShared;
if (strcmp(name, "ReleaseSRWLockShared") == 0) return (void *) kernel32::ReleaseSRWLockShared;
if (strcmp(name, "ReleaseSRWLockShared") == 0) return (void *) kernel32::AcquireSRWLockShared;
if (strcmp(name, "AcquireSRWLockExclusive") == 0) return (void *) kernel32::AcquireSRWLockExclusive;
if (strcmp(name, "ReleaseSRWLockExclusive") == 0) return (void *) kernel32::ReleaseSRWLockExclusive;
if (strcmp(name, "TryAcquireSRWLockExclusive") == 0) return (void *) kernel32::TryAcquireSRWLockExclusive;
// winbase.h
if (strcmp(name, "GlobalAlloc") == 0) return (void *) kernel32::GlobalAlloc;
@ -1706,6 +1952,7 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "GetComputerNameA") == 0) return (void *) kernel32::GetComputerNameA;
if (strcmp(name, "EncodePointer") == 0) return (void *) kernel32::EncodePointer;
if (strcmp(name, "DecodePointer") == 0) return (void *) kernel32::DecodePointer;
if (strcmp(name, "SetDllDirectoryA") == 0) return (void *) kernel32::SetDllDirectoryA;
// processenv.h
if (strcmp(name, "GetCommandLineA") == 0) return (void *) kernel32::GetCommandLineA;
@ -1714,7 +1961,9 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "FreeEnvironmentStringsA") == 0) return (void *) kernel32::FreeEnvironmentStringsA;
if (strcmp(name, "GetEnvironmentStringsW") == 0) return (void *) kernel32::GetEnvironmentStringsW;
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, "GetEnvironmentVariableW") == 0) return (void *) kernel32::GetEnvironmentVariableW;
// console api
if (strcmp(name, "GetStdHandle") == 0) return (void *) kernel32::GetStdHandle;
@ -1724,9 +1973,11 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "GetConsoleMode") == 0) return (void *) kernel32::GetConsoleMode;
if (strcmp(name, "SetConsoleCtrlHandler") == 0) return (void *) kernel32::SetConsoleCtrlHandler;
if (strcmp(name, "GetConsoleScreenBufferInfo") == 0) return (void *) kernel32::GetConsoleScreenBufferInfo;
if (strcmp(name, "WriteConsoleW") == 0) return (void *) kernel32::WriteConsoleW;
// fileapi.h
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, "FindFirstFileA") == 0) return (void *) kernel32::FindFirstFileA;
if (strcmp(name, "FindFirstFileExA") == 0) return (void *) kernel32::FindFirstFileExA;
@ -1736,11 +1987,13 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "WriteFile") == 0) return (void *) kernel32::WriteFile;
if (strcmp(name, "ReadFile") == 0) return (void *) kernel32::ReadFile;
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, "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, "SetFilePointer") == 0) return (void *) kernel32::SetFilePointer;
if (strcmp(name, "SetFilePointerEx") == 0) return (void *) kernel32::SetFilePointerEx;
if (strcmp(name, "SetEndOfFile") == 0) return (void *) kernel32::SetEndOfFile;
if (strcmp(name, "CreateDirectoryA") == 0) return (void *) kernel32::CreateDirectoryA;
if (strcmp(name, "RemoveDirectoryA") == 0) return (void *) kernel32::RemoveDirectoryA;
@ -1750,6 +2003,7 @@ void *wibo::resolveKernel32(const char *name) {
if (strcmp(name, "SetFileTime") == 0) return (void *) kernel32::SetFileTime;
if (strcmp(name, "GetFileType") == 0) return (void *) kernel32::GetFileType;
if (strcmp(name, "FileTimeToLocalFileTime") == 0) return (void *) kernel32::FileTimeToLocalFileTime;
if (strcmp(name, "GetFileInformationByHandle") == 0) return (void *) kernel32::GetFileInformationByHandle;
// sysinfoapi.h
if (strcmp(name, "GetSystemTime") == 0) return (void *) kernel32::GetSystemTime;
@ -1819,3 +2073,13 @@ void *wibo::resolveKernel32(const char *name) {
return 0;
}
wibo::Module lib_kernel32 = {
(const char *[]){
"kernel32",
"kernel32.dll",
nullptr,
},
resolveByName,
nullptr,
};

View File

@ -13,7 +13,7 @@ namespace lmgr {
}
}
void *wibo::resolveLmgr(uint16_t ordinal) {
static void *resolveByOrdinal(uint16_t ordinal) {
switch (ordinal) {
case 189:
return (void*)lmgr::lp_checkin;
@ -22,3 +22,17 @@ void *wibo::resolveLmgr(uint16_t ordinal) {
}
return 0;
}
wibo::Module lib_lmgr = {
(const char *[]){
"lmgr11",
"lmgr11.dll",
"lmgr326b",
"lmgr326b.dll",
"lmgr8c",
"lmgr8c.dll",
nullptr,
},
nullptr,
resolveByOrdinal,
};

165
dll/ntdll.cpp Normal file
View File

@ -0,0 +1,165 @@
#include "common.h"
#include "files.h"
#include <sys/mman.h>
#define PIO_APC_ROUTINE void *
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
namespace ntdll {
NTSTATUS WIN_FUNC NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset,
PULONG Key) {
DEBUG_LOG("NtReadFile(%p, %p, %p, %p, %p, %p, %u, %p, %p) ", FileHandle, Event, ApcRoutine, ApcContext,
IoStatusBlock, Buffer, Length, ByteOffset, Key);
assert(Event == nullptr);
assert(ApcRoutine == nullptr);
assert(ApcContext == nullptr);
assert(ByteOffset == nullptr);
assert(Key == nullptr);
wibo::lastError = 0;
FILE *fp = files::fpFromHandle(FileHandle);
if (!fp) {
wibo::lastError = ERROR_INVALID_HANDLE;
return STATUS_INVALID_HANDLE;
}
size_t read = fread(Buffer, 1, Length, fp);
NTSTATUS status = STATUS_SUCCESS;
if (read < Length) {
if (feof(fp)) {
wibo::lastError = ERROR_HANDLE_EOF;
status = STATUS_END_OF_FILE;
} else {
wibo::lastError = ERROR_READ_FAULT; // ?
status = STATUS_UNEXPECTED_IO_ERROR;
}
}
if (IoStatusBlock) {
IoStatusBlock->Status = status;
IoStatusBlock->Information = read;
}
DEBUG_LOG("-> 0x%x\n", status);
return status;
}
#define PAGE_NOACCESS 0x1
#define PAGE_READONLY 0x2
#define PAGE_READWRITE 0x4
#define PAGE_WRITECOPY 0x8
#define PAGE_EXECUTE 0x10
#define PAGE_EXECUTE_READ 0x20
#define PAGE_EXECUTE_READWRITE 0x40
#define PAGE_EXECUTE_WRITECOPY 0x80
#define PAGE_GUARD 0x100
#define PAGE_NOCACHE 0x200
#define PAGE_WRITECOMBINE 0x400
NTSTATUS WIN_FUNC NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits,
PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect) {
DEBUG_LOG("NtAllocateVirtualMemory(%p, %p, %lu, %p, %lu, %lu) ", ProcessHandle, BaseAddress, ZeroBits, RegionSize,
AllocationType, Protect);
assert(ProcessHandle == (HANDLE)-1);
assert(ZeroBits == 0);
int prot = 0;
if (Protect & PAGE_NOACCESS)
prot |= PROT_NONE;
if (Protect & PAGE_READONLY)
prot |= PROT_READ;
if (Protect & PAGE_READWRITE)
prot |= PROT_READ | PROT_WRITE;
if (Protect & PAGE_WRITECOPY)
prot |= PROT_READ | PROT_WRITE;
if (Protect & PAGE_EXECUTE)
prot |= PROT_EXEC;
if (Protect & PAGE_EXECUTE_READ)
prot |= PROT_EXEC | PROT_READ;
if (Protect & PAGE_EXECUTE_READWRITE)
prot |= PROT_EXEC | PROT_READ | PROT_WRITE;
assert(!(Protect & PAGE_EXECUTE_WRITECOPY));
assert(!(Protect & PAGE_GUARD));
assert(!(Protect & PAGE_NOCACHE));
assert(!(Protect & PAGE_WRITECOMBINE));
void *addr = mmap(*BaseAddress, *RegionSize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
perror("mmap");
return STATUS_NOT_SUPPORTED;
}
*BaseAddress = addr;
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
return STATUS_SUCCESS;
}
NTSTATUS WIN_FUNC NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
ULONG NewAccessProtection, PULONG OldAccessProtection) {
DEBUG_LOG("NtProtectVirtualMemory(%p, %p, %p, %lu, %p) ", ProcessHandle, BaseAddress, NumberOfBytesToProtect,
NewAccessProtection, OldAccessProtection);
assert(ProcessHandle == (HANDLE)-1);
assert(NumberOfBytesToProtect != nullptr);
int prot = 0;
if (NewAccessProtection & PAGE_NOACCESS)
prot |= PROT_NONE;
if (NewAccessProtection & PAGE_READONLY)
prot |= PROT_READ;
if (NewAccessProtection & PAGE_READWRITE)
prot |= PROT_READ | PROT_WRITE;
if (NewAccessProtection & PAGE_WRITECOPY)
prot |= PROT_READ | PROT_WRITE;
if (NewAccessProtection & PAGE_EXECUTE)
prot |= PROT_EXEC;
if (NewAccessProtection & PAGE_EXECUTE_READ)
prot |= PROT_EXEC | PROT_READ;
if (NewAccessProtection & PAGE_EXECUTE_READWRITE)
prot |= PROT_EXEC | PROT_READ | PROT_WRITE;
assert(!(NewAccessProtection & PAGE_EXECUTE_WRITECOPY));
assert(!(NewAccessProtection & PAGE_GUARD));
assert(!(NewAccessProtection & PAGE_NOCACHE));
assert(!(NewAccessProtection & PAGE_WRITECOMBINE));
int ret = mprotect(*BaseAddress, *NumberOfBytesToProtect, prot);
if (ret != 0) {
perror("mprotect");
return STATUS_NOT_SUPPORTED;
}
if (OldAccessProtection) {
*OldAccessProtection = 0; // stub
}
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
return STATUS_SUCCESS;
}
} // namespace ntdll
static void *resolveByName(const char *name) {
if (strcmp(name, "NtReadFile") == 0)
return (void *)ntdll::NtReadFile;
if (strcmp(name, "NtAllocateVirtualMemory") == 0)
return (void *)ntdll::NtAllocateVirtualMemory;
if (strcmp(name, "NtProtectVirtualMemory") == 0)
return (void *)ntdll::NtProtectVirtualMemory;
return nullptr;
}
wibo::Module lib_ntdll = {
(const char *[]){
"ntdll",
"ntdll.dll",
nullptr,
},
resolveByName,
nullptr,
};

View File

@ -29,8 +29,18 @@ namespace ole32 {
}
}
void *wibo::resolveOle32(const char *name) {
static void *resolveByName(const char *name) {
if (strcmp(name, "CoInitialize") == 0) return (void *) ole32::CoInitialize;
if (strcmp(name, "CoCreateInstance") == 0) return (void *) ole32::CoCreateInstance;
return 0;
return nullptr;
}
wibo::Module lib_ole32 = {
(const char *[]){
"ole32",
"ole32.dll",
nullptr,
},
resolveByName,
nullptr,
};

View File

@ -105,8 +105,18 @@ namespace user32 {
}
}
void *wibo::resolveUser32(const char *name) {
static void *resolveByName(const char *name) {
if (strcmp(name, "LoadStringA") == 0) return (void *) user32::LoadStringA;
if (strcmp(name, "MessageBoxA") == 0) return (void *) user32::MessageBoxA;
return 0;
return nullptr;
}
wibo::Module lib_user32 = {
(const char *[]){
"user32",
"user32.dll",
nullptr,
},
resolveByName,
nullptr,
};

31
dll/vcruntime.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "common.h"
namespace vcruntime {
void *WIN_ENTRY memcpy(void *dest, const void *src, size_t count) { return ::memcpy(dest, src, count); }
void *WIN_ENTRY memset(void *dest, int ch, size_t count) { return ::memset(dest, ch, count); }
int WIN_ENTRY memcmp(const void *buf1, const void *buf2, size_t count) { return ::memcmp(buf1, buf2, count); }
} // namespace vcruntime
static void *resolveByName(const char *name) {
if (strcmp(name, "memcpy") == 0)
return (void *)vcruntime::memcpy;
if (strcmp(name, "memset") == 0)
return (void *)vcruntime::memset;
if (strcmp(name, "memcmp") == 0)
return (void *)vcruntime::memcmp;
return nullptr;
}
wibo::Module lib_vcruntime = {
(const char *[]){
"vcruntime140",
"vcruntime140.dll",
nullptr,
},
resolveByName,
nullptr,
};

View File

@ -9,7 +9,17 @@ namespace version {
}
}
void *wibo::resolveVersion(const char *name) {
static void *resolveByName(const char *name) {
if (strcmp(name, "GetFileVersionInfoSizeA") == 0) return (void *) version::GetFileVersionInfoSizeA;
return 0;
return nullptr;
}
wibo::Module lib_version = {
(const char *[]){
"version",
"version.dll",
nullptr,
},
resolveByName,
nullptr,
};

View File

@ -15,6 +15,11 @@ namespace files {
std::string str = inStr;
std::replace(str.begin(), str.end(), '\\', '/');
// Remove "//?/" prefix
if (str.rfind("//?/", 0) == 0) {
str.erase(0, 4);
}
// Remove the drive letter
if (str.rfind("z:/", 0) == 0 || str.rfind("Z:/", 0) == 0) {
str.erase(0, 2);

View File

@ -11,6 +11,6 @@ namespace files {
void init();
}
static bool endsWith(const std::string &str, const std::string &suffix) {
inline bool endsWith(const std::string &str, const std::string &suffix) {
return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}

View File

@ -188,22 +188,24 @@ bool wibo::Executable::loadPE(FILE *file) {
uint32_t *lookupTable = fromRVA(dir->importLookupTable);
uint32_t *addressTable = fromRVA(dir->importAddressTable);
HMODULE module = loadModule(dllName);
while (*lookupTable) {
uint32_t lookup = *lookupTable;
if (lookup & 0x80000000) {
// Import by ordinal
uint16_t ordinal = lookup & 0xFFFF;
DEBUG_LOG(" Ordinal: %d\n", ordinal);
*addressTable = (uint32_t) resolveFuncByOrdinal(dllName, ordinal);
*addressTable = reinterpret_cast<uintptr_t>(resolveFuncByOrdinal(module, ordinal));
} else {
// Import by name
PEHintNameTableEntry *hintName = fromRVA<PEHintNameTableEntry>(lookup);
DEBUG_LOG(" Name: %s\n", hintName->name);
*addressTable = (uint32_t) resolveFuncByName(dllName, hintName->name);
*addressTable = reinterpret_cast<uintptr_t>(resolveFuncByName(module, hintName->name));
}
++lookupTable;
++addressTable;
}
freeModule(module);
++dir;
}

112
main.cpp
View File

@ -8,9 +8,11 @@
#include <sys/syscall.h>
#include <stdarg.h>
#include <iostream>
#include <fstream>
#include <fstream>
uint32_t wibo::lastError = 0;
char** wibo::argv;
int wibo::argc;
char *wibo::commandLine;
wibo::Executable *wibo::mainModule = 0;
bool wibo::debugEnabled = false;
@ -54,48 +56,85 @@ FOR_256
#undef FOR_256_2
#undef FOR_256
static void *resolveMissingFunc(const char *dllName, const char *funcName) {
static void *resolveMissingFuncName(const char *dllName, const char *funcName) {
DEBUG_LOG("Missing function: %s (%s)\n", dllName, funcName);
assert(stubIndex < 0x100);
assert(strlen(dllName) < 0x100);
assert(strlen(funcName) < 0x100);
strcpy(stubFuncNames[stubIndex], funcName);
strcpy(stubDlls[stubIndex], dllName);
return (void *) stubFuncs[stubIndex++];
return (void *)stubFuncs[stubIndex++];
}
void *wibo::resolveFuncByName(const char *dllName, const char *funcName) {
void *func = nullptr;
if (strcasecmp(dllName, "KERNEL32.dll") == 0) {
func = wibo::resolveKernel32(funcName);
} else if (strcasecmp(dllName, "USER32.dll") == 0) {
func = wibo::resolveUser32(funcName);
} else if (strcasecmp(dllName, "ADVAPI32.dll") == 0) {
func = wibo::resolveAdvApi32(funcName);
} else if (strcasecmp(dllName, "VERSION.dll") == 0) {
func = wibo::resolveVersion(funcName);
} else if (strcasecmp(dllName, "OLE32.dll") == 0) {
func = wibo::resolveOle32(funcName);
}
if (func)
return func;
return resolveMissingFunc(dllName, funcName);
}
void *wibo::resolveFuncByOrdinal(const char *dllName, uint16_t ordinal) {
void *func;
if (strcmp(dllName, "LMGR11.dll") == 0 ||
strcmp(dllName, "LMGR326B.dll") == 0 ||
strcmp(dllName, "LMGR8C.dll") == 0) {
func = wibo::resolveLmgr(ordinal);
}
if (func)
return func;
static void *resolveMissingFuncOrdinal(const char *dllName, uint16_t ordinal) {
char buf[16];
sprintf(buf, "%d", ordinal);
return resolveMissingFunc(dllName, buf);
return resolveMissingFuncName(dllName, buf);
}
extern const wibo::Module lib_advapi32;
extern const wibo::Module lib_bcrypt;
extern const wibo::Module lib_crt;
extern const wibo::Module lib_kernel32;
extern const wibo::Module lib_lmgr;
extern const wibo::Module lib_ntdll;
extern const wibo::Module lib_ole32;
extern const wibo::Module lib_user32;
extern const wibo::Module lib_vcruntime;
extern const wibo::Module lib_version;
const wibo::Module * wibo::modules[] = {
&lib_advapi32,
&lib_bcrypt,
&lib_crt,
&lib_kernel32,
&lib_lmgr,
&lib_ntdll,
&lib_ole32,
&lib_user32,
&lib_vcruntime,
&lib_version,
nullptr,
};
struct ModuleInfo {
std::string name;
const wibo::Module* module = nullptr;
};
HMODULE wibo::loadModule(const char *dllName) {
auto *result = new ModuleInfo;
result->name = dllName;
for (int i = 0; modules[i]; i++) {
for (int j = 0; modules[i]->names[j]; j++) {
if (strcasecmp(dllName, modules[i]->names[j]) == 0) {
result->module = modules[i];
return result;
}
}
}
return result;
}
void wibo::freeModule(HMODULE module) { delete static_cast<ModuleInfo *>(module); }
void *wibo::resolveFuncByName(HMODULE module, const char *funcName) {
auto *info = static_cast<ModuleInfo *>(module);
if (info && info->module && info->module->byName) {
void *func = info->module->byName(funcName);
if (func)
return func;
}
return resolveMissingFuncName(info->name.c_str(), funcName);
}
void *wibo::resolveFuncByOrdinal(HMODULE module, uint16_t ordinal) {
auto *info = static_cast<ModuleInfo *>(module);
if (info && info->module && info->module->byOrdinal) {
void *func = info->module->byOrdinal(ordinal);
if (func)
return func;
}
return resolveMissingFuncOrdinal(info->name.c_str(), ordinal);
}
struct UNICODE_STRING {
@ -221,6 +260,9 @@ int main(int argc, char **argv) {
wibo::commandLine = cmdLine.data();
DEBUG_LOG("Command line: %s\n", wibo::commandLine);
wibo::argv = argv + 1;
wibo::argc = argc - 1;
wibo::Executable exec;
wibo::mainModule = &exec;
@ -259,13 +301,13 @@ int main(int argc, char **argv) {
holdingMapStart = std::max(holdingMapStart, FILL_MEMORY_ABOVE);
void* holdingMap = mmap((void*) holdingMapStart, holdingMapEnd - holdingMapStart, PROT_READ, MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, -1, 0);
if (holdingMap == MAP_FAILED) {
perror("Failed to create holding map");
return 1;
}
}
lastMapEnd = mapEnd;
}