1.9.6
This commit is contained in:
parent
f6d97f0147
commit
6c5f116484
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,335 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include <QAbstractEventDispatcher>
|
||||
|
||||
#include <ntstatus.h>
|
||||
#define WIN32_NO_STATUS
|
||||
typedef long NTSTATUS;
|
||||
|
||||
#include <windows.h>
|
||||
#include "..\..\..\Sandboxie\common\win32_ntddk.h"
|
||||
|
||||
#include "DbgHelper.h"
|
||||
|
||||
|
||||
#include <dbghelp.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include "../qsbieapi_global.h"
|
||||
|
||||
#include <QQueue>
|
||||
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<CSymbolProviderJob*> m_JobQueue;
|
||||
|
||||
QMutex m_SymLock;
|
||||
QHash<quint64, SWorker> 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);
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "BoxedProcess.h"
|
||||
#include "SandBox.h"
|
||||
#include "../SbieAPI.h"
|
||||
#include "../Helpers/DbgHelper.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
#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<quint64>& 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&)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<quint64>& 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<quint64, SSymbol> m_Symbols;
|
||||
|
||||
//private:
|
||||
// struct SBoxedProcess* m;
|
||||
};
|
||||
|
|
|
@ -279,7 +279,7 @@ QList<QPair<QString, QString>> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <QDebug>
|
||||
#include <QStandardPaths>
|
||||
|
@ -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<QUEUE_CREATE_RPL> 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<QUEUE_GETREQ_RPL> 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<QUEUE_PUTRPL_REQ> 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<QUEUE_PUTRPL_RPL> 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<SBIE_INI_GET_PATH_RPL> 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<SBIE_INI_GET_USER_RPL> 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<MSG_HEADER> 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<SBIE_INI_SETTING_REQ> 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<SBIE_INI_SETTING_REQ> 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<SBIE_INI_SETTING_RPL> 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<MSG_HEADER> 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<MSG_HEADER> 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<PROCESS_RUN_SANDBOXED_REQ> 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<PROCESS_RUN_SANDBOXED_RPL> 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<SBIE_INI_PASSWORD_REQ> 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<SBIE_INI_PASSWORD_REQ> 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<quint64> 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<CTraceEntryPtr>& CSbieAPI::GetTrace()
|
|||
if (CBoxedProcessPtr proc = m_BoxedProxesses.value(pEntry->GetProcessId())) {
|
||||
pEntry->SetProcessName(proc->GetProcessName());
|
||||
pEntry->SetBoxPtr(proc->GetBoxPtr());
|
||||
QVector<quint64> 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<PROCESS_RUN_UPDATER_REQ> 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<PROCESS_RUN_UPDATER_RPL> 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>((int)ExitCode);
|
||||
}
|
||||
|
|
|
@ -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 <typename T>
|
||||
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<T>& operator=(T* p) {return *this;}
|
||||
SScoped<T>& operator=(const SScoped<T>& 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;
|
||||
};
|
||||
|
|
|
@ -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<quint64>& 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;
|
||||
|
|
|
@ -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<quint64>& Stack = QVector<quint64>());
|
||||
|
||||
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<quint64> 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<quint64> m_Stack;
|
||||
void* m_BoxPtr;
|
||||
|
||||
union
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -150,6 +150,7 @@
|
|||
<file>Actions/Windows.png</file>
|
||||
<file>Actions/Interface.png</file>
|
||||
<file>Actions/Notification.png</file>
|
||||
<file>Actions/Stack.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Boxes">
|
||||
<file alias="Empty3">Boxes/sandbox-b-empty.png</file>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <QSessionManager>
|
||||
#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<quint32, CBoxedProcessPtr> 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
|
||||
{
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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<quint64>& 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;
|
||||
}
|
|
@ -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<quint64>& 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;
|
||||
};
|
|
@ -49,8 +49,28 @@
|
|||
// CTraceTree
|
||||
|
||||
CTraceTree::CTraceTree(QWidget* parent)
|
||||
: CPanelWidget<QTreeViewEx>(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()
|
||||
{
|
||||
QList<CSandBoxPtr>Boxes;
|
||||
|
@ -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();
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
#include "../Models/TraceModel.h"
|
||||
#include "../Models/MonitorModel.h"
|
||||
#include "../../MiscHelpers/Common/SortFilterProxyModel.h"
|
||||
#include "StackView.h"
|
||||
|
||||
|
||||
class CTraceTree : public CPanelWidget<QTreeViewEx>
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue