This commit is contained in:
DavidXanatos 2023-05-27 09:03:42 +02:00
parent f6d97f0147
commit 6c5f116484
23 changed files with 902 additions and 139 deletions

View File

@ -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)

View File

@ -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);

View File

@ -470,3 +470,32 @@ _FX LARGE_INTEGER Util_GetTimestamp(void)
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;
}

View File

@ -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);
//---------------------------------------------------------------------------

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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

View File

@ -19,6 +19,7 @@
#include "BoxedProcess.h"
#include "SandBox.h"
#include "../SbieAPI.h"
#include "../Helpers/DbgHelper.h"
#include <ntstatus.h>
#define WIN32_NO_STATUS
@ -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&)));
}
}
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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)
@ -1907,8 +1886,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);
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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>

View 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
{

View File

@ -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 \

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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();

View File

@ -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;

View File

@ -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;