diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1eca5fb --- /dev/null +++ b/.clang-format @@ -0,0 +1,6 @@ +--- +BasedOnStyle: LLVM +IndentWidth: 4 +TabWidth: 4 +UseTab: Always +ColumnLimit: 120 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..0b060b7 --- /dev/null +++ b/.clang-tidy @@ -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' \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 170f78a..56153bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/common.h b/common.h index b150afe..844c42f 100644 --- a/common.h +++ b/common.h @@ -1,10 +1,11 @@ -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -#include // 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(); diff --git a/dll/advapi32.cpp b/dll/advapi32.cpp index 00b8c3f..ce627ac 100644 --- a/dll/advapi32.cpp +++ b/dll/advapi32.cpp @@ -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, +}; diff --git a/dll/bcrypt.cpp b/dll/bcrypt.cpp new file mode 100644 index 0000000..a2dc27b --- /dev/null +++ b/dll/bcrypt.cpp @@ -0,0 +1,38 @@ +#include "common.h" + +#include +#include +#include + +typedef PVOID BCRYPT_ALG_HANDLE; + +namespace bcrypt { + +using random_bytes_engine = std::independent_bits_engine; + +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, +}; diff --git a/dll/crt.cpp b/dll/crt.cpp new file mode 100644 index 0000000..61ff89f --- /dev/null +++ b/dll/crt.cpp @@ -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, +}; diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 0907703..5c1ca27 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -12,6 +12,27 @@ #include #include +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) : ""; - 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(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(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, +}; diff --git a/dll/lmgr.cpp b/dll/lmgr.cpp index 9a65919..4ed6d16 100644 --- a/dll/lmgr.cpp +++ b/dll/lmgr.cpp @@ -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, +}; diff --git a/dll/ntdll.cpp b/dll/ntdll.cpp new file mode 100644 index 0000000..d992647 --- /dev/null +++ b/dll/ntdll.cpp @@ -0,0 +1,165 @@ +#include "common.h" +#include "files.h" + +#include + +#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, +}; diff --git a/dll/ole32.cpp b/dll/ole32.cpp index 53eea1d..72f2df3 100644 --- a/dll/ole32.cpp +++ b/dll/ole32.cpp @@ -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, +}; diff --git a/dll/user32.cpp b/dll/user32.cpp index ffa035a..fc9c1b8 100644 --- a/dll/user32.cpp +++ b/dll/user32.cpp @@ -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, +}; diff --git a/dll/vcruntime.cpp b/dll/vcruntime.cpp new file mode 100644 index 0000000..ed31789 --- /dev/null +++ b/dll/vcruntime.cpp @@ -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, +}; diff --git a/dll/version.cpp b/dll/version.cpp index 6fddbdb..c7401a4 100644 --- a/dll/version.cpp +++ b/dll/version.cpp @@ -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, +}; diff --git a/files.cpp b/files.cpp index fbb0d88..a684ae3 100644 --- a/files.cpp +++ b/files.cpp @@ -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); diff --git a/files.h b/files.h index 1023b84..d86e927 100644 --- a/files.h +++ b/files.h @@ -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; } diff --git a/loader.cpp b/loader.cpp index 63b9100..a8766f4 100644 --- a/loader.cpp +++ b/loader.cpp @@ -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(resolveFuncByOrdinal(module, ordinal)); } else { // Import by name PEHintNameTableEntry *hintName = fromRVA(lookup); DEBUG_LOG(" Name: %s\n", hintName->name); - *addressTable = (uint32_t) resolveFuncByName(dllName, hintName->name); + *addressTable = reinterpret_cast(resolveFuncByName(module, hintName->name)); } ++lookupTable; ++addressTable; } + freeModule(module); ++dir; } diff --git a/main.cpp b/main.cpp index 41296f5..5a63bbc 100644 --- a/main.cpp +++ b/main.cpp @@ -8,9 +8,11 @@ #include #include #include -#include +#include 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(module); } + +void *wibo::resolveFuncByName(HMODULE module, const char *funcName) { + auto *info = static_cast(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(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; }