diff --git a/CHANGELOG.md b/CHANGELOG.md index 35713775..d2c41a29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [1.9.6 / 5.64.6] - 2023-05-?? -### Changed -- Don't close submenus on mouse-leave [#2963](https://github.com/sandboxie-plus/Sandboxie/issues/2963) +### Added +- added full stack trace to all trace messages ### Fixed - fixed an issue with token manipulation in the SbieDrv driver - +- fixed "Reset all GUI options" does not reset all GUI sections as expected [#2967](https://github.com/sandboxie-plus/Sandboxie/issues/2967) diff --git a/Sandboxie/core/drv/session.c b/Sandboxie/core/drv/session.c index 57c4f1f2..b35cecee 100644 --- a/Sandboxie/core/drv/session.c +++ b/Sandboxie/core/drv/session.c @@ -74,6 +74,8 @@ struct _SESSION { LOG_BUFFER* monitor_log; + BOOLEAN monitor_stack_trace; + BOOLEAN monitor_overflow; }; @@ -563,9 +565,16 @@ _FX void Session_MonitorPutEx(ULONG type, const WCHAR** strings, ULONG* lengths, data_len += ((lengths ? lengths [i] : wcslen(strings[i])) + 1) * sizeof(WCHAR); - //[Time 8][Type 4][PID 4][TID 4][Data n*2] + //[Time 8][Type 4][PID 4][TID 4][Data n*2](0xFFFF[ID1][LEN1][DATA1]...[IDn][LENn][DATAn]) SIZE_T entry_size = 8 + 4 + 4 + 4 + data_len; + PVOID backTrace[MAX_STACK_DEPTH]; + ULONG frames = 0; + if (session->monitor_stack_trace) { + frames = Util_CaptureStack(backTrace, MAX_STACK_DEPTH); + entry_size += sizeof(WCHAR) + sizeof(ULONG) + sizeof(ULONG) + (frames * sizeof(PVOID)); + } + CHAR* write_ptr = log_buffer_push_entry((LOG_BUFFER_SIZE_T)entry_size, session->monitor_log, FALSE); if (write_ptr) { WCHAR null_char = L'\0'; @@ -579,6 +588,17 @@ _FX void Session_MonitorPutEx(ULONG type, const WCHAR** strings, ULONG* lengths, log_buffer_push_bytes((CHAR*)strings[i], (lengths ? lengths[i] : wcslen(strings[i])) * sizeof(WCHAR), &write_ptr, session->monitor_log); log_buffer_push_bytes((CHAR*)&null_char, sizeof(WCHAR), &write_ptr, session->monitor_log); } + + if (frames) { + WCHAR strings_end = 0xFFFF; + log_buffer_push_bytes((CHAR*)&strings_end, sizeof(WCHAR), &write_ptr, session->monitor_log); + + ULONG tag_id = 'STCK'; + ULONG tag_len = frames * sizeof(PVOID); + log_buffer_push_bytes((CHAR*)&tag_id, sizeof(ULONG), &write_ptr, session->monitor_log); + log_buffer_push_bytes((CHAR*)&tag_len, sizeof(ULONG), &write_ptr, session->monitor_log); + log_buffer_push_bytes((CHAR*)backTrace, frames * sizeof(PVOID), &write_ptr, session->monitor_log); + } } else if (!session->monitor_overflow) { session->monitor_overflow = TRUE; @@ -671,6 +691,8 @@ _FX NTSTATUS Session_Api_MonitorControl(PROCESS *proc, ULONG64 *parms) } else Log_Msg0(MSG_1201); + session->monitor_stack_trace = Conf_Get_Boolean(NULL, L"MonitorStackTrace", 0, FALSE); + } else if ((! EnableMonitor) && session->monitor_log) { log_buffer_free(session->monitor_log); diff --git a/Sandboxie/core/drv/util.c b/Sandboxie/core/drv/util.c index b81546d2..0f1d9519 100644 --- a/Sandboxie/core/drv/util.c +++ b/Sandboxie/core/drv/util.c @@ -469,4 +469,33 @@ _FX LARGE_INTEGER Util_GetTimestamp(void) ((10000000 * (CounterOff % gPerformanceFrequency.QuadPart)) / gPerformanceFrequency.QuadPart); return Time; +} + + +//--------------------------------------------------------------------------- +// Util_CaptureStack +//--------------------------------------------------------------------------- + + +ULONG Util_CaptureStack(_Out_ PVOID* Frames, _In_ ULONG Count) +{ + ULONG frames; + + NT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + frames = RtlWalkFrameChain(Frames, Count, 0); + + if (KeGetCurrentIrql() < DISPATCH_LEVEL) + { + if (frames >= Count) + { + return frames; + } + + frames += RtlWalkFrameChain(&Frames[frames], + (Count - frames), + RTL_WALK_USER_MODE_STACK); + } + + return frames; } \ No newline at end of file diff --git a/Sandboxie/core/drv/util.h b/Sandboxie/core/drv/util.h index fdda19d5..d82685ab 100644 --- a/Sandboxie/core/drv/util.h +++ b/Sandboxie/core/drv/util.h @@ -112,6 +112,15 @@ HANDLE Util_GetProcessPidByName(const WCHAR* name); LARGE_INTEGER Util_GetTimestamp(void); + +// Sensible limit that may or may not correspond to the actual Windows value. +#define MAX_STACK_DEPTH 256 + +#define RTL_WALK_USER_MODE_STACK 0x00000001 +#define RTL_WALK_VALID_FLAGS 0x00000001 + +ULONG Util_CaptureStack(_Out_ PVOID* Frames, _In_ ULONG Count); + //--------------------------------------------------------------------------- diff --git a/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp new file mode 100644 index 00000000..df0f5a5b --- /dev/null +++ b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.cpp @@ -0,0 +1,335 @@ +#include "stdafx.h" + +#include + +#include +#define WIN32_NO_STATUS +typedef long NTSTATUS; + +#include +#include "..\..\..\Sandboxie\common\win32_ntddk.h" + +#include "DbgHelper.h" + + +#include + +typedef BOOL(WINAPI* P_SymFromAddr)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol); +typedef BOOL(WINAPI* P_SymGetModuleInfoW64)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULEW64 ModuleInfo); +typedef DWORD(WINAPI* P_SymSetOptions)(DWORD SymOptions); +typedef DWORD(WINAPI* P_SymGetOptions)(); +typedef BOOL(WINAPI* P_SymInitialize)(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess); +typedef BOOL(WINAPI* P_SymCleanup)(HANDLE ProcessHandle); +typedef BOOL(WINAPI* P_SymSetSearchPathW)(HANDLE hProcess, PCWSTR SearchPath); +typedef BOOL(WINAPI* P_SymRegisterCallbackW64)(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ULONG64 UserContext); + + +static P_SymFromAddr __sys_SymFromAddr = NULL; +static P_SymGetModuleInfoW64 __sys_SymGetModuleInfoW64 = NULL; +static P_SymSetOptions __sys_SymSetOptions = NULL; +static P_SymGetOptions __sys_SymGetOptions = NULL; +static P_SymSetSearchPathW __sys_SymSetSearchPathW = NULL; +static P_SymInitialize __sys_SymInitialize = NULL; +static P_SymCleanup __sys_SymCleanup = NULL; +static P_SymRegisterCallbackW64 __sys_SymRegisterCallbackW64 = NULL; + +CSymbolProvider* g_SymbolProvider = NULL; + +CSymbolProvider::CSymbolProvider() +{ + //m_uTimerID = startTimer(1000); + + // start thread + m_bRunning = true; + start(); +} + +CSymbolProvider::~CSymbolProvider() +{ + //killTimer(m_uTimerID); + + m_bRunning = false; + //quit(); + if (!wait(10 * 1000)) + terminate(); + + // cleanup unfinished tasks + while (!m_JobQueue.isEmpty()) { + m_JobQueue.takeFirst()->deleteLater(); + } + + g_SymbolProvider = NULL; +} + +//void CSymbolProvider::timerEvent(QTimerEvent* pEvent) +//{ +// if (pEvent->timerId() != m_uTimerID) +// return; +//} + +void CSymbolProvider::run() +{ + quint64 LastCleanUp = 0; + + while (m_bRunning) + { + quint64 OldTime = GetTickCount64() - 3000; // cleanup everythign older than 3 sec + if (LastCleanUp < OldTime) + { + QMutexLocker Lock(&m_SymLock); + for(auto I = m_Workers.begin(); I != m_Workers.end(); ) + { + if (GetTickCount64() - I->last > 2000) { + __sys_SymCleanup((HANDLE)I->handle); + if ((I->handle & 1) == 0) + CloseHandle((HANDLE)I->handle); + I = m_Workers.erase(I); + } + else + I++; + } + + LastCleanUp = GetTickCount64(); + } + + QMutexLocker Locker(&m_JobMutex); + if (m_JobQueue.isEmpty()) { + Locker.unlock(); + QThread::msleep(250); + continue; + } + CSymbolProviderJob* pJob = m_JobQueue.takeFirst(); + Locker.unlock(); + + QString Name = Resolve(pJob->m_ProcessId, pJob->m_Address); + emit pJob->SymbolResolved(pJob->m_Address, Name); + + pJob->deleteLater(); + } +} + +QString CSymbolProvider::Resolve(quint64 pid, quint64 Address) +{ + QMutexLocker Lock(&m_SymLock); + + SWorker& Worker = m_Workers[pid]; + if (Worker.handle == 0) + { + static ACCESS_MASK accesses[] = + { + //STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff, // pre-Vista full access + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE, + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, + MAXIMUM_ALLOWED + }; + for (ULONG i = 0; i < sizeof(accesses) / sizeof(ACCESS_MASK); i++) { + Worker.handle = (quint64)OpenProcess(accesses[i], FALSE, pid); + if (Worker.handle != (quint64)INVALID_HANDLE_VALUE) + break; + } + + static QAtomicInt FakeHandle = 1; // real handles are divisable b 4 + if (Worker.handle == (quint64)INVALID_HANDLE_VALUE) + Worker.handle = FakeHandle.fetchAndAddAcquire(4); + + __sys_SymInitialize((HANDLE)Worker.handle, NULL, TRUE); + //__sys_SymRegisterCallbackW64((HANDLE)Worker.handle, SymbolCallbackFunction, (ULONG64)&Worker); + __sys_SymSetSearchPathW((HANDLE)Worker.handle, m_SymPath.toStdWString().c_str()); + } + Worker.last = GetTickCount64(); + + QString Symbol; + + DWORD64 displacement; + UCHAR buffer[sizeof(SYMBOL_INFO) + sizeof(TCHAR) + (MAX_SYM_NAME - 1)] = { 0 }; + SYMBOL_INFO* symbolInfo = (SYMBOL_INFO*)buffer; + symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO); + symbolInfo->MaxNameLen = MAX_SYM_NAME; + if (__sys_SymFromAddr((HANDLE)Worker.handle, Address, &displacement, symbolInfo)) + { + symbolInfo->Name[symbolInfo->NameLen] = 0; + + Symbol = QString(symbolInfo->Name); + if (displacement != 0) + Symbol.append(QString("+0x%1").arg(displacement, 0, 16)); + + IMAGEHLP_MODULEW64 ModuleInfo; + ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); + if (__sys_SymGetModuleInfoW64((HANDLE)Worker.handle, symbolInfo->ModBase ? symbolInfo->ModBase : symbolInfo->Address, &ModuleInfo)) + Symbol.prepend(QString::fromWCharArray(ModuleInfo.ModuleName) + "!"); + } + else + { + // Then this happens probably symsrv.dll is missing + + IMAGEHLP_MODULEW64 ModuleInfo; + ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); + if (__sys_SymGetModuleInfoW64((HANDLE)Worker.handle, Address, &ModuleInfo)) + Symbol.prepend(QString::fromWCharArray(ModuleInfo.ModuleName) + "+" + QString("0x%1").arg(Address - ModuleInfo.BaseOfImage, 0, 16)); + } + + return Symbol; +} + +void CSymbolProvider::ResolveAsync(quint64 pid, quint64 Address, QObject* receiver, const char* member) +{ + CSymbolProvider* This = CSymbolProvider::Instance(); + + if (!QAbstractEventDispatcher::instance(QThread::currentThread())) { + qWarning("CSymbolProvider::ResolveAsync() called with no event dispatcher"); + return; + } + + CSymbolProviderJob* pJob = new CSymbolProviderJob(pid, Address); + pJob->moveToThread(This); + QObject::connect(pJob, SIGNAL(SymbolResolved(quint64, const QString&)), receiver, member, Qt::QueuedConnection); + + QMutexLocker Locker(&This->m_JobMutex); + This->m_JobQueue.append(pJob); +} + +/*extern "C" BOOL CALLBACK SymbolCallbackFunction(HANDLE ProcessHandle, ULONG ActionCode, ULONG64 CallbackData, ULONG64 UserContext) +{ + CSymbolProvider::SWorker* pWorker = (CSymbolProvider::SWorker*)UserContext; + + switch (ActionCode) + { + case CBA_DEFERRED_SYMBOL_LOAD_START: + { + PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; + + IMAGEHLP_MODULEW64 ModuleInfo; + ModuleInfo.SizeOfStruct = sizeof(ModuleInfo); + if (__sys_SymGetModuleInfoW64(ProcessHandle, callbackData->BaseOfImage, &ModuleInfo)) + { + HANDLE fileHandle; + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES objectAttributes; + IO_STATUS_BLOCK ioStatusBlock; + + std::wstring FileName = L"\\??\\" + std::wstring(ModuleInfo.ImageName); + fileName.Buffer = (WCHAR*)FileName.c_str(); + fileName.Length = fileName.MaximumLength = FileName.size() * sizeof(WCHAR); + + InitializeObjectAttributes( + &objectAttributes, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + if (NT_SUCCESS(NtCreateFile( + &fileHandle, + FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &objectAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ))) + { + callbackData->FileName[0] = UNICODE_NULL; + callbackData->hFile = fileHandle; + + return TRUE; + } + } + } + return FALSE; + case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: + { + PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 callbackData = (PIMAGEHLP_DEFERRED_SYMBOL_LOADW64)CallbackData; + + if (callbackData->hFile) + { + NtClose(callbackData->hFile); + callbackData->hFile = NULL; + } + } + return TRUE; + case CBA_READ_MEMORY: + { + PIMAGEHLP_CBA_READ_MEMORY callbackData = (PIMAGEHLP_CBA_READ_MEMORY)CallbackData; + + if ((pWorker->handle & 1) == 0) + { + if (NT_SUCCESS(NtReadVirtualMemory( + ProcessHandle, + (PVOID)callbackData->addr, + callbackData->buf, + (SIZE_T)callbackData->bytes, + (PSIZE_T)callbackData->bytesread + ))) + { + return TRUE; + } + } + } + return FALSE; + case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: + { + if (pWorker->last == 0) // terminating + return TRUE; + } + break; + } + + return FALSE; +}*/ + +bool MyBeginInitOnce(QAtomicInt& InitOnce) +{ + if (InitOnce == 1) + return false; + else + { + if (InitOnce.testAndSetAcquire(0, 2)) + return true; + + while (InitOnce == 2) + Sleep(10); + + return false; + } +} + +void MyEndInitOnce(QAtomicInt& InitOnce) +{ + InitOnce = 1; +} + +CSymbolProvider* CSymbolProvider::Instance() +{ + static QAtomicInt InitOnce = 0; + + if (MyBeginInitOnce(InitOnce)) + { + HMODULE DbgHelpMod = LoadLibrary(L"dbghelp.dll"); + __sys_SymFromAddr = (P_SymFromAddr)GetProcAddress(DbgHelpMod, "SymFromAddr"); + __sys_SymGetModuleInfoW64 = (P_SymGetModuleInfoW64)GetProcAddress(DbgHelpMod, "SymGetModuleInfoW64"); + __sys_SymSetOptions = (P_SymSetOptions)GetProcAddress(DbgHelpMod, "SymSetOptions"); + __sys_SymGetOptions = (P_SymGetOptions)GetProcAddress(DbgHelpMod, "SymGetOptions"); + __sys_SymSetSearchPathW = (P_SymSetSearchPathW)GetProcAddress(DbgHelpMod, "SymSetSearchPathW"); + __sys_SymInitialize = (P_SymInitialize)GetProcAddress(DbgHelpMod, "SymInitialize"); + __sys_SymCleanup = (P_SymCleanup)GetProcAddress(DbgHelpMod, "SymCleanup"); + __sys_SymRegisterCallbackW64 = (P_SymRegisterCallbackW64)GetProcAddress(DbgHelpMod, "SymRegisterCallbackW64"); + + __sys_SymSetOptions( + __sys_SymGetOptions() | SYMOPT_UNDNAME | + SYMOPT_AUTO_PUBLICS | SYMOPT_CASE_INSENSITIVE | SYMOPT_DEFERRED_LOADS | + SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_INCLUDE_32BIT_MODULES | + SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_UNDNAME // | SYMOPT_DEBUG + ); + + g_SymbolProvider = new CSymbolProvider(); + + MyEndInitOnce(InitOnce); + } + + return g_SymbolProvider; +} \ No newline at end of file diff --git a/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h new file mode 100644 index 00000000..b7b1beb6 --- /dev/null +++ b/SandboxiePlus/QSbieAPI/Helpers/DbgHelper.h @@ -0,0 +1,60 @@ +#pragma once + +#include "../qsbieapi_global.h" + +#include +class CSymbolProviderJob; + +class QSBIEAPI_EXPORT CSymbolProvider: public QThread +{ + Q_OBJECT + + CSymbolProvider(); +public: + static CSymbolProvider* Instance(); + ~CSymbolProvider(); + + QString Resolve(quint64 pid, quint64 Address); + static void ResolveAsync(quint64 pid, quint64 Address, QObject* receiver, const char* member); + + void SetSymPath(const QString& Path) { QMutexLocker Lock(&m_SymLock); m_SymPath = Path; } + + struct SWorker + { + SWorker() : last(-1), handle(0) {} + quint64 last; + quint64 handle; + }; + +protected: + //void timerEvent(QTimerEvent* pEvent); + //int m_uTimerID; + + virtual void run(); + bool m_bRunning; + + mutable QMutex m_JobMutex; + QQueue m_JobQueue; + + QMutex m_SymLock; + QHash m_Workers; + QString m_SymPath; +}; + + +class CSymbolProviderJob : public QObject +{ + Q_OBJECT + +protected: + friend class CSymbolProvider; + + CSymbolProviderJob(quint64 ProcessId, quint64 Address, QObject *parent = nullptr) : QObject(parent) { m_ProcessId = ProcessId; m_Address = Address; } + virtual ~CSymbolProviderJob() {} + + quint64 m_ProcessId; + quint64 m_Address; + +signals: + void SymbolResolved(quint64 Address, const QString& Name); +}; \ No newline at end of file diff --git a/SandboxiePlus/QSbieAPI/QSbieAPI.pri b/SandboxiePlus/QSbieAPI/QSbieAPI.pri index 098c4554..d127e87d 100644 --- a/SandboxiePlus/QSbieAPI/QSbieAPI.pri +++ b/SandboxiePlus/QSbieAPI/QSbieAPI.pri @@ -16,7 +16,8 @@ HEADERS += ./qsbieapi_global.h \ ./Sandboxie/SbieIni.h \ ./Sandboxie/BoxBorder.h \ ./Sandboxie/SbieTemplates.h \ - ./Helpers/NtIO.h + ./Helpers/NtIO.h \ + ./Helpers/DbgHelper.h SOURCES += ./stdafx.cpp \ ./SbieAPI.cpp \ @@ -27,4 +28,5 @@ SOURCES += ./stdafx.cpp \ ./Sandboxie/SandBox.cpp \ ./Sandboxie/SbieIni.cpp \ ./Sandboxie/SbieTemplates.cpp \ - ./Helpers/NtIO.cpp + ./Helpers/NtIO.cpp \ + ./Helpers/DbgHelper.cpp diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp index 3b67894c..2336e1aa 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.cpp @@ -19,6 +19,7 @@ #include "BoxedProcess.h" #include "SandBox.h" #include "../SbieAPI.h" +#include "../Helpers/DbgHelper.h" #include #define WIN32_NO_STATUS @@ -274,7 +275,7 @@ bool CBoxedProcess::InitProcessInfoEx() { if (m_ProcessFlags == 0 && m_pBox) m_ProcessFlags = m_pBox->Api()->QueryProcessInfo(m_ProcessId); - m_ImageType = m_pBox->Api()->QueryProcessInfo(m_ProcessId, 'gpit'); + m_ImageType = m_pBox->Api()->QueryProcessInfo(m_ProcessId, 'gpit'); return true; } @@ -371,3 +372,16 @@ bool CBoxedProcess::IsSuspended() const return isSuspended; } */ + +void CBoxedProcess::ResolveSymbols(const QVector& Addresses) +{ + foreach(quint64 Address, Addresses) + { + if (!m_Symbols.contains(Address)) { + SSymbol Symbol; + //Symbol.Name = CSymbolProvider::Instance()->Resolve(m_ProcessId, Address); + m_Symbols[Address] = Symbol; + CSymbolProvider::ResolveAsync(m_ProcessId, Address, this, SLOT(OnSymbol(quint64, const QString&))); + } + } +} diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h index 9f6473a3..8ce5a645 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h +++ b/SandboxiePlus/QSbieAPI/Sandboxie/BoxedProcess.h @@ -53,6 +53,12 @@ public: virtual QString GetBoxName() const { return m_BoxName; } virtual class CSandBox* GetBoxPtr() const { return m_pBox; } + virtual void ResolveSymbols(const QVector& Addresses); + virtual QString GetSymbol(quint64 Address) { return m_Symbols.value(Address).Name; } + +public slots: + virtual void OnSymbol(quint64 Address, const QString& Name) { m_Symbols[Address].Name = Name; } + protected: friend class CSbieAPI; @@ -74,6 +80,12 @@ protected: class CSandBox* m_pBox; + struct SSymbol { + QString Name; + }; + + QHash m_Symbols; + //private: // struct SBoxedProcess* m; }; diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp index 78d2408e..a31acd03 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SbieIni.cpp @@ -279,7 +279,7 @@ QList> CSbieIni::GetIniSection(qint32* pStatus, bool wit return Settings; } -SB_STATUS CSbieIni::RenameSection( const QString& NewName, bool deleteOld) // Note: deleteOld is used when duplicating a box +SB_STATUS CSbieIni::RenameSection(const QString& NewName, bool deleteOld) // Note: deleteOld is used when duplicating a box { qint32 status = STATUS_SUCCESS; @@ -330,6 +330,8 @@ do_delete: if (m_RefreshOnChange) m_pAPI->CommitIniChanges(); + m_Name = NewName; + return SB_OK; } diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.cpp b/SandboxiePlus/QSbieAPI/SbieAPI.cpp index 156bccdd..efc9e44c 100644 --- a/SandboxiePlus/QSbieAPI/SbieAPI.cpp +++ b/SandboxiePlus/QSbieAPI/SbieAPI.cpp @@ -1,6 +1,5 @@ -/* - * - * Copyright (c) 2020, David Xanatos +/* + * Copyright (c) 2020-2023, David Xanatos * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -15,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include "stdafx.h" #include #include @@ -104,8 +104,8 @@ struct SSbieAPI HMODULE SbieMsgDll; mutable volatile LONG SvcLock; - mutable void* SvcReq; - mutable void* SvcRpl; + mutable MSG_HEADER* SvcReq; + mutable CSbieAPI::SScopedVoid* SvcRpl; mutable SB_STATUS SvcStatus; }; @@ -420,7 +420,7 @@ SB_STATUS CSbieAPI__ConnectPort(SSbieAPI* m) return SB_OK; } -SB_STATUS CSbieAPI__CallServer(SSbieAPI* m, MSG_HEADER* req, MSG_HEADER** prpl) +SB_STATUS CSbieAPI__CallServer(SSbieAPI* m, MSG_HEADER* req, CSbieAPI::SScopedVoid* prpl) { if (!m->PortHandle) { SB_STATUS Status = CSbieAPI__ConnectPort(m); @@ -490,8 +490,7 @@ SB_STATUS CSbieAPI__CallServer(SSbieAPI* m, MSG_HEADER* req, MSG_HEADER** prpl) return SB_ERR(SB_ServiceFail, QVariantList() << QString("null reply (msg %1 len %2)").arg(req->msgid, 8, 16).arg(req->length)); // 2203 // read remaining chunks - MSG_HEADER*& rpl = *prpl; - rpl = (MSG_HEADER*)malloc(BuffLen); + MSG_HEADER* rpl = (MSG_HEADER*)malloc(BuffLen); Buffer = (UCHAR*)rpl; for (;;) { @@ -528,6 +527,7 @@ SB_STATUS CSbieAPI__CallServer(SSbieAPI* m, MSG_HEADER* req, MSG_HEADER** prpl) return SB_ERR(SB_ServiceFail, QVariantList() << QString("reply %1").arg(status, 8, 16), status); // 2203 } } + prpl->Assign(rpl); return SB_OK; } @@ -543,13 +543,10 @@ SB_STATUS CSbieAPI__QueueCreate(SSbieAPI* m, const WCHAR* QueueName, HANDLE *out return SB_ERR(STATUS_UNSUCCESSFUL); NTSTATUS status = STATUS_SERVER_DISABLED; - QUEUE_CREATE_RPL *rpl = NULL; - CSbieAPI__CallServer(m, &req.h, (MSG_HEADER**)&rpl); + CSbieAPI::SScoped rpl; + CSbieAPI__CallServer(m, &req.h, &rpl); if (rpl) - { status = rpl->h.status; - free(rpl); - } if (!NT_SUCCESS(status)) { CloseHandle((HANDLE)(ULONG_PTR)req.event_handle); @@ -569,8 +566,8 @@ bool CSbieAPI::GetQueue() wcscpy(req.queue_name, m->QueueName); NTSTATUS status = STATUS_SERVER_DISABLED; - QUEUE_GETREQ_RPL *rpl = NULL; - CSbieAPI__CallServer(m, &req.h, (MSG_HEADER**)&rpl); + SScoped rpl; + CSbieAPI__CallServer(m, &req.h, &rpl); if (rpl) { status = rpl->h.status; @@ -598,8 +595,6 @@ bool CSbieAPI::GetQueue() emit QueuedRequest(rpl->client_pid, rpl->client_tid, rpl->req_id, Data); } - - free(rpl); } //if(status == STATUS_END_OF_FILE) // there are no more requests in the queue at this time @@ -644,9 +639,7 @@ void CSbieAPI::SendReplyData(quint32 RequestId, const QVariantMap& Result) } ULONG req_len = sizeof(QUEUE_PUTRPL_REQ) + Data.length(); - - QUEUE_PUTRPL_REQ *req; - req = (QUEUE_PUTRPL_REQ*)malloc(req_len); + SScoped req(malloc(req_len)); req->h.length = req_len; req->h.msgid = MSGID_QUEUE_PUTRPL; wcscpy(req->queue_name, m->QueueName); @@ -655,15 +648,10 @@ void CSbieAPI::SendReplyData(quint32 RequestId, const QVariantMap& Result) memcpy(req->data, Data.constData(), req->data_len); NTSTATUS status = STATUS_SERVER_DISABLED; - QUEUE_PUTRPL_RPL *rpl = NULL; - CallServer(&req->h, (MSG_HEADER**)&rpl); + SScoped rpl; + CallServer(&req->h, &rpl); if (rpl) - { status = rpl->h.status; - free(rpl); - } - - free(req); } void CSbieAPI::run() @@ -680,7 +668,7 @@ void CSbieAPI::run() if (InterlockedCompareExchange(&m->SvcLock, SVC_OP_STATE_EXEC, SVC_OP_STATE_START) == SVC_OP_STATE_START) { - m->SvcStatus = CSbieAPI__CallServer(m, (MSG_HEADER*)m->SvcReq, (MSG_HEADER**)m->SvcRpl); + m->SvcStatus = CSbieAPI__CallServer(m, m->SvcReq, m->SvcRpl); InterlockedExchange(&m->SvcLock, SVC_OP_STATE_DONE); @@ -719,7 +707,7 @@ void CSbieAPI::run() CloseHandle(EventHandle); } -SB_STATUS CSbieAPI::CallServer(void* req, void* rpl) const +SB_STATUS CSbieAPI::CallServer(void* req, SScopedVoid* prpl) const { // // Note: Once we open a port to the server from a threat the service will remember it we can't reconnect after disconnection @@ -732,8 +720,8 @@ SB_STATUS CSbieAPI::CallServer(void* req, void* rpl) const while (InterlockedCompareExchange(&m->SvcLock, SVC_OP_STATE_PREP, SVC_OP_STATE_IDLE) != SVC_OP_STATE_IDLE) QThread::usleep(100); - m->SvcReq = req; - m->SvcRpl = rpl; + m->SvcReq = (MSG_HEADER*)req; + m->SvcRpl = prpl; m->SvcStatus = SB_OK; InterlockedExchange(&m->SvcLock, SVC_OP_STATE_START); @@ -1010,7 +998,7 @@ QString CSbieAPI::GetIniPath(bool* IsHome) const req.h.msgid = MSGID_SBIE_INI_GET_PATH; req.h.length = sizeof(SBIE_INI_GET_PATH_REQ); - SBIE_INI_GET_PATH_RPL *rpl = NULL; + SScoped rpl; SB_STATUS Status = CallServer(&req.h, &rpl); if (!Status || !rpl) return QString(); @@ -1019,7 +1007,6 @@ QString CSbieAPI::GetIniPath(bool* IsHome) const if (IsHome) *IsHome = rpl->is_home_path; } - free(rpl); return IniPath; } @@ -1032,7 +1019,7 @@ QString CSbieAPI::GetUserSection(QString* pUserName, bool* pIsAdmin) const req.h.msgid = MSGID_SBIE_INI_GET_USER; req.h.length = sizeof(SBIE_INI_GET_USER_REQ); - SBIE_INI_GET_USER_RPL *rpl = NULL; + SScoped rpl; SB_STATUS Status = CallServer(&req.h, &rpl); if (!Status || !rpl) return QString(); @@ -1042,7 +1029,6 @@ QString CSbieAPI::GetUserSection(QString* pUserName, bool* pIsAdmin) const UserSection = QString::fromWCharArray(rpl->section); if (pUserName) *pUserName = QString::fromWCharArray(rpl->name); } - free(rpl); return UserSection; } @@ -1184,7 +1170,7 @@ QString CSbieAPI__FormatNtStatus(long nsCode) WCHAR* ret_str = NULL; DWORD dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE, - hNtDll, RtlNtStatusToDosError(nsCode), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + hNtDll, nsCode >= 0 ? nsCode : RtlNtStatusToDosError(nsCode), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&ret_str, 0, NULL); QString qStr = dwRes > 0 ? QString::fromWCharArray(ret_str) : QString(); @@ -1198,13 +1184,12 @@ retry: m->Password.toWCharArray((WCHAR*)pPasswordWithinRequestBuf); // fix-me: potential overflow ((WCHAR*)pPasswordWithinRequestBuf)[m->Password.length()] = L'\0'; - MSG_HEADER *rpl = NULL; + SScoped rpl; SB_STATUS Status = CallServer((MSG_HEADER *)RequestBuf, &rpl); SecureZeroMemory(pPasswordWithinRequestBuf, sizeof(WCHAR) * 64); if (!Status || !rpl) return Status; ULONG status = rpl->status; - free(rpl); if (status == 0) return SB_OK; if (status == STATUS_LOGON_NOT_GRANTED || status == STATUS_WRONG_PASSWORD) @@ -1234,7 +1219,7 @@ SB_STATUS CSbieAPI::SbieIniSet(const QString& Section, const QString& Setting, c return SB_ERR(); } - SBIE_INI_SETTING_REQ *req = (SBIE_INI_SETTING_REQ *)malloc(sizeof(SBIE_INI_SETTING_REQ) + Value.length() * sizeof(WCHAR)); + SScoped req(malloc(sizeof(SBIE_INI_SETTING_REQ) + Value.length() * sizeof(WCHAR))); req->refresh = bRefresh ? TRUE : FALSE; @@ -1248,10 +1233,9 @@ SB_STATUS CSbieAPI::SbieIniSet(const QString& Section, const QString& Setting, c req->h.msgid = msgid; req->h.length = sizeof(SBIE_INI_SETTING_REQ) + req->value_len * sizeof(WCHAR); - SB_STATUS Status = SbieIniSet(req, req->password, Section, Setting); + SB_STATUS Status = SbieIniSet(&req->h, req->password, Section, Setting); //if (!Status) // emit LogSbieMessage(0xC1020000 | 2203, QStringList() << "" << Status.GetText() << "", GetCurrentProcessId()); - free(req); return Status; } @@ -1270,7 +1254,7 @@ QString CSbieAPI::SbieIniGetEx(const QString& Section, const QString& Setting) { QString Value; - SBIE_INI_SETTING_REQ *req = (SBIE_INI_SETTING_REQ *)malloc(sizeof(SBIE_INI_SETTING_REQ) ); + SScoped req(malloc(sizeof(SBIE_INI_SETTING_REQ) )); memset(req, 0, sizeof(SBIE_INI_SETTING_REQ)); Section.toWCharArray(req->section); // fix-me: potential overflow @@ -1280,15 +1264,13 @@ QString CSbieAPI::SbieIniGetEx(const QString& Section, const QString& Setting) req->h.msgid = MSGID_SBIE_INI_GET_SETTING; req->h.length = sizeof(SBIE_INI_SETTING_REQ); - SBIE_INI_SETTING_RPL *rpl = NULL; + SScoped rpl; SB_STATUS Status = CallServer(&req->h, &rpl); - free(req); if (!Status || !rpl) return QString(); if (rpl->h.status == 0) { Value = QString::fromWCharArray(rpl->value, rpl->value_len - 1); } - free(rpl); return Value; } @@ -1698,13 +1680,12 @@ SB_STATUS CSbieAPI::TerminateAll(const QString& BoxName) BoxName.toWCharArray(req.boxname); // fix-me: potential overflow req.boxname[BoxName.size()] = L'\0'; - MSG_HEADER *rpl = NULL; + SScoped rpl; SB_STATUS Status = CallServer(&req.h, &rpl); if (!Status || !rpl) return Status; if(rpl->status != 0) Status = SB_ERR(rpl->status); - free(rpl); return Status; } @@ -1725,13 +1706,12 @@ SB_STATUS CSbieAPI::Terminate(quint32 ProcessId) req.h.msgid = MSGID_PROCESS_KILL_ONE; req.pid = ProcessId; - MSG_HEADER *rpl = NULL; + SScoped rpl; SB_STATUS Status = CallServer(&req.h, &rpl); if (!Status || !rpl) return Status; if (rpl->status != 0) Status = SB_ERR(rpl->status); - free(rpl); return Status; } @@ -1850,7 +1830,7 @@ SB_STATUS CSbieAPI::RunSandboxed(const QString& BoxName, const QString& Command, ULONG env_len = (env.size() - 1) / sizeof(WCHAR); ULONG req_len = sizeof(PROCESS_RUN_SANDBOXED_REQ) + (cmd_len + dir_len + env_len + 8) * sizeof(WCHAR); - PROCESS_RUN_SANDBOXED_REQ* req = (PROCESS_RUN_SANDBOXED_REQ*)malloc(req_len); + SScoped req(malloc(req_len)); req->h.length = req_len; req->h.msgid = MSGID_PROCESS_RUN_SANDBOXED; @@ -1866,9 +1846,9 @@ SB_STATUS CSbieAPI::RunSandboxed(const QString& BoxName, const QString& Command, req->si_flags |= STARTF_USESHOWWINDOW; req->creation_flags = Flags; - WCHAR* ptr = (WCHAR*)((ULONG_PTR)req + sizeof(PROCESS_RUN_SANDBOXED_REQ)); + WCHAR* ptr = (WCHAR*)((ULONG_PTR)req.Value() + sizeof(PROCESS_RUN_SANDBOXED_REQ)); - req->cmd_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); + req->cmd_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req.Value()); req->cmd_len = cmd_len; if (cmd_len) { Command.toWCharArray(ptr); @@ -1876,7 +1856,7 @@ SB_STATUS CSbieAPI::RunSandboxed(const QString& BoxName, const QString& Command, } *ptr++ = L'\0'; - req->dir_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); + req->dir_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req.Value()); req->dir_len = dir_len; if (dir_len) { WrkDir.toWCharArray(ptr); @@ -1884,7 +1864,7 @@ SB_STATUS CSbieAPI::RunSandboxed(const QString& BoxName, const QString& Command, } *ptr++ = L'\0'; - req->env_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); + req->env_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req.Value()); req->env_len = env_len; if (env_len) { wmemcpy(ptr, (WCHAR*)env.data(), env_len); @@ -1892,9 +1872,8 @@ SB_STATUS CSbieAPI::RunSandboxed(const QString& BoxName, const QString& Command, } *ptr++ = L'\0'; - PROCESS_RUN_SANDBOXED_RPL *rpl; + SScoped rpl; SB_STATUS Status = CallServer(&req->h, &rpl); - free(req); if (!Status) return Status; if (!rpl) @@ -1906,8 +1885,6 @@ SB_STATUS CSbieAPI::RunSandboxed(const QString& BoxName, const QString& Command, CloseHandle((HANDLE)rpl->hProcess); CloseHandle((HANDLE)rpl->hThread); - - free(rpl); return SB_OK; } @@ -2120,14 +2097,13 @@ bool CSbieAPI::IsConfigLocked() SB_STATUS CSbieAPI::UnlockConfig(const QString& Password) { - SBIE_INI_PASSWORD_REQ *req = (SBIE_INI_PASSWORD_REQ *)malloc(REQUEST_LEN); + SScoped req(malloc(REQUEST_LEN)); req->h.msgid = MSGID_SBIE_INI_TEST_PASSWORD; req->h.length = sizeof(SBIE_INI_PASSWORD_REQ); m->Password = Password; - SB_STATUS Status = SbieIniSet(req, req->old_password, "GlobalSettings", "*"); + SB_STATUS Status = SbieIniSet(&req->h, req->old_password, "GlobalSettings", "*"); if (Status.IsError()) m->Password.clear(); - free(req); return Status; } @@ -2136,15 +2112,14 @@ SB_STATUS CSbieAPI::LockConfig(const QString& NewPassword) if(NewPassword.length() > 64) return SB_ERR(SB_PasswordBad, STATUS_INVALID_PARAMETER); - SBIE_INI_PASSWORD_REQ *req = (SBIE_INI_PASSWORD_REQ *)malloc(REQUEST_LEN); + SScoped req(malloc(REQUEST_LEN)); req->h.msgid = MSGID_SBIE_INI_SET_PASSWORD; req->h.length = sizeof(SBIE_INI_PASSWORD_REQ); NewPassword.toWCharArray(req->new_password); // fix-me: potential overflow req->new_password[NewPassword.length()] = L'\0'; - SB_STATUS Status = SbieIniSet(req, req->old_password, "GlobalSettings", "*"); + SB_STATUS Status = SbieIniSet(&req->h, req->old_password, "GlobalSettings", "*"); if (!Status.IsError()) m->Password = NewPassword; - free(req); return Status; } @@ -2600,14 +2575,59 @@ bool CSbieAPI::GetMonitor() uSize -= sizeof(ULONG); QStringList LogData; - for (size_t pos = 0; pos < uSize; ) { - size_t len = wcslen((WCHAR*)(ptr + pos)); - LogData.append(QString::fromWCharArray((WCHAR*)(ptr + pos), len)); - pos += (len + 1) * sizeof(WCHAR); + for (; uSize > 0;) { + if (*(WCHAR*)ptr == 0xFFFF) { // end of strings marker + ptr += sizeof(WCHAR); + uSize -= sizeof(WCHAR); + break; + } + size_t len = wcslen((WCHAR*)ptr); + QString str = QString::fromWCharArray((WCHAR*)ptr, len); + ptr += (len + 1) * sizeof(WCHAR); + uSize -= (len + 1) * sizeof(WCHAR); + LogData.append(str); } - ptr += uSize; - CTraceEntryPtr LogEntry = CTraceEntryPtr(new CTraceEntry(FILETIME2ms(uTimestamp), uPid, uTid, uType, LogData)); + QVector Stack; + + for (; uSize > 0;) { + + ULONG uTagID = *(ULONG*)ptr; + ptr += sizeof(ULONG); + uSize -= sizeof(ULONG); + + ULONG uTagLen = *(ULONG*)ptr; + ptr += sizeof(ULONG); + uSize -= sizeof(ULONG); + + switch (uTagID) { + case 'STCK': + int PtrSize = sizeof(PVOID); +#ifndef _WIN64 + if (IsWow64()) + PtrSize = sizeof(__int64); +#endif + int Frames = uTagLen / PtrSize; + Stack.reserve(Frames); + for (int i = 0; i < Frames; i++) { + quint64 Address; +#ifndef _WIN64 + if (PtrSize == sizeof(quint32)) + Address = ((quint32*)ptr)[i]; + else +#endif + Address = ((quint64*)ptr)[i]; + + if ((Address & 0x8000000000000000ull) == 0) // skip kernel addresses + Stack.append(Address); + } + } + + ptr += uTagLen; + uSize -= uTagLen; + } + + CTraceEntryPtr LogEntry = CTraceEntryPtr(new CTraceEntry(FILETIME2ms(uTimestamp), uPid, uTid, uType, LogData, Stack)); QMutexLocker Lock(&m_TraceMutex); m_TraceCache.append(LogEntry); @@ -2635,6 +2655,9 @@ const QVector& CSbieAPI::GetTrace() if (CBoxedProcessPtr proc = m_BoxedProxesses.value(pEntry->GetProcessId())) { pEntry->SetProcessName(proc->GetProcessName()); pEntry->SetBoxPtr(proc->GetBoxPtr()); + QVector Stack = pEntry->GetStack(); + if(!Stack.isEmpty()) + proc->ResolveSymbols(Stack); } m_TraceList.append(pEntry); @@ -2654,7 +2677,7 @@ QString CSbieAPI::GetSbieMsgStr(quint32 code, quint32 Lang) WCHAR* ret_str = NULL; if (!m->SbieMsgDll || (FormatMessage(FormatFlags, m->SbieMsgDll, code, Lang, (LPWSTR)&ret_str, 4, NULL) == 0 && FormatMessage(FormatFlags, m->SbieMsgDll, code, 1033, (LPWSTR)&ret_str, 4, NULL) == 0)) - return QString("SBIE%0: %1; %2").arg(code, 4, 10); + return QString("SBIE%0: %1; %2").arg(code & 0xFFFF, 4, 10); QString qStr = QString::fromWCharArray(ret_str); LocalFree(ret_str); return qStr.trimmed(); // note messages may have \r\n at the end @@ -2726,15 +2749,15 @@ SB_RESULT(int) CSbieAPI::RunUpdateUtility(const QStringList& Params, quint32 Ele ULONG cmd_len = Command.length(); ULONG req_len = sizeof(PROCESS_RUN_UPDATER_REQ) + (cmd_len + 8) * sizeof(WCHAR); - PROCESS_RUN_UPDATER_REQ* req = (PROCESS_RUN_UPDATER_REQ*)malloc(req_len); + SScoped req(malloc(req_len)); req->h.length = req_len; req->h.msgid = MSGID_PROCESS_RUN_UPDATER; req->elevate = Elevate; - WCHAR* ptr = (WCHAR*)((ULONG_PTR)req + sizeof(PROCESS_RUN_UPDATER_REQ)); + WCHAR* ptr = (WCHAR*)((ULONG_PTR)req.Value() + sizeof(PROCESS_RUN_UPDATER_REQ)); - req->cmd_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req); + req->cmd_ofs = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)req.Value()); req->cmd_len = cmd_len; if (cmd_len) { Command.toWCharArray(ptr); @@ -2742,9 +2765,8 @@ SB_RESULT(int) CSbieAPI::RunUpdateUtility(const QStringList& Params, quint32 Ele } *ptr++ = L'\0'; - PROCESS_RUN_UPDATER_RPL *rpl; + SScoped rpl; SB_STATUS Status = CallServer(&req->h, &rpl); - free(req); if (!Status) return Status; if (!rpl) @@ -2762,7 +2784,5 @@ SB_RESULT(int) CSbieAPI::RunUpdateUtility(const QStringList& Params, quint32 Ele CloseHandle((HANDLE)rpl->hProcess); CloseHandle((HANDLE)rpl->hThread); - free(rpl); - return CSbieResult((int)ExitCode); } diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.h b/SandboxiePlus/QSbieAPI/SbieAPI.h index 20425b54..c53dae21 100644 --- a/SandboxiePlus/QSbieAPI/SbieAPI.h +++ b/SandboxiePlus/QSbieAPI/SbieAPI.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2020, David Xanatos + * Copyright (c) 2020-2023, David Xanatos * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -260,11 +260,39 @@ protected: QString m_PublicDir; QString m_UserDir; +public: + + struct SScopedVoid { + ~SScopedVoid() { if (ptr) free(ptr); } + + inline void Assign(void* p) {Q_ASSERT(!ptr); ptr = p;} + + protected: + SScopedVoid(void* p) : ptr(p) {} + void* ptr; + }; + + template + struct SScoped : public SScopedVoid { + SScoped(void* p = NULL) : SScopedVoid(p) {} + + inline T* Detache() {T* p = ptr; ptr = NULL; return p;} + inline T* Value() {return (T*)ptr;} + inline T* operator->() const {return (T*)ptr;} + inline T& operator*() const {return *((T*)ptr);} + inline operator T*() const {return (T*)ptr;} + + private: + SScoped(const SScoped& other) {} // copying is explicitly forbidden + SScoped& operator=(T* p) {return *this;} + SScoped& operator=(const SScoped& other) {return *this;} + }; + private: mutable QMutex m_ThreadMutex; mutable QWaitCondition m_ThreadWait; - SB_STATUS CallServer(void* req, void* rpl) const; + SB_STATUS CallServer(void* req, SScopedVoid* prpl) const; SB_STATUS SbieIniSet(void *RequestBuf, void *pPasswordWithinRequestBuf, const QString& SectionName, const QString& SettingName); struct SSbieAPI* m; }; diff --git a/SandboxiePlus/QSbieAPI/SbieTrace.cpp b/SandboxiePlus/QSbieAPI/SbieTrace.cpp index c60ae74a..eafdfcb4 100644 --- a/SandboxiePlus/QSbieAPI/SbieTrace.cpp +++ b/SandboxiePlus/QSbieAPI/SbieTrace.cpp @@ -60,7 +60,7 @@ QString ErrorString(qint32 err) return Error; } -CTraceEntry::CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData) +CTraceEntry::CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData, const QVector& Stack) { m_ProcessId = ProcessId; m_ThreadId = ThreadId; @@ -68,6 +68,7 @@ CTraceEntry::CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, m_Message = LogData.length() > 1 ? LogData.at(1) : QString(); m_SubType = LogData.length() > 2 ? LogData.at(2) : QString(); m_Type.Flags = Type; + m_Stack = Stack; if (m_Type.Type == MONITOR_SYSCALL && !m_SubType.isEmpty()) { m_Message += ", name=" + m_SubType; diff --git a/SandboxiePlus/QSbieAPI/SbieTrace.h b/SandboxiePlus/QSbieAPI/SbieTrace.h index 7ba05b46..94f69bff 100644 --- a/SandboxiePlus/QSbieAPI/SbieTrace.h +++ b/SandboxiePlus/QSbieAPI/SbieTrace.h @@ -28,7 +28,7 @@ class QSBIEAPI_EXPORT CTraceEntry : public QSharedData { public: - CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData); + CTraceEntry(quint64 Timestamp, quint32 ProcessId, quint32 ThreadId, quint32 Type, const QStringList& LogData, const QVector& Stack = QVector()); virtual QString GetName() const { return m_Name; } virtual QString GetMessage() const { return m_Message; } @@ -45,6 +45,8 @@ public: virtual void SetProcessName(const QString& name) { m_ProcessName = name; } virtual QString GetProcessName() const { return m_ProcessName; } + const QVector GetStack() const { return m_Stack; } + virtual void SetBoxPtr(void* ptr) { m_BoxPtr = ptr; } virtual void* GetBoxPtr() const { return m_BoxPtr; } @@ -74,6 +76,7 @@ protected: quint32 m_ThreadId; quint64 m_TimeStamp; QString m_ProcessName; + QVector m_Stack; void* m_BoxPtr; union diff --git a/SandboxiePlus/SandMan/Resources/Actions/Stack.png b/SandboxiePlus/SandMan/Resources/Actions/Stack.png new file mode 100644 index 00000000..1f8ec3a8 Binary files /dev/null and b/SandboxiePlus/SandMan/Resources/Actions/Stack.png differ diff --git a/SandboxiePlus/SandMan/Resources/SandMan.qrc b/SandboxiePlus/SandMan/Resources/SandMan.qrc index 05b93588..edf84e15 100644 --- a/SandboxiePlus/SandMan/Resources/SandMan.qrc +++ b/SandboxiePlus/SandMan/Resources/SandMan.qrc @@ -150,6 +150,7 @@ Actions/Windows.png Actions/Interface.png Actions/Notification.png + Actions/Stack.png Boxes/sandbox-b-empty.png diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp index f7e84c9d..4fa34cf1 100644 --- a/SandboxiePlus/SandMan/SandMan.cpp +++ b/SandboxiePlus/SandMan/SandMan.cpp @@ -35,6 +35,7 @@ #include #include "Helpers/FullScreen.h" #include "Helpers/WinHelper.h" +#include "../QSbieAPI/Helpers/DbgHelper.h" CSbiePlusAPI* theAPI = NULL; @@ -1421,7 +1422,7 @@ void CSandMan::timerEvent(QTimerEvent* pEvent) bIsMonitoring = true; // don't disable the view as long as there are entries shown if (bIsMonitoring && m_pTraceView) m_pTraceInfo->setText(QString::number(iTraceCount)); - m_pTraceView->setEnabled(bIsMonitoring); + m_pTraceView->SetEnabled(bIsMonitoring); } QMap Processes = theAPI->GetAllProcesses(); @@ -2813,28 +2814,26 @@ void CSandMan::OnResetMsgs() void CSandMan::OnResetGUI() { - theConf->DelValue("ErrorWindow/Window_Geometry"); - theConf->DelValue("MainWindow/Window_Geometry"); - theConf->DelValue("MainWindow/Window_State"); - theConf->DelValue("MainWindow/BoxTree_Columns"); - theConf->DelValue("MainWindow/LogList_Columns"); - theConf->DelValue("MainWindow/Log_Splitter"); - theConf->DelValue("MainWindow/Panel_Splitter"); - theConf->DelValue("MainWindow/BoxTree_Columns"); - theConf->DelValue("MainWindow/TraceLog_Columns"); - theConf->DelValue("FileBrowserWindow/Window_Geometry"); - theConf->DelValue("MainWindow/FileTree_Columns"); - theConf->DelValue("NewBoxWindow/Window_Geometry"); - theConf->DelValue("PopUpWindow/Window_Geometry"); - theConf->DelValue("RecoveryWindow/Window_Geometry"); - theConf->DelValue("RecoveryWindow/TreeView_Columns"); - theConf->DelValue("SelectBoxWindow/Window_Geometry"); - theConf->DelValue("SettingsWindow/Window_Geometry"); - theConf->DelValue("SnapshotsWindow/Window_Geometry"); - QStringList Options = theConf->ListKeys("OptionsWindow"); - foreach(const QString& Option, Options) + foreach(const QString& Option, theConf->ListKeys("RecoveryWindow")) + theConf->DelValue("RecoveryWindow/" + Option); + + foreach(const QString& Option, theConf->ListKeys("MainWindow")) + theConf->DelValue("MainWindow/" + Option); + + foreach(const QString& Option, theConf->ListKeys("SettingsWindow")) + theConf->DelValue("SettingsWindow/" + Option); + + foreach(const QString& Option, theConf->ListKeys("OptionsWindow")) theConf->DelValue("OptionsWindow/" + Option); + theConf->DelValue("ErrorWindow/Window_Geometry"); + theConf->DelValue("PopUpWindow/Window_Geometry"); + theConf->DelValue("TraceWindow/Window_Geometry"); + theConf->DelValue("SelectBoxWindow/Window_Geometry"); + theConf->DelValue("SnapshotsWindow/Window_Geometry"); + theConf->DelValue("FileBrowserWindow/Window_Geometry"); + theConf->DelValue("RecoveryLogWindow/Window_Geometry"); + // theConf->SetValue("Options/DPIScaling", 1); theConf->SetValue("Options/FontScaling", 100); @@ -2928,6 +2927,15 @@ void CSandMan::OnIniReloaded() m_pPopUpWindow->ReloadHiddenMessages(); g_FeatureFlags = theAPI->GetFeatureFlags(); + + if (theAPI->GetGlobalSettings()->GetBool("MonitorStackTrace", false)) { + QString SymPath = theConf->GetString("Options/Debug"); + if (SymPath.isEmpty()){ + SymPath = "SRV*C:\\Symbols*https://msdl.microsoft.com/download/symbols"; + theConf->SetValue("Options/Debug", SymPath); + } + CSymbolProvider::Instance()->SetSymPath(SymPath); + } } void CSandMan::OnMonitoring() @@ -2939,7 +2947,10 @@ void CSandMan::OnMonitoring() if(m_pEnableMonitoring->isChecked() && !m_pToolBar->isVisible()) m_pLogTabs->show(); - //m_pTraceView->setEnabled(m_pEnableMonitoring->isChecked()); + if(m_pEnableMonitoring->isChecked()) + m_pKeepTerminated->setChecked(true); + else + m_pKeepTerminated->setChecked(theConf->GetBool("Options/KeepTerminated")); } else { diff --git a/SandboxiePlus/SandMan/SandMan.pri b/SandboxiePlus/SandMan/SandMan.pri index 98e5dfc7..c3632b66 100644 --- a/SandboxiePlus/SandMan/SandMan.pri +++ b/SandboxiePlus/SandMan/SandMan.pri @@ -15,6 +15,7 @@ HEADERS += ./stdafx.h \ ./Views/SbieView.h \ ./Views/FileView.h \ ./Views/TraceView.h \ + ./Views/StackView.h \ ./Dialogs/MultiErrorDialog.h \ ./Helpers/FindTool.h \ ./Helpers/FullScreen.h \ @@ -48,6 +49,7 @@ SOURCES += ./main.cpp \ ./Views/SbieView.cpp \ ./Views/FileView.cpp \ ./Views/TraceView.cpp \ + ./Views/StackView.cpp \ ./Dialogs/MultiErrorDialog.cpp \ ./Helpers/FindTool.cpp \ ./Helpers/FullScreen.cpp \ diff --git a/SandboxiePlus/SandMan/Views/StackView.cpp b/SandboxiePlus/SandMan/Views/StackView.cpp new file mode 100644 index 00000000..772902cc --- /dev/null +++ b/SandboxiePlus/SandMan/Views/StackView.cpp @@ -0,0 +1,94 @@ +#include "stdafx.h" +#include "..\SandMan.h" +#include "StackView.h" +#include "..\..\MiscHelpers\Common\Common.h" + +CStackView::CStackView(QWidget *parent) + : CPanelView(parent) +{ + m_pMainLayout = new QVBoxLayout(); + m_pMainLayout->setContentsMargins(0, 0, 0, 0); + this->setLayout(m_pMainLayout); + + // Stack List + m_pStackList = new QTreeWidgetEx(); + m_pStackList->setItemDelegate(new CTreeItemDelegate()); + //m_pStackList->setHeaderLabels(tr("#|Symbol|Stack address|Frame address|Control address|Return address|Stack parameters|File info").split("|")); + m_pStackList->setHeaderLabels(tr("#|Symbol").split("|")); + m_pStackList->setMinimumHeight(50); + + m_pStackList->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_pStackList->setSortingEnabled(false); + + m_pStackList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_pStackList, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnMenu(const QPoint &))); + + m_pMainLayout->addWidget(CFinder::AddFinder(m_pStackList, this, true, &m_pFinder)); + // + + m_bIsInvalid = false; + + //m_pMenu = new QMenu(); + AddPanelItemsToMenu(); + + m_pStackList->header()->restoreState(theConf->GetBlob("MainWindow/StackView_Columns")); +} + +CStackView::~CStackView() +{ + theConf->SetBlob("MainWindow/StackView_Columns", m_pStackList->header()->saveState()); +} + +void CStackView::Invalidate() +{ + m_bIsInvalid = true; + + for (int i = 0; i < m_pStackList->topLevelItemCount(); i++) + { + for(int j=0; j < m_pStackList->columnCount(); j++) + m_pStackList->topLevelItem(i)->setForeground(j, Qt::lightGray); + } +} + +void CStackView::SetFilter(const QRegularExpression& Exp, bool bHighLight, int Col) +{ + CPanelWidgetEx::ApplyFilter(m_pStackList, Exp/*, bHighLight, Col*/); +} + +void CStackView::ShowStack(const QVector& Stack, const CBoxedProcessPtr& pProcess) +{ + int i = 0; + for (; i < Stack.count(); i++) + { + quint64 Address = Stack[i]; + + QTreeWidgetItem* pItem; + if (i >= m_pStackList->topLevelItemCount()) + { + pItem = new QTreeWidgetItem(); + pItem->setData(eStack, Qt::UserRole, i); + pItem->setText(eStack, QString::number(i)); + m_pStackList->addTopLevelItem(pItem); + } + else + pItem = m_pStackList->topLevelItem(i); + + if (m_bIsInvalid) + { + for (int j = 0; j < m_pStackList->columnCount(); j++) + pItem->setForeground(j, Qt::black); + } + + QString Symbol = pProcess->GetSymbol(Address); + if (Symbol.isNull()) Symbol = FormatAddress(Address); + pItem->setText(eSymbol, Symbol); + } + + for (; i < m_pStackList->topLevelItemCount(); ) + delete m_pStackList->topLevelItem(i); + + if (!m_pFinder->GetSearchExp().pattern().isEmpty()) + SetFilter(m_pFinder->GetSearchExp()); + + m_bIsInvalid = false; +} diff --git a/SandboxiePlus/SandMan/Views/StackView.h b/SandboxiePlus/SandMan/Views/StackView.h new file mode 100644 index 00000000..ac16b9f4 --- /dev/null +++ b/SandboxiePlus/SandMan/Views/StackView.h @@ -0,0 +1,50 @@ +#pragma once + +#include "../../MiscHelpers/Common/PanelView.h" +#include "../../MiscHelpers/Common/TreeviewEx.h" +#include "../Models/SbieModel.h" +#include "../Models/TraceModel.h" +#include "../Models/MonitorModel.h" +#include "../../MiscHelpers/Common/SortFilterProxyModel.h" + + +class CFinder; + +class CStackView : public CPanelView +{ + Q_OBJECT +public: + CStackView(QWidget *parent = 0); + virtual ~CStackView(); + +public slots: + void Clear() { m_pStackList->clear(); } + void Invalidate(); + void ShowStack(const QVector& Stack, const CBoxedProcessPtr& pProcess); + + //void OnMenu(const QPoint &point); + + void SetFilter(const QRegularExpression& Exp, bool bHighLight = false, int Col = -1); // -1 = any + +protected: + //virtual void OnMenu(const QPoint& Point); + virtual QTreeView* GetView() { return m_pStackList; } + virtual QAbstractItemModel* GetModel() { return m_pStackList->model(); } + +private: + enum EStackColumns + { + eStack = 0, + eSymbol, + eCount + }; + + QVBoxLayout* m_pMainLayout; + + bool m_bIsInvalid; + QTreeWidgetEx* m_pStackList; + + CFinder* m_pFinder; + + //QMenu* m_pMenu; +}; diff --git a/SandboxiePlus/SandMan/Views/TraceView.cpp b/SandboxiePlus/SandMan/Views/TraceView.cpp index e4c51766..13abdc32 100644 --- a/SandboxiePlus/SandMan/Views/TraceView.cpp +++ b/SandboxiePlus/SandMan/Views/TraceView.cpp @@ -49,8 +49,28 @@ // CTraceTree CTraceTree::CTraceTree(QWidget* parent) - : CPanelWidget(parent) + : CPanelView(parent) { + m_pMainLayout = new QVBoxLayout(); + m_pMainLayout->setContentsMargins(0,0,0,0); + this->setLayout(m_pMainLayout); + + m_pSplitter = new QSplitter(); + m_pSplitter->setOrientation(Qt::Horizontal); + m_pMainLayout->addWidget(m_pSplitter); + + m_pTreeList = new QTreeViewEx(); + m_pTreeList->setColumnFixed(0, true); + m_pTreeList->setColumnFixed(1, true); + m_pTreeList->setColumnFixed(2, true); + m_pTreeList->setColumnFixed(3, true); + m_pTreeList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_pTreeList, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(OnMenu(const QPoint &))); + //m_pSplitter->addWidget(m_pTreeList); + m_pTreeList->setMinimumHeight(50); + AddPanelItemsToMenu(); + + m_bHighLight = false; //m_FilterCol = -1; @@ -81,31 +101,48 @@ CTraceTree::CTraceTree(QWidget* parent) m_pTreeList->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_pTreeList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnMenu(const QPoint&))); - m_pTreeList->setColumnFixed(0, true); - m_pTreeList->setColumnFixed(1, true); - m_pTreeList->setColumnFixed(2, true); - m_pTreeList->setColumnFixed(3, true); m_pTreeList->setColumnReset(1); //connect(m_pTreeList, SIGNAL(ResetColumns()), m_pTreeList, SLOT(OnResetColumns())); //connect(m_pBoxTree, SIGNAL(ColumnChanged(int, bool)), this, SLOT(OnColumnsChanged())); //m_pMainLayout->addWidget(CFinder::AddFinder(m_pTreeList, m_pSortProxy)); + /*CFinder* pFinder = new CFinder(this, this, CFinder::eHighLightDefault); + pFinder->SetTree(m_pTreeList); + m_pMainLayout->addWidget(pFinder);*/ + CFinder* pFinder; - m_pMainLayout->addWidget(CFinder::AddFinder(m_pTreeList, this, CFinder::eHighLightDefault, &pFinder)); + //m_pMainLayout->addWidget(CFinder::AddFinder(m_pTreeList, this, CFinder::eHighLightDefault, &pFinder)); + m_pSplitter->addWidget(CFinder::AddFinder(m_pTreeList, this, CFinder::eHighLightDefault, &pFinder)); pFinder->SetModel(m_pTraceModel); //QObject::connect(pFinder, SIGNAL(SelectNext()), this, SLOT(SelectNext())); + m_pStackView = new CStackView(); + m_pSplitter->addWidget(m_pStackView); + + connect(m_pTreeList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), SLOT(ItemSelection(QItemSelection, QItemSelection))); + + QByteArray Columns = theConf->GetBlob("MainWindow/TraceLog_Columns"); if (!Columns.isEmpty()) ((QTreeViewEx*)GetView())->restoreState(Columns); else ((QTreeViewEx*)GetView())->OnResetColumns(); + + QByteArray Split = theConf->GetBlob("MainWindow/TraceSplitter"); + if(!Split.isEmpty()) + m_pSplitter->restoreState(Split); + //else { // by default colapse the details pannel + // auto Sizes = m_pSplitter->sizes(); + // Sizes[1] = 0; + // m_pSplitter->setSizes(Sizes); + //} } CTraceTree::~CTraceTree() { theConf->SetBlob("MainWindow/TraceLog_Columns", GetView()->header()->saveState()); + theConf->SetBlob("MainWindow/TraceSplitter", m_pSplitter->saveState()); } void CTraceTree::SetFilter(const QString& Exp, int iOptions, int Column) @@ -123,6 +160,20 @@ void CTraceTree::SetFilter(const QString& Exp, int iOptions, int Column) emit FilterChanged(); } +void CTraceTree::ItemSelection(const QItemSelection& selected, const QItemSelection& deselected) +{ + QItemSelectionModel* selectionModel = m_pTreeList->selectionModel(); + QItemSelection selection = selectionModel->selection(); + + if (selection.indexes().isEmpty()) + return; + + CTraceEntryPtr pEntry = m_pTraceModel->GetEntry(selection.indexes().first()); + CBoxedProcessPtr pProcess = theAPI->GetProcessById(pEntry->GetProcessId()); + if(!pProcess.isNull()) + m_pStackView->ShowStack(pEntry->GetStack(), pProcess); +} + //////////////////////////////////////////////////////////////////////////////////////// @@ -183,8 +234,6 @@ CMonitorList::~CMonitorList() CTraceView::CTraceView(bool bStandAlone, QWidget* parent) : QWidget(parent) { - //m_pTreeList->setItemDelegate(theGUI->GetItemDelegate()); - m_FullRefresh = true; m_LastID = 0; @@ -258,9 +307,11 @@ CTraceView::CTraceView(bool bStandAlone, QWidget* parent) : QWidget(parent) else { m_pAllBoxes = m_pTraceToolBar->addAction(CSandMan::GetIcon("All"), tr("Show All Boxes"), this, SLOT(OnSetFilter())); m_pAllBoxes->setCheckable(true); - m_pAllBoxes->setChecked(theConf->GetBool("Options/UseLogTree")); } + m_pShowStack = m_pTraceToolBar->addAction(CSandMan::GetIcon("Stack"), tr("Show Stack Trace"), this, SLOT(OnShowStack())); + m_pShowStack->setCheckable(true); + m_pTraceToolBar->addSeparator(); m_pSaveToFile = m_pTraceToolBar->addAction(CSandMan::GetIcon("Save"), tr("Save to file"), this, SLOT(SaveToFile())); @@ -312,6 +363,19 @@ void CTraceView::timerEvent(QTimerEvent* pEvent) Refresh(); } +void CTraceView::SetEnabled(bool bSet) +{ + setEnabled(bSet); + m_pShowStack->setChecked(theAPI->GetGlobalSettings()->GetBool("MonitorStackTrace", false)); + m_pTrace->m_pStackView->setVisible(m_pShowStack->isChecked()); +} + +void CTraceView::OnShowStack() +{ + theAPI->GetGlobalSettings()->SetBool("MonitorStackTrace", m_pShowStack->isChecked()); + m_pTrace->m_pStackView->setVisible(m_pShowStack->isChecked()); +} + void CTraceView::Refresh() { QListBoxes; @@ -451,7 +515,7 @@ void CTraceView::Refresh() if (m_pMonitor->m_pMonitorModel->IsObjTree()) { - QTimer::singleShot(100, this, [this, NewBranches]() { + QTimer::singleShot(10, this, [this, NewBranches]() { CSortFilterProxyModel* pSortProxy = m_pMonitor->m_pSortProxy; foreach(const QModelIndex& Index, NewBranches) { m_pMonitor->GetTree()->expand(pSortProxy->mapFromSource(Index)); @@ -472,7 +536,7 @@ void CTraceView::Refresh() if (m_pTrace->m_pTraceModel->IsTree()) { - QTimer::singleShot(100, this, [this, NewBranches]() { + QTimer::singleShot(10, this, [this, NewBranches]() { quint64 start = GetCurCycle(); foreach(const QModelIndex& Index, NewBranches) m_pTrace->GetTree()->expand(Index); @@ -527,6 +591,7 @@ void CTraceView::OnSetMode() m_pTraceTree->setEnabled(!m_pMonitorMode->isChecked()); m_pObjectTree->setEnabled(m_pMonitorMode->isChecked()); m_pTraceStatus->setEnabled(!m_pMonitorMode->isChecked()); + m_pShowStack->setEnabled(!m_pMonitorMode->isChecked()); m_FullRefresh = true; Refresh(); diff --git a/SandboxiePlus/SandMan/Views/TraceView.h b/SandboxiePlus/SandMan/Views/TraceView.h index 3b751644..e338e3ab 100644 --- a/SandboxiePlus/SandMan/Views/TraceView.h +++ b/SandboxiePlus/SandMan/Views/TraceView.h @@ -6,9 +6,10 @@ #include "../Models/TraceModel.h" #include "../Models/MonitorModel.h" #include "../../MiscHelpers/Common/SortFilterProxyModel.h" +#include "StackView.h" -class CTraceTree : public CPanelWidget +class CTraceTree : public CPanelView { Q_OBJECT public: @@ -16,11 +17,19 @@ public: CTraceTree(QWidget* parent = 0); ~CTraceTree(); + virtual QMenu* GetMenu() { return m_pMenu; } + + virtual QTreeViewEx* GetTree() { return m_pTreeList; } + virtual QTreeView* GetView() { return m_pTreeList; } + virtual QAbstractItemModel* GetModel() { return m_pTreeList->model(); } + CTraceModel* m_pTraceModel; public slots: void SetFilter(const QString& Exp, int iOptions = 0, int Column = -1); + void ItemSelection(const QItemSelection& selected, const QItemSelection& deselected); + signals: void FilterChanged(); @@ -29,6 +38,11 @@ protected: QString GetFilterExp() const { return m_FilterExp; } + QVBoxLayout* m_pMainLayout; + QSplitter* m_pSplitter; + QTreeViewEx* m_pTreeList; + CStackView* m_pStackView; + //QRegularExpression m_FilterExp; QString m_FilterExp; bool m_bHighLight; @@ -55,6 +69,8 @@ public: void AddAction(QAction* pAction); + void SetEnabled(bool bSet); + public slots: void Refresh(); void Clear(); @@ -65,6 +81,7 @@ public slots: void OnSetPidFilter(); void OnSetTidFilter(); void OnSetFilter(); + void OnShowStack(); private slots: void UpdateFilters(); @@ -112,6 +129,7 @@ protected: class QCheckList* m_pTraceType; QComboBox* m_pTraceStatus; QAction* m_pAllBoxes; + QAction* m_pShowStack; QAction* m_pSaveToFile; QWidget* m_pView; diff --git a/SandboxiePlus/SandMan/main.cpp b/SandboxiePlus/SandMan/main.cpp index 894006ef..ab47af70 100644 --- a/SandboxiePlus/SandMan/main.cpp +++ b/SandboxiePlus/SandMan/main.cpp @@ -14,18 +14,6 @@ CSettings* theConf = NULL; QString g_PendingMessage; -class CCustomStyle : public QProxyStyle { -public: - CCustomStyle(QStyle* style = 0) : QProxyStyle(style) {} - - int styleHint(StyleHint stylehint, const QStyleOption* opt = nullptr, - const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const - { - if (stylehint == SH_Menu_SubMenuSloppyCloseTimeout) - return -1; - return QProxyStyle::styleHint(stylehint, opt, widget, returnData); - } -}; int main(int argc, char *argv[]) { srand(QDateTime::currentDateTimeUtc().toSecsSinceEpoch()); @@ -74,9 +62,6 @@ int main(int argc, char *argv[]) QtSingleApplication app(argc, argv); app.setQuitOnLastWindowClosed(false); - CCustomStyle* style = new CCustomStyle(app.style()); - app.setStyle(style); - //InitConsole(false); bool IsBoxed = GetModuleHandle(L"SbieDll.dll") != NULL;