#include "framework.h" #include "exception.hpp" HMODULE hm; std::vector iniPaths; bool iequals(std::wstring_view s1, std::wstring_view s2) { std::wstring str1(std::move(s1)); std::wstring str2(std::move(s2)); std::transform(str1.begin(), str1.end(), str1.begin(), [](wchar_t c) { return ::towlower(c); }); std::transform(str2.begin(), str2.end(), str2.begin(), [](wchar_t c) { return ::towlower(c); }); return (str1 == str2); } std::wstring to_wstring(std::string_view cstr) { std::string str(std::move(cstr)); auto charsReturned = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); std::wstring wstrTo(charsReturned, 0); MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], charsReturned); return wstrTo; } std::wstring SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken) { std::wstring r; WCHAR* szSystemPath = nullptr; if (SUCCEEDED(SHGetKnownFolderPath(rfid, dwFlags, hToken, &szSystemPath))) { r = szSystemPath; } CoTaskMemFree(szSystemPath); return r; }; HMODULE LoadLibraryW(const std::wstring& lpLibFileName) { return LoadLibraryW(lpLibFileName.c_str()); } std::wstring GetCurrentDirectoryW() { static constexpr auto INITIAL_BUFFER_SIZE = MAX_PATH; static constexpr auto MAX_ITERATIONS = 7; std::wstring ret; auto bufferSize = INITIAL_BUFFER_SIZE; for (size_t iterations = 0; iterations < MAX_ITERATIONS; ++iterations) { ret.resize(bufferSize); auto charsReturned = GetCurrentDirectoryW(bufferSize, &ret[0]); if (charsReturned < ret.length()) { ret.resize(charsReturned); return ret; } else { bufferSize *= 2; } } return L""; } UINT GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, const std::vector& fileNames) { for (const auto& file : fileNames) { nDefault = GetPrivateProfileIntW(lpAppName, lpKeyName, nDefault, file.c_str()); } return nDefault; } std::wstring GetSelfName() { const std::wstring moduleFileName = GetModuleFileNameW(hm); return moduleFileName.substr(moduleFileName.find_last_of(L"/\\") + 1); } template void GetSections(T&& h, Args... args) { const std::set< std::string_view, std::less<> > s = { args... }; size_t dwLoadOffset = (size_t)GetModuleHandle(NULL); BYTE* pImageBase = reinterpret_cast(dwLoadOffset); PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast(dwLoadOffset); PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast(pImageBase + pDosHeader->e_lfanew); PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader); for (int iSection = 0; iSection < pNtHeader->FileHeader.NumberOfSections; ++iSection, ++pSection) { auto pszSectionName = reinterpret_cast(pSection->Name); if (s.find(pszSectionName) != s.end()) { DWORD dwPhysSize = (pSection->Misc.VirtualSize + 4095) & ~4095; std::forward(h)(pSection, dwLoadOffset, dwPhysSize); } } } enum Kernel32ExportsNames { eGetStartupInfoA, eGetStartupInfoW, eGetModuleHandleA, eGetModuleHandleW, eGetProcAddress, eGetShortPathNameA, eFindNextFileA, eFindNextFileW, eLoadLibraryA, eLoadLibraryW, eFreeLibrary, eCreateEventA, eCreateEventW, eGetSystemInfo, eInterlockedCompareExchange, eSleep, Kernel32ExportsNamesCount }; enum Kernel32ExportsData { IATPtr, ProcAddress, Kernel32ExportsDataCount }; size_t Kernel32Data[Kernel32ExportsNamesCount][Kernel32ExportsDataCount]; static LONG OriginalLibraryLoaded = 0; void LoadOriginalLibrary() { if (_InterlockedCompareExchange(&OriginalLibraryLoaded, 1, 0) != 0) return; auto szSelfName = GetSelfName(); auto szSystemPath = SHGetKnownFolderPath(FOLDERID_System, 0, nullptr) + L'\\' + szSelfName; auto szLocalPath = GetModuleFileNameW(hm); szLocalPath = szLocalPath.substr(0, szLocalPath.find_last_of(L"/\\") + 1); if (iequals(szSelfName, L"dinput8.dll")) { dinput8.LoadOriginalLibrary(LoadLibraryW(szSystemPath)); } else if (iequals(szSelfName, L"dnsapi.dll")) { dnsapi.LoadOriginalLibrary(LoadLibraryW(szSystemPath)); } } void LoadDVA(std::wstring &path, LPCWSTR dir, LPCWSTR fileName) { if (GetModuleHandle(path.c_str()) == NULL) { auto h = LoadLibraryW(path); SetCurrentDirectoryW(dir); //in case dva switched it if (h == NULL) { auto e = GetLastError(); if (e != ERROR_DLL_INIT_FAILED) // in case dllmain returns false { std::wstring msg = L"Unable to load " + std::wstring(fileName) + L". Error: " + std::to_wstring(e); MessageBoxW(0, msg.c_str(), L"PD Loader", MB_ICONERROR); } } else { auto procedure = (void(*)())GetProcAddress(h, "InitializeDVA"); if (procedure != NULL) { procedure(); } } } } void FindFiles(WIN32_FIND_DATAW* fd) { auto dir = GetCurrentDirectoryW(); HANDLE dvaFile = FindFirstFileW(L"*.dva", fd); if (dvaFile != INVALID_HANDLE_VALUE) { do { if (!(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { auto pos = wcslen(fd->cFileName); if (fd->cFileName[pos - 4] == '.' && (fd->cFileName[pos - 3] == 'd' || fd->cFileName[pos - 3] == 'D') && (fd->cFileName[pos - 2] == 'v' || fd->cFileName[pos - 2] == 'V') && (fd->cFileName[pos - 1] == 'a' || fd->cFileName[pos - 1] == 'A') && GetPrivateProfileIntW(L"plugins", fd->cFileName, TRUE, iniPaths)) { auto path = dir + L'\\' + fd->cFileName; LoadDVA(path, dir.c_str(), fd->cFileName); } } } while (FindNextFileW(dvaFile, fd)); FindClose(dvaFile); } } void LoadPlugins() { auto oldDir = GetCurrentDirectoryW(); // store the current directory auto szSelfPath = GetModuleFileNameW(hm).substr(0, GetModuleFileNameW(hm).find_last_of(L"/\\") + 1); SetCurrentDirectoryW(szSelfPath.c_str()); auto nWantsToLoadPlugins = GetPrivateProfileIntW(L"global", L"enable", TRUE, iniPaths); if (nWantsToLoadPlugins) { if (SetCurrentDirectoryW(szSelfPath.c_str())) { WIN32_FIND_DATAW dh; HANDLE divaHook = FindFirstFileW(L"divahook.dll", &dh); if (divaHook != INVALID_HANDLE_VALUE && !(dh.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { printf("[PD Loader] Loading divahook.dll\n"); auto path = szSelfPath + L'\\' + dh.cFileName; LoadDVA(path, szSelfPath.c_str(), dh.cFileName); } if (SetCurrentDirectoryW(L"plugins\\")) { WIN32_FIND_DATAW fd; FindFiles(&fd); } } } SetCurrentDirectoryW(oldDir.c_str()); // Reset the current directory } static LONG LoadedPluginsYet = 0; void LoadEverything() { if (_InterlockedCompareExchange(&LoadedPluginsYet, 1, 0) != 0) return; LoadOriginalLibrary(); LoadPlugins(); } static LONG RestoredOnce = 0; void LoadPluginsAndRestoreIAT(uintptr_t retaddr) { bool calledFromBind = false; //steam drm check GetSections([&](PIMAGE_SECTION_HEADER pSection, size_t dwLoadOffset, DWORD dwPhysSize) { auto dwStart = static_cast(dwLoadOffset + pSection->VirtualAddress); auto dwEnd = dwStart + dwPhysSize; if (retaddr >= dwStart && retaddr <= dwEnd) calledFromBind = true; }, ".bind"); if (calledFromBind) return; if (_InterlockedCompareExchange(&RestoredOnce, 1, 0) != 0) return; LoadEverything(); for (size_t i = 0; i < Kernel32ExportsNamesCount; i++) { if (Kernel32Data[i][IATPtr] && Kernel32Data[i][ProcAddress]) { auto ptr = (size_t*)Kernel32Data[i][IATPtr]; DWORD dwProtect[2]; VirtualProtect(ptr, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]); *ptr = Kernel32Data[i][ProcAddress]; VirtualProtect(ptr, sizeof(size_t), dwProtect[0], &dwProtect[1]); } } } void WINAPI CustomGetStartupInfoA(LPSTARTUPINFOA lpStartupInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetStartupInfoA(lpStartupInfo); } void WINAPI CustomGetStartupInfoW(LPSTARTUPINFOW lpStartupInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetStartupInfoW(lpStartupInfo); } HMODULE WINAPI CustomGetModuleHandleA(LPCSTR lpModuleName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetModuleHandleA(lpModuleName); } HMODULE WINAPI CustomGetModuleHandleW(LPCWSTR lpModuleName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetModuleHandleW(lpModuleName); } FARPROC WINAPI CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetProcAddress(hModule, lpProcName); } DWORD WINAPI CustomGetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetShortPathNameA(lpszLongPath, lpszShortPath, cchBuffer); } BOOL WINAPI CustomFindNextFileA(HANDLE hFindFile, LPWIN32_FIND_DATAA lpFindFileData) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return FindNextFileA(hFindFile, lpFindFileData); } BOOL WINAPI CustomFindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return FindNextFileW(hFindFile, lpFindFileData); } HMODULE WINAPI CustomLoadLibraryA(LPCSTR lpLibFileName) { LoadOriginalLibrary(); return LoadLibraryA(lpLibFileName); } HMODULE WINAPI CustomLoadLibraryW(LPCWSTR lpLibFileName) { LoadOriginalLibrary(); return LoadLibraryW(lpLibFileName); } BOOL WINAPI CustomFreeLibrary(HMODULE hLibModule) { if (hLibModule != hm) return FreeLibrary(hLibModule); else return !NULL; } HANDLE WINAPI CustomCreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCSTR lpName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return CreateEventA(lpEventAttributes, bManualReset, bInitialState, lpName); } HANDLE WINAPI CustomCreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName); } void WINAPI CustomGetSystemInfo(LPSYSTEM_INFO lpSystemInfo) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return GetSystemInfo(lpSystemInfo); } LONG WINAPI CustomInterlockedCompareExchange(LONG volatile* Destination, LONG ExChange, LONG Comperand) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return _InterlockedCompareExchange(Destination, ExChange, Comperand); } void WINAPI CustomSleep(DWORD dwMilliseconds) { LoadPluginsAndRestoreIAT((uintptr_t)_ReturnAddress()); return Sleep(dwMilliseconds); } bool HookKernel32IAT(HMODULE mod, bool exe) { auto hExecutableInstance = (size_t)mod; IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hExecutableInstance + ((IMAGE_DOS_HEADER*)hExecutableInstance)->e_lfanew); IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hExecutableInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; if (exe) { Kernel32Data[eGetStartupInfoA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoA"); Kernel32Data[eGetStartupInfoW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetStartupInfoW"); Kernel32Data[eGetModuleHandleA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleA"); Kernel32Data[eGetModuleHandleW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetModuleHandleW"); Kernel32Data[eGetProcAddress][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetProcAddress"); Kernel32Data[eGetShortPathNameA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetShortPathNameA"); Kernel32Data[eFindNextFileA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileA"); Kernel32Data[eFindNextFileW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FindNextFileW"); Kernel32Data[eLoadLibraryA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryA"); Kernel32Data[eLoadLibraryW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "LoadLibraryW"); Kernel32Data[eFreeLibrary][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "FreeLibrary"); Kernel32Data[eCreateEventA][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventA"); Kernel32Data[eCreateEventW][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "CreateEventW"); Kernel32Data[eGetSystemInfo][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "GetSystemInfo"); Kernel32Data[eInterlockedCompareExchange][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "InterlockedCompareExchange"); Kernel32Data[eSleep][ProcAddress] = (size_t)GetProcAddress(GetModuleHandle(TEXT("KERNEL32.DLL")), "Sleep"); } uint32_t matchedImports = 0; auto PatchIAT = [&](size_t start, size_t end, size_t exe_end) { for (size_t i = 0; i < nNumImports; i++) { if (hExecutableInstance + (pImports + i)->FirstThunk > start && !(end && hExecutableInstance + (pImports + i)->FirstThunk > end)) end = hExecutableInstance + (pImports + i)->FirstThunk; } if (!end) { end = start + 0x100; } if (end > exe_end) //for very broken exes { start = hExecutableInstance; end = exe_end; } for (auto i = start; i < end; i += sizeof(size_t)) { DWORD dwProtect[2]; VirtualProtect((size_t*)i, sizeof(size_t), PAGE_EXECUTE_READWRITE, &dwProtect[0]); auto ptr = *(size_t*)i; if (!ptr) continue; if (ptr == Kernel32Data[eGetStartupInfoA][ProcAddress]) { if (exe) Kernel32Data[eGetStartupInfoA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetStartupInfoA; matchedImports++; } else if (ptr == Kernel32Data[eGetStartupInfoW][ProcAddress]) { if (exe) Kernel32Data[eGetStartupInfoW][IATPtr] = i; *(size_t*)i = (size_t)CustomGetStartupInfoW; matchedImports++; } else if (ptr == Kernel32Data[eGetModuleHandleA][ProcAddress]) { if (exe) Kernel32Data[eGetModuleHandleA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetModuleHandleA; matchedImports++; } else if (ptr == Kernel32Data[eGetModuleHandleW][ProcAddress]) { if (exe) Kernel32Data[eGetModuleHandleW][IATPtr] = i; *(size_t*)i = (size_t)CustomGetModuleHandleW; matchedImports++; } else if (ptr == Kernel32Data[eGetProcAddress][ProcAddress]) { if (exe) Kernel32Data[eGetProcAddress][IATPtr] = i; *(size_t*)i = (size_t)CustomGetProcAddress; matchedImports++; } else if (ptr == Kernel32Data[eGetShortPathNameA][ProcAddress]) { if (exe) Kernel32Data[eGetShortPathNameA][IATPtr] = i; *(size_t*)i = (size_t)CustomGetShortPathNameA; matchedImports++; } else if (ptr == Kernel32Data[eFindNextFileA][ProcAddress]) { if (exe) Kernel32Data[eFindNextFileA][IATPtr] = i; *(size_t*)i = (size_t)CustomFindNextFileA; matchedImports++; } else if (ptr == Kernel32Data[eFindNextFileW][ProcAddress]) { if (exe) Kernel32Data[eFindNextFileW][IATPtr] = i; *(size_t*)i = (size_t)CustomFindNextFileW; matchedImports++; } else if (ptr == Kernel32Data[eLoadLibraryA][ProcAddress]) { if (exe) Kernel32Data[eLoadLibraryA][IATPtr] = i; *(size_t*)i = (size_t)CustomLoadLibraryA; matchedImports++; } else if (ptr == Kernel32Data[eLoadLibraryW][ProcAddress]) { if (exe) Kernel32Data[eLoadLibraryW][IATPtr] = i; *(size_t*)i = (size_t)CustomLoadLibraryW; matchedImports++; } else if (ptr == Kernel32Data[eFreeLibrary][ProcAddress]) { if (exe) Kernel32Data[eFreeLibrary][IATPtr] = i; *(size_t*)i = (size_t)CustomFreeLibrary; matchedImports++; } else if (ptr == Kernel32Data[eCreateEventA][ProcAddress]) { if (exe) Kernel32Data[eCreateEventA][IATPtr] = i; *(size_t*)i = (size_t)CustomCreateEventA; matchedImports++; } else if (ptr == Kernel32Data[eCreateEventW][ProcAddress]) { if (exe) Kernel32Data[eCreateEventW][IATPtr] = i; *(size_t*)i = (size_t)CustomCreateEventW; matchedImports++; } else if (ptr == Kernel32Data[eGetSystemInfo][ProcAddress]) { if (exe) Kernel32Data[eGetSystemInfo][IATPtr] = i; *(size_t*)i = (size_t)CustomGetSystemInfo; matchedImports++; } else if (ptr == Kernel32Data[eInterlockedCompareExchange][ProcAddress]) { if (exe) Kernel32Data[eInterlockedCompareExchange][IATPtr] = i; *(size_t*)i = (size_t)CustomInterlockedCompareExchange; matchedImports++; } else if (ptr == Kernel32Data[eSleep][ProcAddress]) { if (exe) Kernel32Data[eSleep][IATPtr] = i; *(size_t*)i = (size_t)CustomSleep; matchedImports++; } VirtualProtect((size_t*)i, sizeof(size_t), dwProtect[0], &dwProtect[1]); } }; static auto getSection = [](const PIMAGE_NT_HEADERS nt_headers, unsigned section) -> PIMAGE_SECTION_HEADER { return reinterpret_cast( (UCHAR*)nt_headers->OptionalHeader.DataDirectory + nt_headers->OptionalHeader.NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY) + section * sizeof(IMAGE_SECTION_HEADER)); }; static auto getSectionEnd = [](IMAGE_NT_HEADERS* ntHeader, size_t inst) -> auto { auto sec = getSection(ntHeader, ntHeader->FileHeader.NumberOfSections - 1); auto secSize = max(sec->SizeOfRawData, sec->Misc.VirtualSize); auto end = inst + max(sec->PointerToRawData, sec->VirtualAddress) + secSize; return end; }; auto hExecutableInstance_end = getSectionEnd(ntHeader, hExecutableInstance); // Find kernel32.dll for (size_t i = 0; i < nNumImports; i++) { if ((size_t)(hExecutableInstance + (pImports + i)->Name) < hExecutableInstance_end) { if (!_stricmp((const char*)(hExecutableInstance + (pImports + i)->Name), "KERNEL32.DLL")) PatchIAT(hExecutableInstance + (pImports + i)->FirstThunk, 0, hExecutableInstance_end); } } // Fixing ordinals auto szSelfName = GetSelfName(); static auto PatchOrdinals = [&szSelfName](size_t hInstance) { IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(hInstance + ((IMAGE_DOS_HEADER*)hInstance)->e_lfanew); IMAGE_IMPORT_DESCRIPTOR* pImports = (IMAGE_IMPORT_DESCRIPTOR*)(hInstance + ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); size_t nNumImports = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1; for (size_t i = 0; i < nNumImports; i++) { if ((size_t)(hInstance + (pImports + i)->Name) < getSectionEnd(ntHeader, (size_t)hInstance)) { if (iequals(szSelfName, (to_wstring((const char*)(hInstance + (pImports + i)->Name))))) { PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(hInstance + (pImports + i)->OriginalFirstThunk); size_t j = 0; while (thunk->u1.Function) { if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)(hInstance + thunk->u1.AddressOfData); void** p = (void**)(hInstance + (pImports + i)->FirstThunk); if (iequals(szSelfName, L"dinput8.dll")) { DWORD Protect; VirtualProtect(&p[j], 4, PAGE_EXECUTE_READWRITE, &Protect); if ((IMAGE_ORDINAL(thunk->u1.Ordinal)) == 1) p[j] = _DirectInput8Create; } } ++thunk; } } } } }; ModuleList dlls; dlls.Enumerate(ModuleList::SearchLocation::LocalOnly); for (auto& e : dlls.m_moduleList) { PatchOrdinals((size_t)std::get(e)); } return matchedImports > 0; } LONG WINAPI CustomUnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) { // step 1: write minidump wchar_t modulename[MAX_PATH]; wchar_t filename[MAX_PATH]; wchar_t timestamp[128]; __time64_t time; struct tm ltime; HANDLE hFile; HWND hWnd; wchar_t* modulenameptr = NULL; if (GetModuleFileNameW(GetModuleHandle(NULL), modulename, _countof(modulename)) != 0) { modulenameptr = wcsrchr(modulename, '\\'); *modulenameptr = L'\0'; modulenameptr += 1; } else { *modulenameptr = L'err.err'; } _time64(&time); _localtime64_s(<ime, &time); wcsftime(timestamp, _countof(timestamp), L"%Y%m%d%H%M%S", <ime); swprintf_s(filename, L"%s\\%s\\%s.%s.dmp", modulename, L"logs", modulenameptr, timestamp); hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION ex; memset(&ex, 0, sizeof(ex)); ex.ThreadId = GetCurrentThreadId(); ex.ExceptionPointers = ExceptionInfo; ex.ClientPointers = TRUE; if (FAILED(MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs, &ex, NULL, NULL))) { } CloseHandle(hFile); } // step 2: write log // Logs exception into buffer and writes to file swprintf_s(filename, L"%s\\%s\\%s.%s.log", modulename, L"logs", modulenameptr, timestamp); hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { auto Log = [ExceptionInfo, hFile](char* buffer, size_t size, bool reg, bool stack, bool trace) { if (LogException(buffer, size, (LPEXCEPTION_POINTERS)ExceptionInfo, reg, stack, trace)) { DWORD NumberOfBytesWritten = 0; WriteFile(hFile, buffer, strlen(buffer), &NumberOfBytesWritten, NULL); } }; // Try to make a very descriptive exception, for that we need to malloc a huge buffer... if (auto buffer = (char*)malloc(max_logsize_ever)) { Log(buffer, max_logsize_ever, true, true, true); free(buffer); } else { // Use a static buffer, no need for any allocation static const auto size = max_logsize_basic + max_logsize_regs + max_logsize_stackdump; static char static_buf[size]; static_assert(size <= max_static_buffer, "Static buffer is too big"); Log(buffer = static_buf, sizeof(static_buf), true, true, false); } CloseHandle(hFile); } // step 3: exit the application ShowCursor(TRUE); hWnd = FindWindowW(0, L""); SetForegroundWindow(hWnd); return EXCEPTION_CONTINUE_SEARCH; } void Init() { std::wstring modulePath = GetModuleFileNameW(hm); std::wstring moduleName = modulePath.substr(modulePath.find_last_of(L"/\\") + 1); moduleName.resize(moduleName.find_last_of(L'.')); modulePath.resize(modulePath.find_last_of(L"/\\") + 1); iniPaths.emplace_back(modulePath + moduleName + L".ini"); iniPaths.emplace_back(modulePath + L"plugins\\config.ini"); std::wstring m = GetModuleFileNameW(NULL); m = m.substr(0, m.find_last_of(L"/\\") + 1) + L"logs"; auto FolderExists = [](LPCWSTR szPath) -> BOOL { DWORD dwAttrib = GetFileAttributes(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); }; if (FolderExists(m.c_str())) { SetUnhandledExceptionFilter(CustomUnhandledExceptionFilter); // Now stub out CustomUnhandledExceptionFilter so NO ONE ELSE can set it! uint32_t ret = 0x909090C3; //ret DWORD protect[2]; VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), PAGE_EXECUTE_READWRITE, &protect[0]); memcpy(&SetUnhandledExceptionFilter, &ret, sizeof(ret)); VirtualProtect(&SetUnhandledExceptionFilter, sizeof(ret), protect[0], &protect[1]); } LoadEverything(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID /*lpReserved*/) { if (reason == DLL_PROCESS_ATTACH) { hm = hModule; Init(); } return TRUE; }