diff --git a/CHANGELOG.md b/CHANGELOG.md index c404e79b..b2c60fd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [1.0.5 / 5.55.5] - 2021-12-?? ### Added -- +- sandbox top level exception handler to create crash dumps +-- can be enabled per process or globally using "EnableMiniDump=process.exe,y" or "EnableMiniDump=y" respectivly +-- the dump flags can be set as hex with MiniDumpFlags=0xAABBCCDD +-- a presellected flag set for a verbose dump can be set with MiniDumpFlags=Extended +-- note: Created dump files are located at: C:\Sandbox\%SANDBOX% ### Changed - improved sbiedll initialization a bit ### Fixed - fixed issue with forced process display [#1447](https://github.com/sandboxie-plus/Sandboxie/issues/1447) +- fixed crash issue with GetClassName [#1448](https://github.com/sandboxie-plus/Sandboxie/issues/1448) diff --git a/Sandboxie/core/dll/SboxDll.vcxproj b/Sandboxie/core/dll/SboxDll.vcxproj index a42e660e..7a73dd19 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj +++ b/Sandboxie/core/dll/SboxDll.vcxproj @@ -240,6 +240,7 @@ + @@ -423,6 +424,7 @@ + diff --git a/Sandboxie/core/dll/SboxDll.vcxproj.filters b/Sandboxie/core/dll/SboxDll.vcxproj.filters index 1dd59a1f..0e744e64 100644 --- a/Sandboxie/core/dll/SboxDll.vcxproj.filters +++ b/Sandboxie/core/dll/SboxDll.vcxproj.filters @@ -4,7 +4,6 @@ - @@ -161,7 +160,6 @@ hook - common @@ -211,10 +209,18 @@ common\wow64ext + + debug + + + debug + + + debug + - hook @@ -252,7 +258,6 @@ com - common @@ -298,6 +303,15 @@ common + + debug + + + debug + + + debug + @@ -356,6 +370,9 @@ {c6a9654a-9f55-43ca-9cd1-7571bb879288} + + {db0f9820-8908-4325-96f9-69c82fa9e268} + diff --git a/Sandboxie/core/dll/dllmain.c b/Sandboxie/core/dll/dllmain.c index b52b6e4f..620b5129 100644 --- a/Sandboxie/core/dll/dllmain.c +++ b/Sandboxie/core/dll/dllmain.c @@ -25,6 +25,7 @@ #include "obj.h" #include "trace.h" #include "debug.h" +#include "dump.h" #include "core/low/lowdata.h" #include "common/my_version.h" @@ -529,6 +530,17 @@ _FX void Dll_InitExeEntry(void) // SbieDll_StartCOM(TRUE); + + // + // setup own top level exception handler + // + + if(Config_GetSettingsForImageName_bool(L"EnableMiniDump", FALSE)) + Dump_Init(); + + // + // once we return here the process images entrypoint will be called + // } diff --git a/Sandboxie/core/dll/dump.c b/Sandboxie/core/dll/dump.c new file mode 100644 index 00000000..738d4389 --- /dev/null +++ b/Sandboxie/core/dll/dump.c @@ -0,0 +1,245 @@ +/* + * Copyright 2021 DavidXanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// Dump Helper +//--------------------------------------------------------------------------- + +#include "dll.h" +#include "dump.h" + +#include + +//--------------------------------------------------------------------------- +// Defines +//--------------------------------------------------------------------------- + + +typedef BOOL (__stdcall *P_MiniDumpWriteDump)( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL + IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL + ); + +typedef LPTOP_LEVEL_EXCEPTION_FILTER(*P_SetUnhandledExceptionFilter)( + _In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); + +//--------------------------------------------------------------------------- +// Variables +//--------------------------------------------------------------------------- + + +static P_MiniDumpWriteDump __sys_MiniDumpWriteDump; +static HMODULE Dump_DbgHelpMod; + +#define DUMP_FLAGS_DEFAULT MiniDumpWithHandleData | \ + MiniDumpWithUnloadedModules | \ + MiniDumpFilterModulePaths | \ + MiniDumpWithProcessThreadData | \ + MiniDumpWithoutOptionalData | \ + MiniDumpIgnoreInaccessibleMemory | \ + MiniDumpFilterTriage //0x001205a4 thats what WerFault.exe uses + +#define DUMP_FLAGS_EXTENDED MiniDumpWithFullMemory | \ + MiniDumpWithHandleData | \ + MiniDumpWithThreadInfo | \ + MiniDumpWithProcessThreadData | \ + MiniDumpWithFullMemoryInfo | \ + MiniDumpWithUnloadedModules | \ + MiniDumpWithFullAuxiliaryState | \ + MiniDumpIgnoreInaccessibleMemory | \ + MiniDumpWithTokenInformation + +static MINIDUMP_TYPE Dump_Flags = DUMP_FLAGS_DEFAULT; +static P_SetUnhandledExceptionFilter __sys_SetUnhandledExceptionFilter = NULL; + + +//--------------------------------------------------------------------------- +// Functions +//--------------------------------------------------------------------------- + + +//--------------------------------------------------------------------------- +// Dump_CrashHandlerExceptionFilter +//--------------------------------------------------------------------------- + +LONGLONG GetCurCycle() +{ + LONGLONG freq, now; + QueryPerformanceFrequency((LARGE_INTEGER*)&freq); + QueryPerformanceCounter((LARGE_INTEGER*)&now); + LONGLONG dwNow = ((now * 1000000) / freq); + return dwNow; // returns time since system start in us +} + +static LONG __stdcall Dump_CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pEx) +{ +#ifdef _M_IX86 + if (pEx->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) + { + // be sure that we have enought space... + static char MyStack[1024 * 128]; + // it assumes that DS and SS are the same!!! (this is the case for Win32) + // change the stack only if the selectors are the same (this is the case for Win32) + //__asm push offset MyStack[1024*128]; + //__asm pop esp; + __asm mov eax, offset MyStack[1024 * 128]; + __asm mov esp, eax; + } +#endif + + SbieApi_Log(2224, L"%S [%S]", Dll_ImageName, Dll_BoxName); + + BOOLEAN bSuccess = FALSE; + HANDLE hFile; + + wchar_t szMiniDumpFileName[128]; + Sbie_snwprintf(szMiniDumpFileName, 128, L"%s.%lld.dmp", Dll_ImageName, GetCurCycle); + + wchar_t szMiniDumpFilePath[MAX_PATH] = { 0 }; + Sbie_snwprintf(szMiniDumpFilePath, MAX_PATH, L"%s\\%s", Dll_BoxFilePath, szMiniDumpFileName); + //hFile = CreateFile(szMiniDumpFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + UNICODE_STRING uni; + OBJECT_ATTRIBUTES attr; + RtlInitUnicodeString(&uni, szMiniDumpFilePath); + InitializeObjectAttributes(&attr, &uni, OBJ_CASE_INSENSITIVE, NULL, 0); + + IO_STATUS_BLOCK Iosb; + extern P_NtCreateFile __sys_NtCreateFile; + NTSTATUS status = __sys_NtCreateFile(&hFile, FILE_GENERIC_WRITE, &attr, &Iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); + + //if (hFile != INVALID_HANDLE_VALUE) + if (NT_SUCCESS(status)) + { + MINIDUMP_EXCEPTION_INFORMATION stMDEI; + stMDEI.ThreadId = GetCurrentThreadId(); + stMDEI.ExceptionPointers = pEx; + stMDEI.ClientPointers = TRUE; + // try to create an miniDump: + if (__sys_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, Dump_Flags, &stMDEI, NULL, NULL)) + { + bSuccess = TRUE; + } + //CloseHandle(hFile); + extern P_NtClose __sys_NtClose; + __sys_NtClose(hFile); + } + + wchar_t szMiniDumpMessage[256]; + if (!bSuccess) + Sbie_snwprintf(szMiniDumpMessage, 256, L"%s crashed!\r\nCrashdump creation failed.", Dll_ImageName); + else + Sbie_snwprintf(szMiniDumpMessage, 256, L"%s crashed!\r\nCrashdump saved to \"%s\".", Dll_ImageName, szMiniDumpFileName); + SbieApi_MonitorPut2(MONITOR_OTHER | MONITOR_TRACE, szMiniDumpMessage, FALSE); + + // or return one of the following: + // - EXCEPTION_CONTINUE_SEARCH // this will trigger the "normal" OS error-dialog + // - EXCEPTION_CONTINUE_EXECUTION + // - EXCEPTION_EXECUTE_HANDLER // this will prevent the invocation of WerFault.exe + return EXCEPTION_EXECUTE_HANDLER; +} + + +//--------------------------------------------------------------------------- +// Dump_SetUnhandledExceptionFilter +//--------------------------------------------------------------------------- + + +ALIGNED LPTOP_LEVEL_EXCEPTION_FILTER Dump_SetUnhandledExceptionFilter( + _In_opt_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter +) +{ + return NULL; +} + + +//--------------------------------------------------------------------------- +// Dump_SetUnhandledExceptionFilter +//--------------------------------------------------------------------------- + + +/*ALIGNED BOOLEAN Dump_MiniDumpWriteDump( + _In_ HANDLE hProcess, + _In_ DWORD ProcessId, + _In_ HANDLE hFile, + _In_ MINIDUMP_TYPE DumpType, + _In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + _In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + _In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam +) +{ + while (! IsDebuggerPresent()) { + OutputDebugString(L"BREAK\n"); + Sleep(500); + } + __debugbreak(); + + return __sys_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType, ExceptionParam, UserStreamParam, CallbackParam); +}*/ + + +//--------------------------------------------------------------------------- +// Dump_Init +//--------------------------------------------------------------------------- + + +_FX int Dump_Init(void) +{ + if (Dump_DbgHelpMod != NULL) + return 2; + + // Initialize the member, so we do not load the dll after the exception has occured + // which might be not possible anymore... + Dump_DbgHelpMod = LoadLibrary(L"dbghelp.dll"); + if (!Dump_DbgHelpMod ) + return 0; + + /*if (_wcsicmp(Dll_ImageName, L"WerFault.exe") == 0) // fre experimenting only + { + P_MiniDumpWriteDump MiniDumpWriteDump = (P_MiniDumpWriteDump)GetProcAddress(Dump_DbgHelpMod, "MiniDumpWriteDump"); + SBIEDLL_HOOK(Dump_, MiniDumpWriteDump); + return 1; + }*/ + + __sys_MiniDumpWriteDump = (P_MiniDumpWriteDump)GetProcAddress(Dump_DbgHelpMod, "MiniDumpWriteDump"); + + // get the default preset + WCHAR str[32]; + if (NT_SUCCESS(SbieApi_QueryConfAsIs(NULL, L"MiniDumpFlags", 0, str, sizeof(str) - sizeof(WCHAR)))) { + if (_wcsnicmp(str, L"0x", 2) == 0) + Dump_Flags = wcstol(str + 2, NULL, 16); + else if (_wcsnicmp(str, L"extended", 3) == 0) // check only first 3 letters + Dump_Flags = DUMP_FLAGS_EXTENDED; + } + + // Register Unhandled Exception-Filter: + SetUnhandledExceptionFilter(Dump_CrashHandlerExceptionFilter); + + // Additional call "PreventSetUnhandledExceptionFilter"... + // See also: "SetUnhandledExceptionFilter" and VC8 (and later) + // http://blog.kalmbachnet.de/?postid=75 + + SBIEDLL_HOOK(Dump_, SetUnhandledExceptionFilter); + + //SbieApi_MonitorPut2(MONITOR_OTHER | MONITOR_TRACE, L"Minidump enabled", FALSE); + return 1; +} \ No newline at end of file diff --git a/Sandboxie/core/dll/dump.h b/Sandboxie/core/dll/dump.h new file mode 100644 index 00000000..7bff07c5 --- /dev/null +++ b/Sandboxie/core/dll/dump.h @@ -0,0 +1,34 @@ +/* + * Copyright 2021 DavidXanatos, xanasoft.com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//--------------------------------------------------------------------------- +// Sandboxie Trace +//--------------------------------------------------------------------------- + + +#ifndef _MY_DUMP_H +#define _MY_DUMP_H + + +//--------------------------------------------------------------------------- + +int Dump_Init(void); + +//--------------------------------------------------------------------------- + + +#endif /* _MY_DUMP_H */ diff --git a/Sandboxie/core/dll/file.c b/Sandboxie/core/dll/file.c index 7362fad2..11b5072b 100644 --- a/Sandboxie/core/dll/file.c +++ b/Sandboxie/core/dll/file.c @@ -293,7 +293,7 @@ static P_NtQueryInformationFile __sys_NtQueryInformationFile = NULL; static P_NtQueryDirectoryFileEx __sys_NtQueryDirectoryFileEx = NULL; static P_NtSetInformationFile __sys_NtSetInformationFile = NULL; static P_NtDeleteFile __sys_NtDeleteFile = NULL; -static P_NtClose __sys_NtClose = NULL; + P_NtClose __sys_NtClose = NULL; static P_NtCreateNamedPipeFile __sys_NtCreateNamedPipeFile = NULL; static P_NtCreateMailslotFile __sys_NtCreateMailslotFile = NULL; static P_NtReadFile __sys_NtReadFile = NULL; diff --git a/Sandboxie/core/dll/guiclass.c b/Sandboxie/core/dll/guiclass.c index fea16b71..e86e31fd 100644 --- a/Sandboxie/core/dll/guiclass.c +++ b/Sandboxie/core/dll/guiclass.c @@ -742,8 +742,10 @@ _FX int Gui_GetClassNameW( n -= (ULONG)(clsnm_ptr - clsnm); if (n > nMaxCount - 1) n = nMaxCount - 1; - wmemcpy(lpClassName, clsnm_ptr, n); - lpClassName[n] = L'\0'; + if (lpClassName) { + wmemcpy(lpClassName, clsnm_ptr, n); + lpClassName[n] = L'\0'; + } } else n = 0; } else @@ -754,8 +756,10 @@ _FX int Gui_GetClassNameW( n = nMaxCount - 1; else n = n0; - wmemcpy(lpClassName, clsnm, n); - lpClassName[n] = L'\0'; + if (lpClassName) { + wmemcpy(lpClassName, clsnm, n); + lpClassName[n] = L'\0'; + } } Dll_Free(clsnm); @@ -796,8 +800,10 @@ _FX int Gui_GetClassNameA( n -= (ULONG)(clsnm_ptr - clsnm); if (n > nMaxCount - 1) n = nMaxCount - 1; - memcpy(lpClassName, clsnm_ptr, n); - lpClassName[n] = '\0'; + if (lpClassName) { + memcpy(lpClassName, clsnm_ptr, n); + lpClassName[n] = '\0'; + } } else n = 0; } else @@ -808,8 +814,10 @@ _FX int Gui_GetClassNameA( n = nMaxCount - 1; else n = n0; - memcpy(lpClassName, clsnm, n); - lpClassName[n] = L'\0'; + if (lpClassName) { + memcpy(lpClassName, clsnm, n); + lpClassName[n] = L'\0'; + } } Dll_Free(clsnm); diff --git a/SandboxiePlus/SandMan/Windows/OptionsTemplates.cpp b/SandboxiePlus/SandMan/Windows/OptionsTemplates.cpp index 5494b1c9..e6f95286 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsTemplates.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsTemplates.cpp @@ -120,14 +120,14 @@ void COptionsWindow::ShowTemplates() if (!CategoryFilter.isEmpty() && I.key().compare(CategoryFilter, Qt::CaseInsensitive) != 0) continue; - QString Name = I.value().first.mid(9); - - if (!Name.isEmpty() && Name.indexOf(TextFilter, 0, Qt::CaseInsensitive) == -1) + if (I.value().second.indexOf(TextFilter, 0, Qt::CaseInsensitive) == -1) continue; if (I.key().isEmpty()) continue; // dont show templates without a category (these are usually deprecated templates) + QString Name = I.value().first.mid(9); + QTreeWidgetItem* pItem = new QTreeWidgetItem(); pItem->setText(0, GetCategoryName(I.key())); pItem->setData(1, Qt::UserRole, I.value().first);