diff --git a/README.md b/README.md index 5736b59..1403e3a 100644 --- a/README.md +++ b/README.md @@ -1,173 +1,178 @@ Scylla - x64/x86 Imports Reconstruction ======================================= ImpREC, CHimpREC, Imports Fixer... this are all great tools to rebuild an import table, but they all have some major disadvantages, so I decided to create my own tool for this job. Scylla's key benefits are: - x64 and x86 support - full unicode support - written in C/C++ - plugin support - works great with Windows 7 This tool was designed to be used with Windows 7 x64, so it is recommend to use this operating system. But it may work with XP and Vista, too. Source code is licensed under GNU GENERAL PUBLIC LICENSE v3.0 Known Bugs ---------- ### Windows 7 x64 Sometimes the API kernel32.dll GetProcAddress cannot be resolved, because the IAT has an entry from apphelp.dll Solution? I don't know ### Only Windows XP x64: Windows XP x64 has some API bugs. 100% correct imports reconstruction is impossible. If you still want to use XP x64, here are some hints: * EncodePointer/DecodePointer exported by kernel32.dll have both the same VA. Scylla, CHimpREC and other tools cannot know which API is correct. You need to fix this manually. Your fixed dump will probably run fine on XP but crash on Vista/7. ### ImpREC plugin support: Some ImpREC Plugins don't work with Windows Vista/7 because they don't "return 1" in the DllMain function. Keyboard Shortcuts ------------------ - CTRL + D: [D]ump - CTRL + F: [F]ix Dump - CTRL + R: PE [R]ebuild - CTRL + O: L[o]ad Tree - CTRL + S: [S]ave Tree - CTRL + T: Auto[t]race - CTRL + G: [G]et Imports - CTRL + I: [I]AT Autosearch Changelog --------- +Version 0.9.8 + +- Bugfixes for x64, IAT Search +- diStorm3 update from Jan 3rd 2015 + Version 0.9.7 - Fixed bug bad allocation https://forum.tuts4you.com/topic/36458-scylla-097b-crash-on-pep-50-unpackme/ - Fixed bug https://forum.tuts4you.com/topic/35352-scylla-themida-v2180-iat-problem/ - Fixed bug with api selection https://forum.tuts4you.com/topic/35912-scylla-097-problem-acprotect/ - Included .NET binary + source, ScyllaToImprecTree to convert the api export to imprec Version 0.9.6 - improved iat search - fixed bug in api resolve engine - new option: parse APIs always from disk -> slower, useful against pe header modifications Version 0.9.5 - Fixed virtual device bug caused by QueryDosDeviceW bug - improved process lister - improved module lister - improved dump name - improved IAT parser Version 0.9.4 Final - direct import scanner (LEA, MOV, PUSH, CALL, JMP) + fixer with 2 fix methods - create new iat in section - fixed various bugs Version 0.9.3 - new dll function: iat search - new dll function: iat fix auto Version 0.9.2 - Pick DLL -> Set DLL Entrypoint - Advanced IAT Search Algorithm (Enable/Disable it in Options), thanks to ahmadmansoor - Fixed bug in Options - Added donate information, please feel free to donate some BTC to support this project Version 0.9.1 - Fixed virtual device bug - Fixed 2 minor bugs Version 0.9 - updated to distorm v3.3 - added application exception handler - fixed bug in dump engine - improved "suspend process" feature, messagebox on exit Version 0.8 - added OriginalFirstThunk support. Thanks to p0c - fixed malformed dos header bug - NtCreateThreadEx added infos from waliedassar, thanks! Version 0.7 Beta - fixed bug Overlapped Headers - fixed bug SizeOfOptionalHeader - added feature: suspend process for dumping, more information - improved disassembler - fixed various bugs Version 0.6b - internal code changes - added option: fix iat and oep Version 0.6a - fixed buffer to small bug in dump memory Version 0.6 - added dump memory regions - added dump pe sections -> you can edit some values in the dialog - improved dump engine with intelligent dumping - improved pe rebuild engine -> removed yoda's code - fixed various bugs Version 0.5a: - fixed memory leak - improved IAT search Version 0.5: - added save/load import tree feature - multi-select in tree view - fixed black icons problem in tree view - added keyboard shortcuts - dll dump + dll dump fix now working - added support for scattered IATs - pre select target path in open file dialogs - improved import resolving engine with api scoring - api selection dialog - minor bug fixes and improvements Version 0.4: - GUI code improvements - bug fixes - imports by ordinal Version 0.3a: - Improved import resolving - fixed buffer overflow errors Version 0.3: - ImpREC plugin support - minor bug fix diff --git a/Scylla/IATSearch.cpp b/Scylla/IATSearch.cpp index 973a3a1..8e2e73c 100644 --- a/Scylla/IATSearch.cpp +++ b/Scylla/IATSearch.cpp @@ -1,591 +1,594 @@ #include "IATSearch.h" #include "Scylla.h" #include "Architecture.h" //#define DEBUG_COMMENTS bool IATSearch::searchImportAddressTableInProcess( DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT, bool advanced ) { DWORD_PTR addressInIAT = 0; *addressIAT = 0; *sizeIAT = 0; if (advanced) { return findIATAdvanced(startAddress, addressIAT, sizeIAT); } addressInIAT = findAPIAddressInIAT(startAddress); if(!addressInIAT) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"searchImportAddressTableInProcess :: addressInIAT not found, startAddress " PRINTF_DWORD_PTR_FULL, startAddress); #endif return false; } else { return findIATStartAndSize(addressInIAT, addressIAT,sizeIAT); } } bool IATSearch::findIATAdvanced( DWORD_PTR startAddress, DWORD_PTR* addressIAT, DWORD* sizeIAT ) { BYTE *dataBuffer; DWORD_PTR baseAddress; SIZE_T memorySize; findExecutableMemoryPagesByStartAddress(startAddress, &baseAddress, &memorySize); if (memorySize == 0) return false; dataBuffer = new BYTE[memorySize]; if (!readMemoryFromProcess((DWORD_PTR)baseAddress, memorySize,dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAPIAddressInIAT2 :: error reading memory"); #endif return false; } std::set iatPointers; DWORD_PTR next; BYTE * tempBuf = dataBuffer; while(decomposeMemory(tempBuf, memorySize, (DWORD_PTR)baseAddress) && decomposerInstructionsCount != 0) { findIATPointers(iatPointers); next = (DWORD_PTR)(decomposerResult[decomposerInstructionsCount - 1].addr - baseAddress); next += decomposerResult[decomposerInstructionsCount - 1].size; // Advance ptr and recalc offset. tempBuf += next; if (memorySize <= next) { break; } memorySize -= next; baseAddress += next; } if (iatPointers.size() == 0) return false; filterIATPointersList(iatPointers); + if (iatPointers.size() == 0) + return false; + *addressIAT = *(iatPointers.begin()); *sizeIAT = (DWORD)(*(--iatPointers.end()) - *(iatPointers.begin()) + sizeof(DWORD_PTR)); //some check, more than 2 million addresses? if ((DWORD)(2000000*sizeof(DWORD_PTR)) < *sizeIAT) { *addressIAT = 0; *sizeIAT = 0; return false; } Scylla::windowLog.log(L"IAT Search Adv: Found %d (0x%X) possible IAT entries.", iatPointers.size(), iatPointers.size()); Scylla::windowLog.log(L"IAT Search Adv: Possible IAT first " PRINTF_DWORD_PTR_FULL L" last " PRINTF_DWORD_PTR_FULL L" entry.", *(iatPointers.begin()), *(--iatPointers.end())); delete [] dataBuffer; return true; } DWORD_PTR IATSearch::findAPIAddressInIAT(DWORD_PTR startAddress) { const size_t MEMORY_READ_SIZE = 200; BYTE dataBuffer[MEMORY_READ_SIZE]; DWORD_PTR iatPointer = 0; int counter = 0; // to detect stolen api memoryAddress = 0; memorySize = 0; do { counter++; if (!readMemoryFromProcess(startAddress, sizeof(dataBuffer), dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findAPIAddressInIAT :: error reading memory " PRINTF_DWORD_PTR_FULL, startAddress); #endif return 0; } if (decomposeMemory(dataBuffer, sizeof(dataBuffer), startAddress)) { iatPointer = findIATPointer(); if (iatPointer) { if (isIATPointerValid(iatPointer, true)) { return iatPointer; } } } startAddress = findNextFunctionAddress(); //printf("startAddress %08X\n",startAddress); } while (startAddress != 0 && counter != 8); return 0; } DWORD_PTR IATSearch::findNextFunctionAddress() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { if (decomposerResult[i].ops[0].type == O_PC) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_TARGET(&decomposerResult[i])); #endif return (DWORD_PTR)INSTRUCTION_GET_TARGET(&decomposerResult[i]); } } } } } return 0; } DWORD_PTR IATSearch::findIATPointer() { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { #ifdef _WIN64 if (decomposerResult[i].flags & FLAG_RIP_RELATIVE) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); #endif return INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i]); } #else if (decomposerResult[i].ops[0].type == O_DISP) { //jmp dword ptr || call dword ptr #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, decomposerResult[i].disp); #endif return (DWORD_PTR)decomposerResult[i].disp; } #endif } } } } return 0; } bool IATSearch::isIATPointerValid(DWORD_PTR iatPointer, bool checkRedirects) { DWORD_PTR apiAddress = 0; if (!readMemoryFromProcess(iatPointer,sizeof(DWORD_PTR),&apiAddress)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"isIATPointerValid :: error reading memory"); #endif return false; } //printf("Win api ? %08X\n",apiAddress); if (isApiAddressValid(apiAddress) != 0) { return true; } else { if (checkRedirects) { //maybe redirected import? //if the address is 2 times inside a memory region it is possible a redirected api if (apiAddress > memoryAddress && apiAddress < (memoryAddress+memorySize)) { return true; } else { getMemoryRegionFromAddress(apiAddress, &memoryAddress, &memorySize); } } } return false; } bool IATSearch::findIATStartAndSize(DWORD_PTR address, DWORD_PTR * addressIAT, DWORD * sizeIAT) { BYTE *dataBuffer = 0; DWORD_PTR baseAddress = 0; DWORD baseSize = 0; getMemoryBaseAndSizeForIat(address, &baseAddress, &baseSize); if (!baseAddress) return false; dataBuffer = new BYTE[baseSize * (sizeof(DWORD_PTR)*3)]; if (!dataBuffer) return false; ZeroMemory(dataBuffer, baseSize * (sizeof(DWORD_PTR)*3)); if (!readMemoryFromProcess(baseAddress, baseSize, dataBuffer)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATStartAddress :: error reading memory"); #endif return false; } //printf("address %X memBasic.BaseAddress %X memBasic.RegionSize %X\n",address,memBasic.BaseAddress,memBasic.RegionSize); *addressIAT = findIATStartAddress(baseAddress, address, dataBuffer); *sizeIAT = findIATSize(baseAddress, *addressIAT, dataBuffer, baseSize); delete [] dataBuffer; return true; } DWORD_PTR IATSearch::findIATStartAddress(DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE * dataBuffer) { DWORD_PTR *pIATAddress = 0; pIATAddress = (DWORD_PTR *)((startAddress - baseAddress) + (DWORD_PTR)dataBuffer); while((DWORD_PTR)pIATAddress != (DWORD_PTR)dataBuffer) { if (isInvalidMemoryForIat(*pIATAddress)) { if ((DWORD_PTR)(pIATAddress - 1) >= (DWORD_PTR)dataBuffer) { if (isInvalidMemoryForIat(*(pIATAddress - 1))) { if ((DWORD_PTR)(pIATAddress - 2) >= (DWORD_PTR)dataBuffer) { if (!isApiAddressValid(*(pIATAddress - 2))) { return (((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer) + baseAddress); } } } } } pIATAddress--; } return baseAddress; } DWORD IATSearch::findIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE * dataBuffer, DWORD bufferSize) { DWORD_PTR *pIATAddress = 0; pIATAddress = (DWORD_PTR *)((iatAddress - baseAddress) + (DWORD_PTR)dataBuffer); #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATSize :: baseAddress %X iatAddress %X dataBuffer %X pIATAddress %X", baseAddress, iatAddress, dataBuffer, pIATAddress); #endif while((DWORD_PTR)pIATAddress < ((DWORD_PTR)dataBuffer + bufferSize - 1)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATSize :: %X %X %X", pIATAddress, *pIATAddress, *(pIATAddress + 1)); #endif if (isInvalidMemoryForIat(*pIATAddress)) //normal is 0 { if (isInvalidMemoryForIat(*(pIATAddress + 1))) { //IAT end if (!isApiAddressValid(*(pIATAddress + 2))) { return (DWORD)((DWORD_PTR)pIATAddress - (DWORD_PTR)dataBuffer - (iatAddress - baseAddress)); } } } pIATAddress++; } return bufferSize; } void IATSearch::findIATPointers(std::set & iatPointers) { #ifdef DEBUG_COMMENTS _DecodedInst inst; #endif for (unsigned int i = 0; i < decomposerInstructionsCount; i++) { if (decomposerResult[i].flags != FLAG_NOT_DECODABLE) { if (META_GET_FC(decomposerResult[i].meta) == FC_CALL || META_GET_FC(decomposerResult[i].meta) == FC_UNC_BRANCH) { if (decomposerResult[i].size >= 5) { #ifdef _WIN64 if (decomposerResult[i].flags & FLAG_RIP_RELATIVE) { #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); #endif iatPointers.insert(INSTRUCTION_GET_RIP_TARGET(&decomposerResult[i])); } #else if (decomposerResult[i].ops[0].type == O_DISP) { //jmp dword ptr || call dword ptr #ifdef DEBUG_COMMENTS distorm_format(&decomposerCi, &decomposerResult[i], &inst); Scylla::debugLog.log(L"%S %S %d %d - target address: " PRINTF_DWORD_PTR_FULL, inst.mnemonic.p, inst.operands.p, decomposerResult[i].ops[0].type, decomposerResult[i].size, decomposerResult[i].disp); #endif iatPointers.insert((DWORD_PTR)decomposerResult[i].disp); } #endif } } } } } void IATSearch::findExecutableMemoryPagesByStartAddress( DWORD_PTR startAddress, DWORD_PTR* baseAddress, SIZE_T* memorySize ) { MEMORY_BASIC_INFORMATION memBasic = {0}; DWORD_PTR tempAddress; *memorySize = 0; *baseAddress = 0; if (VirtualQueryEx(hProcess,(LPCVOID)startAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { #ifdef DEBUG_COMMENTS Scylla::debugLog.log(L"findIATStartAddress :: VirtualQueryEx error %u", GetLastError()); #endif return; } //search down do { *memorySize = memBasic.RegionSize; *baseAddress = (DWORD_PTR)memBasic.BaseAddress; tempAddress = (DWORD_PTR)memBasic.BaseAddress - 1; if (VirtualQueryEx(hProcess, (LPCVOID)tempAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { break; } } while (isPageExecutable(memBasic.Protect)); tempAddress = *baseAddress; memBasic.RegionSize = *memorySize; *memorySize = 0; //search up do { tempAddress += memBasic.RegionSize; *memorySize += memBasic.RegionSize; if (VirtualQueryEx(hProcess, (LPCVOID)tempAddress, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION)) { break; } } while (isPageExecutable(memBasic.Protect)); } void IATSearch::filterIATPointersList( std::set & iatPointers ) { std::set::iterator iter; if (iatPointers.size() <= 2) { return; } iter = iatPointers.begin(); std::advance(iter, iatPointers.size() / 2); //start in the middle, important! DWORD_PTR lastPointer = *iter; iter++; for (; iter != iatPointers.end(); iter++) { if ((*iter - lastPointer) > 0x100) //check difference { if (isIATPointerValid(lastPointer, false) == false || isIATPointerValid(*iter, false) == false) { iatPointers.erase(iter, iatPointers.end()); break; } else { lastPointer = *iter; } } else { lastPointer = *iter; } } if (iatPointers.empty()) { return; } //delete bad code pointers. bool erased = true; while(erased) { if (iatPointers.size() <= 1) break; iter = iatPointers.begin(); lastPointer = *iter; iter++; for (; iter != iatPointers.end(); iter++) { if ((*iter - lastPointer) > 0x100) //check pointer difference, a typical difference is 4 on 32bit systems { bool isLastValid = isIATPointerValid(lastPointer, false); bool isCurrentValid = isIATPointerValid(*iter, false); if (isLastValid == false || isCurrentValid == false) { if (isLastValid == false) { iter--; } iatPointers.erase(iter); erased = true; break; } else { erased = false; lastPointer = *iter; } } else { erased = false; lastPointer = *iter; } } } } //A big section size is a common anti-debug/anti-dump trick, limit the max size to 100 000 000 bytes void adjustSizeForBigSections(DWORD * badValue) { if (*badValue > 100000000) { *badValue = 100000000; } } bool isSectionSizeTooBig(SIZE_T sectionSize) { return (sectionSize > 100000000); } void IATSearch::getMemoryBaseAndSizeForIat( DWORD_PTR address, DWORD_PTR* baseAddress, DWORD* baseSize ) { MEMORY_BASIC_INFORMATION memBasic1 = {0}; MEMORY_BASIC_INFORMATION memBasic2 = {0}; MEMORY_BASIC_INFORMATION memBasic3 = {0}; DWORD_PTR start = 0, end = 0; *baseAddress = 0; *baseSize = 0; if (!VirtualQueryEx(hProcess,(LPCVOID)address, &memBasic2, sizeof(MEMORY_BASIC_INFORMATION))) { return; } *baseAddress = (DWORD_PTR)memBasic2.BaseAddress; *baseSize = (DWORD)memBasic2.RegionSize; adjustSizeForBigSections(baseSize); //Get the neighbours if (VirtualQueryEx(hProcess,(LPCVOID)((DWORD_PTR)memBasic2.BaseAddress - 1), &memBasic1, sizeof(MEMORY_BASIC_INFORMATION))) { if (VirtualQueryEx(hProcess,(LPCVOID)((DWORD_PTR)memBasic2.BaseAddress + (DWORD_PTR)memBasic2.RegionSize), &memBasic3, sizeof(MEMORY_BASIC_INFORMATION))) { if (memBasic3.State != MEM_COMMIT || memBasic1.State != MEM_COMMIT || memBasic3.Protect & PAGE_NOACCESS || memBasic1.Protect & PAGE_NOACCESS) { return; } else { if (isSectionSizeTooBig(memBasic1.RegionSize) || isSectionSizeTooBig(memBasic2.RegionSize) || isSectionSizeTooBig(memBasic3.RegionSize)) { return; } start = (DWORD_PTR)memBasic1.BaseAddress; end = (DWORD_PTR)memBasic3.BaseAddress + (DWORD_PTR)memBasic3.RegionSize; *baseAddress = start; *baseSize = (DWORD)(end - start); } } } } diff --git a/Scylla/main.cpp b/Scylla/main.cpp index 59b1224..d629276 100644 --- a/Scylla/main.cpp +++ b/Scylla/main.cpp @@ -1,175 +1,178 @@ //#include // Visual Leak Detector #include // base ATL classes #include // base WTL classes #include "Architecture.h" CAppModule _Module; #include "MainGui.h" #include "Scylla.h" MainGui* pMainGui = NULL; // for Logger HINSTANCE hDllModule = 0; bool IsDllMode = false; LONG WINAPI HandleUnknownException(struct _EXCEPTION_POINTERS *ExceptionInfo); void AddExceptionHandler(); void RemoveExceptionHandler(); int InitializeGui(HINSTANCE hInstance, LPARAM param); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { AddExceptionHandler(); return InitializeGui(hInstance, (LPARAM)0); } int InitializeGui(HINSTANCE hInstance, LPARAM param) { CoInitialize(NULL); AtlInitCommonControls(ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES); Scylla::initAsGuiApp(); IsDllMode = false; HRESULT hRes = _Module.Init(NULL, hInstance); ATLASSERT(SUCCEEDED(hRes)); int nRet = 0; // BLOCK: Run application { MainGui dlgMain; pMainGui = &dlgMain; // o_O CMessageLoop loop; _Module.AddMessageLoop(&loop); dlgMain.Create(GetDesktopWindow(), param); dlgMain.ShowWindow(SW_SHOW); loop.Run(); } _Module.Term(); CoUninitialize(); return nRet; } void InitializeDll(HINSTANCE hinstDLL) { hDllModule = hinstDLL; IsDllMode = true; Scylla::initAsDll(); } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { // Perform actions based on the reason for calling. switch(fdwReason) { case DLL_PROCESS_ATTACH: // Initialize once for each new process. // Return FALSE to fail DLL load. AddExceptionHandler(); InitializeDll(hinstDLL); break; case DLL_THREAD_ATTACH: // Do thread-specific initialization. break; case DLL_THREAD_DETACH: // Do thread-specific cleanup. break; case DLL_PROCESS_DETACH: // Perform any necessary cleanup. RemoveExceptionHandler(); break; } return TRUE; // Successful DLL_PROCESS_ATTACH. } LPTOP_LEVEL_EXCEPTION_FILTER oldFilter; void AddExceptionHandler() { oldFilter = SetUnhandledExceptionFilter(HandleUnknownException); } void RemoveExceptionHandler() { SetUnhandledExceptionFilter(oldFilter); } LONG WINAPI HandleUnknownException(struct _EXCEPTION_POINTERS *ExceptionInfo) { WCHAR registerInfo[220]; WCHAR filepath[MAX_PATH] = {0}; WCHAR file[MAX_PATH] = {0}; WCHAR message[MAX_PATH + 200 + _countof(registerInfo)]; + WCHAR osInfo[100]; DWORD_PTR baseAddress = 0; DWORD_PTR address = (DWORD_PTR)ExceptionInfo->ExceptionRecord->ExceptionAddress; wcscpy_s(filepath, L"unknown"); wcscpy_s(file, L"unknown"); if (GetMappedFileNameW(GetCurrentProcess(), (LPVOID)address, filepath, _countof(filepath)) > 0) { WCHAR *temp = wcsrchr(filepath, '\\'); if (temp) { temp++; wcscpy_s(file, temp); } } + swprintf_s(osInfo, _countof(osInfo), TEXT("Exception! Please report it! OS: %X"), GetVersion()); + DWORD_PTR moduleBase = (DWORD_PTR)GetModuleHandleW(file); swprintf_s(message, _countof(message), TEXT("ExceptionCode %08X\r\nExceptionFlags %08X\r\nNumberParameters %08X\r\nExceptionAddress VA ")TEXT(PRINTF_DWORD_PTR_FULL_S)TEXT(" - Base ")TEXT(PRINTF_DWORD_PTR_FULL_S)TEXT("\r\nExceptionAddress module %s\r\n\r\n"), ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionFlags, ExceptionInfo->ExceptionRecord->NumberParameters, address, moduleBase, file); #ifdef _WIN64 swprintf_s(registerInfo, _countof(registerInfo),TEXT("rax=0x%p, rbx=0x%p, rdx=0x%p, rcx=0x%p, rsi=0x%p, rdi=0x%p, rbp=0x%p, rsp=0x%p, rip=0x%p"), ExceptionInfo->ContextRecord->Rax, ExceptionInfo->ContextRecord->Rbx, ExceptionInfo->ContextRecord->Rdx, ExceptionInfo->ContextRecord->Rcx, ExceptionInfo->ContextRecord->Rsi, ExceptionInfo->ContextRecord->Rdi, ExceptionInfo->ContextRecord->Rbp, ExceptionInfo->ContextRecord->Rsp, ExceptionInfo->ContextRecord->Rip ); #else swprintf_s(registerInfo, _countof(registerInfo),TEXT("eax=0x%p, ebx=0x%p, edx=0x%p, ecx=0x%p, esi=0x%p, edi=0x%p, ebp=0x%p, esp=0x%p, eip=0x%p"), ExceptionInfo->ContextRecord->Eax, ExceptionInfo->ContextRecord->Ebx, ExceptionInfo->ContextRecord->Edx, ExceptionInfo->ContextRecord->Ecx, ExceptionInfo->ContextRecord->Esi, ExceptionInfo->ContextRecord->Edi, ExceptionInfo->ContextRecord->Ebp, ExceptionInfo->ContextRecord->Esp, ExceptionInfo->ContextRecord->Eip ); #endif wcscat_s(message, _countof(message), registerInfo); - MessageBox(0, message, TEXT("Exception! Please report it!"), MB_ICONERROR); + MessageBox(0, message, osInfo, MB_ICONERROR); - return EXCEPTION_EXECUTE_HANDLER; + return EXCEPTION_CONTINUE_SEARCH; }