diff --git a/common.h b/common.h index e69563f..d1eec02 100644 --- a/common.h +++ b/common.h @@ -26,6 +26,7 @@ typedef void *HMODULE; typedef void *PVOID; typedef void *LPVOID; typedef void *FARPROC; +typedef uint16_t WORD; typedef uint32_t DWORD; typedef DWORD *PDWORD; typedef DWORD *LPDWORD; diff --git a/dll/kernel32.cpp b/dll/kernel32.cpp index 624d243..91f38a5 100644 --- a/dll/kernel32.cpp +++ b/dll/kernel32.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -21,9 +22,46 @@ #include #include #include +#include #include #include +namespace { + using DWORD_PTR = uintptr_t; + + constexpr WORD PROCESSOR_ARCHITECTURE_INTEL = 0; + constexpr WORD PROCESSOR_ARCHITECTURE_ARM = 5; + constexpr WORD PROCESSOR_ARCHITECTURE_IA64 = 6; + constexpr WORD PROCESSOR_ARCHITECTURE_AMD64 = 9; + constexpr WORD PROCESSOR_ARCHITECTURE_ARM64 = 12; + constexpr WORD PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF; + + constexpr DWORD PROCESSOR_INTEL_386 = 386; + constexpr DWORD PROCESSOR_INTEL_486 = 486; + constexpr DWORD PROCESSOR_INTEL_PENTIUM = 586; + constexpr DWORD PROCESSOR_INTEL_IA64 = 2200; + constexpr DWORD PROCESSOR_AMD_X8664 = 8664; + + struct SYSTEM_INFO { + union { + DWORD dwOemId; + struct { + WORD wProcessorArchitecture; + WORD wReserved; + }; + }; + DWORD dwPageSize; + LPVOID lpMinimumApplicationAddress; + LPVOID lpMaximumApplicationAddress; + DWORD_PTR dwActiveProcessorMask; + DWORD dwNumberOfProcessors; + DWORD dwProcessorType; + DWORD dwAllocationGranularity; + WORD wProcessorLevel; + WORD wProcessorRevision; + }; +} + typedef union _RTL_RUN_ONCE { PVOID Ptr; } RTL_RUN_ONCE, *PRTL_RUN_ONCE; @@ -177,6 +215,88 @@ namespace kernel32 { return 1; // success in retrieval } + BOOL WIN_FUNC DisableThreadLibraryCalls(HMODULE hLibModule) { + DEBUG_LOG("DisableThreadLibraryCalls(%p)\n", hLibModule); + (void)hLibModule; + return TRUE; + } + + void WIN_FUNC GetSystemInfo(SYSTEM_INFO *lpSystemInfo) { + DEBUG_LOG("GetSystemInfo\n"); + if (!lpSystemInfo) { + return; + } + + std::memset(lpSystemInfo, 0, sizeof(*lpSystemInfo)); + + WORD architecture = PROCESSOR_ARCHITECTURE_UNKNOWN; + DWORD processorType = 0; + WORD processorLevel = 0; + +#if defined(__x86_64__) || defined(_M_X64) + architecture = PROCESSOR_ARCHITECTURE_AMD64; + processorType = PROCESSOR_AMD_X8664; + processorLevel = 6; +#elif defined(__i386__) || defined(_M_IX86) + architecture = PROCESSOR_ARCHITECTURE_INTEL; + processorType = PROCESSOR_INTEL_PENTIUM; + processorLevel = 6; +#elif defined(__aarch64__) + architecture = PROCESSOR_ARCHITECTURE_ARM64; + processorType = 0; + processorLevel = 8; +#elif defined(__arm__) + architecture = PROCESSOR_ARCHITECTURE_ARM; + processorType = 0; + processorLevel = 7; +#else + architecture = PROCESSOR_ARCHITECTURE_UNKNOWN; + processorType = 0; + processorLevel = 0; +#endif + + lpSystemInfo->wProcessorArchitecture = architecture; + lpSystemInfo->wReserved = 0; + lpSystemInfo->dwOemId = lpSystemInfo->wProcessorArchitecture; + lpSystemInfo->dwProcessorType = processorType; + lpSystemInfo->wProcessorLevel = processorLevel; + lpSystemInfo->wProcessorRevision = 0; + + long pageSize = sysconf(_SC_PAGESIZE); + if (pageSize <= 0) { + pageSize = 4096; + } + lpSystemInfo->dwPageSize = static_cast(pageSize); + + lpSystemInfo->lpMinimumApplicationAddress = reinterpret_cast(0x00010000); + if (sizeof(void *) == 4) { + lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast(0x7FFEFFFF); + } else { + lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast(0x00007FFFFFFEFFFFull); + } + + unsigned int cpuCount = 1; + long reported = sysconf(_SC_NPROCESSORS_ONLN); + if (reported > 0) { + cpuCount = static_cast(reported); + } + lpSystemInfo->dwNumberOfProcessors = cpuCount; + + unsigned int maskWidth = static_cast(sizeof(DWORD_PTR) * 8); + DWORD_PTR mask; + if (cpuCount >= maskWidth) { + mask = static_cast(~static_cast(0)); + } else { + mask = (static_cast(1) << cpuCount) - 1; + } + if (mask == 0) { + mask = 1; + } + lpSystemInfo->dwActiveProcessorMask = mask; + + lpSystemInfo->dwAllocationGranularity = 0x10000; + } + struct PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; @@ -2764,6 +2884,7 @@ static void *resolveByName(const char *name) { if (strcmp(name, "GetDiskFreeSpaceExW") == 0) return (void*) kernel32::GetDiskFreeSpaceExW; // sysinfoapi.h + if (strcmp(name, "GetSystemInfo") == 0) return (void *) kernel32::GetSystemInfo; if (strcmp(name, "GetSystemTime") == 0) return (void *) kernel32::GetSystemTime; if (strcmp(name, "GetLocalTime") == 0) return (void *) kernel32::GetLocalTime; if (strcmp(name, "GetSystemTimeAsFileTime") == 0) return (void *) kernel32::GetSystemTimeAsFileTime; @@ -2788,6 +2909,7 @@ static void *resolveByName(const char *name) { if (strcmp(name, "SizeofResource") == 0) return (void *) kernel32::SizeofResource; if (strcmp(name, "LoadLibraryA") == 0) return (void *) kernel32::LoadLibraryA; if (strcmp(name, "LoadLibraryExW") == 0) return (void *) kernel32::LoadLibraryExW; + if (strcmp(name, "DisableThreadLibraryCalls") == 0) return (void *) kernel32::DisableThreadLibraryCalls; if (strcmp(name, "FreeLibrary") == 0) return (void *) kernel32::FreeLibrary; if (strcmp(name, "GetProcAddress") == 0) return (void *) kernel32::GetProcAddress; diff --git a/dll/msvcrt.cpp b/dll/msvcrt.cpp index b9752af..57c8498 100644 --- a/dll/msvcrt.cpp +++ b/dll/msvcrt.cpp @@ -1,5 +1,6 @@ #include "common.h" #include +#include #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +22,7 @@ typedef void (*_PVFV)(); typedef int (*_PIFV)(); +using _onexit_t = _PIFV; namespace msvcrt { int _commode; @@ -29,6 +32,40 @@ namespace msvcrt { uint16_t* _wpgmptr; namespace { + struct DllOnExitTable { + _PVFV **pbegin; + _PVFV **pend; + std::vector<_PVFV> callbacks; + bool registered; + }; + + constexpr size_t LOCK_TABLE_SIZE = 64; + std::array &lockTable() { + static std::array table; + return table; + } + + std::vector &dllOnExitTables() { + static std::vector tables; + return tables; + } + + std::mutex &dllOnExitMutex() { + static std::mutex mutex; + return mutex; + } + + DllOnExitTable &ensureDllOnExitTable(_PVFV **pbegin, _PVFV **pend) { + auto &tables = dllOnExitTables(); + for (auto &table : tables) { + if (table.pbegin == pbegin && table.pend == pend) { + return table; + } + } + tables.push_back(DllOnExitTable{pbegin, pend, {}, false}); + return tables.back(); + } + template struct StringListStorage { std::vector> strings; @@ -336,10 +373,96 @@ namespace msvcrt { return std::malloc(size); } + void* WIN_ENTRY _malloc_crt(size_t size) { + return std::malloc(size); + } + + void WIN_ENTRY _lock(int locknum) { + if (locknum < 0 || static_cast(locknum) >= LOCK_TABLE_SIZE) { + DEBUG_LOG("_lock: unsupported lock %d\n", locknum); + return; + } + lockTable()[static_cast(locknum)].lock(); + } + + void WIN_ENTRY _unlock(int locknum) { + if (locknum < 0 || static_cast(locknum) >= LOCK_TABLE_SIZE) { + DEBUG_LOG("_unlock: unsupported lock %d\n", locknum); + return; + } + lockTable()[static_cast(locknum)].unlock(); + } + + _onexit_t WIN_ENTRY __dllonexit(_onexit_t func, _PVFV **pbegin, _PVFV **pend) { + if (!pbegin || !pend) { + return nullptr; + } + + std::lock_guard guard(dllOnExitMutex()); + auto &table = ensureDllOnExitTable(pbegin, pend); + if (!table.registered) { + wibo::registerOnExitTable(reinterpret_cast(pbegin)); + table.registered = true; + } + + if (func) { + auto callback = reinterpret_cast<_PVFV>(func); + table.callbacks.push_back(callback); + wibo::addOnExitFunction(reinterpret_cast(pbegin), reinterpret_cast(callback)); + } + + if (table.callbacks.empty()) { + *pbegin = nullptr; + *pend = nullptr; + } else { + _PVFV *dataPtr = table.callbacks.data(); + *pbegin = dataPtr; + *pend = dataPtr + table.callbacks.size(); + } + + return reinterpret_cast<_onexit_t>(func); + } + void WIN_ENTRY free(void* ptr){ std::free(ptr); } + static uint16_t toLower(uint16_t ch) { + if (ch >= 'A' && ch <= 'Z') { + return static_cast(ch + ('a' - 'A')); + } + wchar_t wide = static_cast(ch); + wchar_t lowered = std::towlower(wide); + if (lowered < 0 || lowered > 0xFFFF) { + return ch; + } + return static_cast(lowered); + } + + int WIN_ENTRY _wcsicmp(const uint16_t *lhs, const uint16_t *rhs) { + if (lhs == rhs) { + return 0; + } + if (!lhs) { + return -1; + } + if (!rhs) { + return 1; + } + + while (*lhs && *rhs) { + uint16_t a = toLower(*lhs++); + uint16_t b = toLower(*rhs++); + if (a != b) { + return static_cast(a) - static_cast(b); + } + } + + uint16_t a = toLower(*lhs); + uint16_t b = toLower(*rhs); + return static_cast(a) - static_cast(b); + } + int WIN_ENTRY _get_wpgmptr(uint16_t** pValue){ DEBUG_LOG("_get_wpgmptr(%p)\n", pValue); if(!pValue) return 22; @@ -760,8 +883,12 @@ static void *resolveByName(const char *name) { if (strcmp(name, "strcmp") == 0) return (void *)msvcrt::strcmp; if (strcmp(name, "strncmp") == 0) return (void *)msvcrt::strncmp; if (strcmp(name, "malloc") == 0) return (void*)msvcrt::malloc; - if (strcmp(name, "_malloc_crt") == 0) return (void*)msvcrt::malloc; + if (strcmp(name, "_malloc_crt") == 0) return (void*)msvcrt::_malloc_crt; + if (strcmp(name, "_lock") == 0) return (void*)msvcrt::_lock; + if (strcmp(name, "_unlock") == 0) return (void*)msvcrt::_unlock; + if (strcmp(name, "__dllonexit") == 0) return (void*)msvcrt::__dllonexit; if (strcmp(name, "free") == 0) return (void*)msvcrt::free; + if (strcmp(name, "_wcsicmp") == 0) return (void*)msvcrt::_wcsicmp; if (strcmp(name, "_get_wpgmptr") == 0) return (void*)msvcrt::_get_wpgmptr; if (strcmp(name, "_wsplitpath_s") == 0) return (void*)msvcrt::_wsplitpath_s; if (strcmp(name, "wcscat_s") == 0) return (void*)msvcrt::wcscat_s; diff --git a/loader.cpp b/loader.cpp index b074cf7..a8e1389 100644 --- a/loader.cpp +++ b/loader.cpp @@ -292,7 +292,7 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) { ++dir; } - entryPoint = fromRVA(header32.addressOfEntryPoint); + entryPoint = header32.addressOfEntryPoint ? fromRVA(header32.addressOfEntryPoint) : nullptr; return true; }