739 lines
22 KiB
C++
739 lines
22 KiB
C++
#include "stdafx.h"
|
|
#include "SbieUtils.h"
|
|
#include <QCoreApplication>
|
|
#include <QWinEventNotifier>
|
|
|
|
#include <ntstatus.h>
|
|
#define WIN32_NO_STATUS
|
|
typedef long NTSTATUS;
|
|
|
|
#include <windows.h>
|
|
#include <Shlobj.h>
|
|
#include "SbieDefs.h"
|
|
|
|
#include "..\..\Sandboxie\common\win32_ntddk.h"
|
|
#include "..\..\Sandboxie\common\defines.h"
|
|
|
|
#include "SbieAPI.h"
|
|
|
|
template <typename T>
|
|
__forceinline bool charIsNull(const T* v) { return *v == 0; }
|
|
__forceinline bool charIsNull(const QChar* v) { return v->isNull(); }
|
|
|
|
template <typename T>
|
|
bool wildcmpex(const T* Wild, const T* Str)
|
|
{
|
|
const T *cp = NULL, *mp = NULL;
|
|
|
|
while (!charIsNull(Str) && (*Wild != '*'))
|
|
{
|
|
if ((*Wild != *Str) && (*Wild != '?'))
|
|
return false;
|
|
Wild++;
|
|
Str++;
|
|
}
|
|
|
|
while (!charIsNull(Str))
|
|
{
|
|
if (*Wild == '*')
|
|
{
|
|
if (charIsNull(++Wild))
|
|
return Str;
|
|
mp = Wild;
|
|
cp = Str + 1;
|
|
}
|
|
else if ((*Wild == *Str) || (*Wild == '?'))
|
|
{
|
|
Wild++;
|
|
Str++;
|
|
}
|
|
else
|
|
{
|
|
Wild = mp;
|
|
Str = cp++;
|
|
}
|
|
}
|
|
|
|
while (*Wild == '*')
|
|
Wild++;
|
|
return charIsNull(Wild);
|
|
}
|
|
|
|
bool CSbieUtils::WildCompare(const QString& L, const QString& R)
|
|
{
|
|
return wildcmpex(L.data(), R.data());
|
|
}
|
|
|
|
int GetServiceStatus(const wchar_t* name)
|
|
{
|
|
SC_HANDLE scm = OpenSCManager(nullptr, nullptr, SC_MANAGER_ENUMERATE_SERVICE);
|
|
if (!scm)
|
|
return -1;
|
|
|
|
SC_HANDLE service = OpenService(scm, name, SERVICE_QUERY_STATUS);
|
|
if (!service) {
|
|
CloseServiceHandle(scm);
|
|
return 0;
|
|
}
|
|
|
|
DWORD dwBytesNeeded;
|
|
SERVICE_STATUS_PROCESS sStatus;
|
|
BOOL result = QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&sStatus, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded);
|
|
|
|
CloseServiceHandle(service);
|
|
|
|
CloseServiceHandle(scm);
|
|
|
|
if (result == 0)
|
|
return -1;
|
|
return sStatus.dwCurrentState;
|
|
}
|
|
|
|
bool IsProcessElevatd()
|
|
{
|
|
ULONG returnLength;
|
|
TOKEN_ELEVATION elevation;
|
|
if (NT_SUCCESS(NtQueryInformationToken(/*NtCurrentProcessToken()*/((HANDLE)(LONG_PTR)-4), TokenElevation, &elevation, sizeof(TOKEN_ELEVATION), &returnLength)))
|
|
return !!elevation.TokenIsElevated;
|
|
return false;
|
|
}
|
|
|
|
SB_STATUS CSbieUtils::DoAssist()
|
|
{
|
|
QStringList Args = QCoreApplication::arguments();
|
|
int AssistPos = Args.indexOf("-assist");
|
|
if(AssistPos == -1)
|
|
return SB_OK;
|
|
|
|
SB_STATUS Status = ExecOps(Args.mid(AssistPos + 1));
|
|
if (Status.IsError())
|
|
return Status;
|
|
return SB_ERR(ERROR_OK);
|
|
}
|
|
|
|
SB_RESULT(void*) CSbieUtils::Start(EComponent Component)
|
|
{
|
|
QStringList Ops;
|
|
if(!IsInstalled(Component))
|
|
Install(Component, Ops);
|
|
Start(Component, Ops);
|
|
return ElevateOps(Ops);
|
|
}
|
|
|
|
void CSbieUtils::Start(EComponent Component, QStringList& Ops)
|
|
{
|
|
// Note: Service always starts the driver
|
|
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) != SERVICE_RUNNING)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|start|" SBIESVC));
|
|
else if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) != SERVICE_RUNNING)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|start|" SBIEDRV));
|
|
}
|
|
|
|
SB_RESULT(void*) CSbieUtils::Stop(EComponent Component)
|
|
{
|
|
QStringList Ops;
|
|
Stop(Component, Ops);
|
|
return ElevateOps(Ops);
|
|
}
|
|
|
|
void CSbieUtils::Stop(EComponent Component, QStringList& Ops)
|
|
{
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|scandll"));
|
|
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) != SERVICE_STOPPED)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|stop|" SBIESVC));
|
|
if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) != SERVICE_STOPPED)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|stop|" SBIEDRV));
|
|
}
|
|
|
|
bool CSbieUtils::IsRunning(EComponent Component)
|
|
{
|
|
if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) != SERVICE_RUNNING)
|
|
return false;
|
|
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) != SERVICE_RUNNING)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
SB_RESULT(void*) CSbieUtils::Install(EComponent Component)
|
|
{
|
|
QStringList Ops;
|
|
Install(Component, Ops);
|
|
return ElevateOps(Ops);
|
|
}
|
|
|
|
void CSbieUtils::Install(EComponent Component, QStringList& Ops)
|
|
{
|
|
QString HomePath = QCoreApplication::applicationDirPath().replace("/", "\\"); // "C:\\Program Files\\Sandboxie "
|
|
if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) == 0)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|install|" SBIEDRV L"|") + HomePath + "\\" + QString::fromWCharArray(SBIEDRV_SYS) + "|type=kernel|start=demand|altitude=86900");
|
|
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) == 0) {
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|install|" SBIESVC L"|") + HomePath + "\\" + QString::fromWCharArray(SBIESVC_EXE) + "|type=own|start=auto|display=\"Sandboxie Service\"|group=UIGroup");
|
|
Ops.append("reg.exe|ADD|HKLM\\SYSTEM\\ControlSet001\\Services\\SbieSvc|/v|PreferExternalManifest|/t|REG_DWORD|/d|1|/f");
|
|
}
|
|
}
|
|
|
|
SB_RESULT(void*) CSbieUtils::Uninstall(EComponent Component)
|
|
{
|
|
QStringList Ops;
|
|
Stop(Component, Ops);
|
|
Uninstall(Component, Ops);
|
|
return ElevateOps(Ops);
|
|
}
|
|
|
|
void CSbieUtils::Uninstall(EComponent Component, QStringList& Ops)
|
|
{
|
|
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) != 0)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|delete|" SBIESVC));
|
|
if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) != 0)
|
|
Ops.append(QString::fromWCharArray(L"kmdutil.exe|delete|" SBIEDRV));
|
|
}
|
|
|
|
bool CSbieUtils::IsInstalled(EComponent Component)
|
|
{
|
|
if ((Component & eDriver) != 0 && GetServiceStatus(SBIEDRV) == 0)
|
|
return false;
|
|
if ((Component & eService) != 0 && GetServiceStatus(SBIESVC) == 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
SB_RESULT(void*) CSbieUtils::ElevateOps(const QStringList& Ops)
|
|
{
|
|
if (Ops.isEmpty())
|
|
return SB_OK;
|
|
|
|
if (IsProcessElevatd()) {
|
|
SB_RESULT(void*) result = ExecOps(Ops);
|
|
QThread::msleep(1000); // wait for the operation to finish properly
|
|
return result;
|
|
}
|
|
|
|
std::wstring path = QCoreApplication::applicationFilePath().toStdWString();
|
|
std::wstring params = L"-assist \"" + Ops.join("\" \"").toStdWString() + L"\"";
|
|
|
|
SHELLEXECUTEINFO shex;
|
|
memset(&shex, 0, sizeof(SHELLEXECUTEINFO));
|
|
shex.cbSize = sizeof(SHELLEXECUTEINFO);
|
|
shex.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS;
|
|
shex.hwnd = NULL;
|
|
shex.lpFile = path.c_str();
|
|
shex.lpParameters = params.c_str();
|
|
shex.nShow = SW_SHOWNORMAL;
|
|
shex.lpVerb = L"runas";
|
|
|
|
if (!ShellExecuteEx(&shex))
|
|
return SB_ERR(SB_NeedAdmin);
|
|
return CSbieResult<void*>(OP_ASYNC, shex.hProcess);
|
|
}
|
|
|
|
SB_STATUS CSbieUtils::ExecOps(const QStringList& Ops)
|
|
{
|
|
foreach(const QString& Op, Ops)
|
|
{
|
|
QStringList Args = Op.split("|");
|
|
QString Prog = Args.takeFirst();
|
|
|
|
QProcess Proc;
|
|
Proc.execute(Prog, Args);
|
|
Proc.waitForFinished();
|
|
int ret = Proc.exitCode();
|
|
if (ret != 0)
|
|
return SB_ERR(SB_ExecFail, QVariantList() << Args.join(" "));
|
|
}
|
|
return SB_OK;
|
|
}
|
|
|
|
CSbieProgressPtr CSbieUtils::RunCommand(const QString& Command, bool noGui)
|
|
{
|
|
STARTUPINFOW si = { 0 };
|
|
si.cb = sizeof(si);
|
|
if (noGui) {
|
|
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
|
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
|
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
|
si.wShowWindow = SW_HIDE;
|
|
}
|
|
PROCESS_INFORMATION pi = { 0 };
|
|
if (!CreateProcessW(NULL, (LPWSTR)Command.toStdWString().c_str(), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
|
|
return CSbieProgressPtr();
|
|
|
|
HANDLE hJobObject = CreateJobObject(NULL, NULL);
|
|
if (hJobObject)
|
|
AssignProcessToJobObject(hJobObject, pi.hProcess);
|
|
|
|
CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress());
|
|
|
|
QWinEventNotifier* processFinishedNotifier = new QWinEventNotifier(pi.hProcess);
|
|
processFinishedNotifier->setEnabled(true);
|
|
QObject::connect(processFinishedNotifier, &QWinEventNotifier::activated, [=]() {
|
|
processFinishedNotifier->setEnabled(false);
|
|
processFinishedNotifier->deleteLater();
|
|
|
|
pProgress->Finish(SB_OK);
|
|
|
|
if(hJobObject)
|
|
CloseHandle(hJobObject);
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
});
|
|
|
|
QObject::connect(pProgress.data(), &CSbieProgress::Canceled, [=]() {
|
|
if (hJobObject)
|
|
TerminateJobObject(hJobObject, 0);
|
|
else
|
|
TerminateProcess(pi.hProcess, 0);
|
|
});
|
|
|
|
ResumeThread(pi.hThread);
|
|
|
|
return pProgress;
|
|
}
|
|
|
|
int CSbieUtils::ExecCommand(const QString& Command, bool noGui, quint32 Timeout)
|
|
{
|
|
STARTUPINFOW si = { 0 };
|
|
si.cb = sizeof(si);
|
|
if (noGui) {
|
|
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
|
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
|
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
|
si.wShowWindow = SW_HIDE;
|
|
}
|
|
|
|
PROCESS_INFORMATION pi = { 0 };
|
|
if (!CreateProcessW(NULL, (LPWSTR)Command.toStdWString().c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
|
return -1;
|
|
|
|
int iRet = -2;
|
|
if (WaitForSingleObject(pi.hProcess, (DWORD)Timeout) == WAIT_OBJECT_0)
|
|
{
|
|
DWORD dwRet;
|
|
if (GetExitCodeProcess(pi.hProcess, &dwRet))
|
|
iRet = (int)dwRet;
|
|
}
|
|
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
int CSbieUtils::ExecCommandEx(const QString& Command, QString* pOutput, quint32 Timeout)
|
|
{
|
|
HANDLE stdoutReadHandle;
|
|
HANDLE stdoutWriteHandle;
|
|
SECURITY_ATTRIBUTES saAttr;
|
|
// Set the bInheritHandle flag so pipe handles are inherited.
|
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
saAttr.bInheritHandle = TRUE;
|
|
saAttr.lpSecurityDescriptor = nullptr;
|
|
// Create a pipe for the child process's STDOUT.
|
|
if (!CreatePipe(&stdoutReadHandle, &stdoutWriteHandle, &saAttr, 0))
|
|
return -4;
|
|
if (!SetHandleInformation(stdoutReadHandle, HANDLE_FLAG_INHERIT, 0))
|
|
return -4;
|
|
|
|
STARTUPINFOW si = { 0 };
|
|
si.cb = sizeof(si);
|
|
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
|
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
|
si.hStdOutput = stdoutWriteHandle;
|
|
si.hStdError = stdoutWriteHandle;
|
|
si.wShowWindow = SW_HIDE;
|
|
|
|
PROCESS_INFORMATION pi = { 0 };
|
|
if (!CreateProcessW(NULL, (LPWSTR)Command.toStdWString().c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
|
return -1;
|
|
|
|
DWORD exitCode, dataSize;
|
|
do
|
|
{
|
|
// Check if the process is alive.
|
|
GetExitCodeProcess(pi.hProcess, &exitCode);
|
|
|
|
// Check if there is anything in the pipe.
|
|
if (!PeekNamedPipe(stdoutReadHandle, nullptr, 0, nullptr, &dataSize, nullptr))
|
|
return -3;
|
|
if (dataSize == 0)
|
|
Sleep(10);
|
|
else {
|
|
// Read the data out of the pipe.
|
|
CHAR buffer[4096] = { 0 };
|
|
if (!ReadFile(stdoutReadHandle, buffer, sizeof(buffer) - 1, &dataSize, nullptr))
|
|
return -3;
|
|
|
|
pOutput->append(QString(buffer));
|
|
}
|
|
} while (exitCode == STILL_ACTIVE || dataSize != 0);
|
|
|
|
CloseHandle(stdoutReadHandle);
|
|
CloseHandle(stdoutWriteHandle);
|
|
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
return (int)exitCode;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Shell integration
|
|
|
|
QString CSbieUtils::GetContextMenuStartCmd()
|
|
{
|
|
const wchar_t* key = L"Software\\Classes\\*\\shell\\sandbox\\command";
|
|
HKEY hkey;
|
|
LONG rc = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hkey);
|
|
if (rc != 0)
|
|
return QString();
|
|
|
|
ULONG type;
|
|
WCHAR path[512];
|
|
ULONG path_len = sizeof(path) - sizeof(WCHAR) * 4;
|
|
rc = RegQueryValueEx(hkey, NULL, NULL, &type, (BYTE *)path, &path_len);
|
|
RegCloseKey(hkey);
|
|
if (rc != 0)
|
|
return QString();
|
|
|
|
return QString::fromWCharArray(path);
|
|
}
|
|
|
|
void CSbieUtils::AddContextMenu(const QString& StartPath, const QString& RunStr, /*const QString& ExploreStr,*/ const QString& IconPath)
|
|
{
|
|
std::wstring start_path = L"\"" + StartPath.toStdWString() + L"\"";
|
|
std::wstring icon_path = L"\"" + (IconPath.isEmpty() ? StartPath : IconPath).toStdWString() + L"\"";
|
|
|
|
CreateShellEntry(L"*", L"sandbox", RunStr.toStdWString(), icon_path, start_path + L" /box:__ask__ \"%1\" %*");
|
|
|
|
std::wstring explorer_path(512, L'\0');
|
|
|
|
HKEY hkeyWinlogon;
|
|
LONG rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"software\\microsoft\\windows nt\\currentversion\\winlogon", 0, KEY_READ, &hkeyWinlogon);
|
|
if (rc == 0)
|
|
{
|
|
ULONG path_len = explorer_path.size() * sizeof(WCHAR);
|
|
ULONG type;
|
|
rc = RegQueryValueEx(hkeyWinlogon, L"Shell", NULL, &type, (BYTE *)explorer_path.c_str(), &path_len);
|
|
if (rc == 0 && (type == REG_SZ || type == REG_EXPAND_SZ))
|
|
explorer_path.resize(path_len / sizeof(WCHAR));
|
|
RegCloseKey(hkeyWinlogon);
|
|
}
|
|
|
|
// get default explorer path
|
|
if (*explorer_path.c_str() == L'\0' || _wcsicmp(explorer_path.c_str(), L"explorer.exe") == 0)
|
|
{
|
|
GetWindowsDirectory((wchar_t*)explorer_path.c_str(), MAX_PATH);
|
|
ULONG path_len = wcslen(explorer_path.c_str());
|
|
explorer_path.resize(path_len);
|
|
explorer_path.append(L"\\explorer.exe");
|
|
}
|
|
|
|
CreateShellEntry(L"Folder", L"sandbox", RunStr.toStdWString(), icon_path, start_path + L" /box:__ask__ " + explorer_path + L" \"%1\""); // ExploreStr
|
|
}
|
|
|
|
void CSbieUtils::CreateShellEntry(const std::wstring& classname, const std::wstring& key, const std::wstring& cmdtext, const std::wstring& iconpath, const std::wstring& startcmd)
|
|
{
|
|
HKEY hkey;
|
|
LONG rc = RegCreateKeyEx(HKEY_CURRENT_USER, (L"software\\classes\\" + classname + L"\\shell\\" + key).c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL);
|
|
if (rc != 0)
|
|
return;
|
|
|
|
RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)cmdtext.c_str(), (cmdtext.length() + 1) * sizeof(WCHAR));
|
|
RegSetValueEx(hkey, L"Icon", 0, REG_SZ, (BYTE *)iconpath.c_str(), (iconpath.length() + 1) * sizeof(WCHAR));
|
|
|
|
RegCloseKey(hkey);
|
|
if (rc != 0)
|
|
return;
|
|
|
|
rc = RegCreateKeyEx(HKEY_CURRENT_USER, (L"software\\classes\\" + classname + L"\\shell\\" + key + L"\\command").c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hkey, NULL);
|
|
if (rc != 0)
|
|
return;
|
|
|
|
RegSetValueEx(hkey, NULL, 0, REG_SZ, (BYTE *)startcmd.c_str(), (startcmd.length() + 1) * sizeof(WCHAR));
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
void CSbieUtils::RemoveContextMenu()
|
|
{
|
|
RegDeleteTreeW(HKEY_CURRENT_USER, L"software\\classes\\*\\shell\\sandbox");
|
|
RegDeleteTreeW(HKEY_CURRENT_USER, L"software\\classes\\folder\\shell\\sandbox");
|
|
}
|
|
|
|
bool CSbieUtils::HasContextMenu2()
|
|
{
|
|
const wchar_t* key = L"Software\\Classes\\*\\shell\\unbox\\command";
|
|
HKEY hkey;
|
|
LONG rc = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hkey);
|
|
if (rc != 0)
|
|
return false;
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
return true;
|
|
}
|
|
|
|
void CSbieUtils::AddContextMenu2(const QString& StartPath, const QString& RunStr, const QString& IconPath)
|
|
{
|
|
std::wstring start_path = L"\"" + StartPath.toStdWString() + L"\"";
|
|
std::wstring icon_path = L"\"" + (IconPath.isEmpty() ? StartPath : IconPath).toStdWString() + L"\",-104";
|
|
|
|
CreateShellEntry(L"*", L"unbox", RunStr.toStdWString(), icon_path, start_path + L" /disable_force \"%1\" %*");
|
|
}
|
|
|
|
void CSbieUtils::RemoveContextMenu2()
|
|
{
|
|
RegDeleteTreeW(HKEY_CURRENT_USER, L"software\\classes\\*\\shell\\unbox");
|
|
}
|
|
|
|
bool CSbieUtils::HasContextMenu3()
|
|
{
|
|
const wchar_t* key = L"Software\\Classes\\*\\shell\\addforce\\command";
|
|
//const wchar_t* key2 = L"Software\\Classes\\*\\Folder\\addforce\\command";
|
|
HKEY hkey,hKey2;
|
|
LONG rc = RegOpenKeyEx(HKEY_CURRENT_USER, key, 0, KEY_READ, &hkey);
|
|
if (rc != 0)
|
|
return false;
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
/*rc = RegOpenKeyEx(HKEY_CURRENT_USER, key2, 0, KEY_READ, &hkey2);
|
|
if (rc != 0)
|
|
return false;
|
|
|
|
RegCloseKey(hkey2);*/
|
|
|
|
return true;
|
|
}
|
|
|
|
void CSbieUtils::AddContextMenu3(const QString& StartPath, const QString& RunStr, const QString& IconPath)
|
|
{
|
|
std::wstring start_path = L"\"" + StartPath.toStdWString() + L"\"";
|
|
std::wstring icon_path = L"\"" + (IconPath.isEmpty() ? StartPath : IconPath).toStdWString() + L"\"";
|
|
|
|
CreateShellEntry(L"*", L"addforce", RunStr.toStdWString(), icon_path, start_path + L" /add_force \"%1\" %*");
|
|
CreateShellEntry(L"Folder", L"addforce", RunStr.toStdWString(), icon_path, start_path + L" /add_force \"%1\" %*");
|
|
}
|
|
|
|
void CSbieUtils::RemoveContextMenu3()
|
|
{
|
|
RegDeleteTreeW(HKEY_CURRENT_USER, L"software\\classes\\*\\shell\\addforce");
|
|
RegDeleteTreeW(HKEY_CURRENT_USER, L"software\\classes\\folder\\shell\\addforce");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Shortcuts
|
|
|
|
bool CSbieUtils::CreateShortcut(const QString& StartExe, QString LinkPath, const QString &LinkName, const QString &boxname, const QString &arguments, const QString &iconPath, int iconIndex, const QString &workdir, bool bRunElevated)
|
|
{
|
|
QString StartArgs;
|
|
if (bRunElevated)
|
|
StartArgs += "/elevated ";
|
|
if (!boxname.isEmpty())
|
|
StartArgs += "/box:" + boxname;
|
|
if (!arguments.isEmpty()) {
|
|
if (!StartArgs.isEmpty()) StartArgs += " ";
|
|
if(arguments.contains(" ") && arguments.left(1) != "\"")
|
|
StartArgs += "\"" + arguments + "\"";
|
|
else
|
|
StartArgs += arguments;
|
|
}
|
|
|
|
IUnknown *pUnknown;
|
|
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC, IID_IUnknown, (void **)&pUnknown);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
IShellLink *pShellLink;
|
|
hr = pUnknown->QueryInterface(IID_IShellLink, (void **)&pShellLink);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pShellLink->SetPath(StartExe.toStdWString().c_str());
|
|
pShellLink->SetArguments(StartArgs.toStdWString().c_str());
|
|
if (!iconPath.isEmpty())
|
|
pShellLink->SetIconLocation(iconPath.toStdWString().c_str(), iconIndex);
|
|
if (!workdir.isEmpty())
|
|
pShellLink->SetWorkingDirectory(workdir.toStdWString().c_str());
|
|
if (!LinkName.isEmpty()) {
|
|
QString desc = QString("%1 [%2]").arg(LinkName).arg(boxname);
|
|
pShellLink->SetDescription(desc.toStdWString().c_str());
|
|
}
|
|
|
|
IPersistFile *pPersistFile;
|
|
hr = pUnknown->QueryInterface(IID_IPersistFile, (void **)&pPersistFile);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (LinkPath.right(4) != ".lnk")
|
|
LinkPath.append(".lnk");
|
|
|
|
pPersistFile->Save(LinkPath.toStdWString().c_str(), FALSE);
|
|
|
|
pPersistFile->Release();
|
|
}
|
|
|
|
pShellLink->Release();
|
|
}
|
|
|
|
pUnknown->Release();
|
|
return (SUCCEEDED(hr));
|
|
}
|
|
|
|
bool CSbieUtils::GetStartMenuShortcut(CSbieAPI* pApi, QString &BoxName, QString &LinkPath, QString &IconPath, quint32& IconIndex, QString &WorkDir)
|
|
{
|
|
WCHAR MapName[128];
|
|
wsprintf(MapName, SANDBOXIE L"_StartMenu_WorkArea_%08X_%08X", GetCurrentProcessId(), GetTickCount());
|
|
HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 8192, MapName);
|
|
if (!hMapping)
|
|
return false;
|
|
|
|
WCHAR* buf = (WCHAR *)MapViewOfFile(hMapping, FILE_MAP_WRITE, 0, 0, 8192);
|
|
if (!buf) {
|
|
CloseHandle(hMapping);
|
|
return false;
|
|
}
|
|
memset(buf, 0, 8192);
|
|
|
|
|
|
QProcess Process;
|
|
QString Command = "start_menu:" + QString::fromWCharArray(MapName);
|
|
if (!LinkPath.isEmpty())
|
|
Command += ":" + LinkPath;
|
|
pApi->RunStart(BoxName, Command, CSbieAPI::eStartDefault, QString(), &Process);
|
|
//Process.waitForFinished(-1);
|
|
while(Process.state() != QProcess::NotRunning)
|
|
QCoreApplication::processEvents(); // keep UI responsive
|
|
|
|
|
|
struct SLnk {
|
|
WCHAR box_name[BOXNAME_COUNT]; //0
|
|
WCHAR reserved[30]; //34
|
|
WCHAR link_path[956]; //64
|
|
ULONG IconIndex; //1020
|
|
WCHAR unused[2]; //1022
|
|
WCHAR icon_path[1024]; //1024
|
|
WCHAR work_dir[1024]; //2048
|
|
//3072
|
|
} *lnk = (SLnk*)buf;
|
|
|
|
BoxName = QString::fromWCharArray(lnk->box_name, wcsnlen_s(lnk->box_name, sizeof(lnk->box_name)));
|
|
LinkPath = QString::fromWCharArray(lnk->link_path, wcsnlen_s(lnk->link_path, sizeof(lnk->link_path)));
|
|
if (*lnk->icon_path) {
|
|
IconIndex = lnk->IconIndex;
|
|
IconPath = QString::fromWCharArray(lnk->icon_path, wcsnlen_s(lnk->icon_path, sizeof(lnk->icon_path)));
|
|
}
|
|
if (*lnk->work_dir) WorkDir = QString::fromWCharArray(lnk->work_dir, wcsnlen_s(lnk->work_dir, sizeof(lnk->work_dir)));
|
|
else WorkDir = LinkPath.left(LinkPath.lastIndexOf('\\'));
|
|
|
|
UnmapViewOfFile(buf);
|
|
CloseHandle(hMapping);
|
|
|
|
if (BoxName.isEmpty() || LinkPath.isEmpty())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOLEAN SelectFavoriteInRegedit(HWND RegeditWindow, std::wstring FavoriteName)
|
|
{
|
|
HMENU menu;
|
|
HMENU favoritesMenu;
|
|
ULONG count;
|
|
ULONG i;
|
|
ULONG id = ULONG_MAX;
|
|
|
|
if (IsIconic(RegeditWindow)) {
|
|
ShowWindow(RegeditWindow, SW_RESTORE);
|
|
SetForegroundWindow(RegeditWindow);
|
|
}
|
|
else {
|
|
SetForegroundWindow(RegeditWindow);
|
|
}
|
|
|
|
if (!(menu = GetMenu(RegeditWindow)))
|
|
return FALSE;
|
|
|
|
/*UINT scan = MapVirtualKey(VK_F5, 0);
|
|
LPARAM lparam = 0x00000001 | (LPARAM)(scan << 16);
|
|
SendMessage(RegeditWindow, WM_KEYDOWN, VK_F5, lparam);
|
|
SendMessage(RegeditWindow, WM_KEYUP, VK_F5, 0);*/
|
|
SendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(2, MF_POPUP), (LPARAM)menu);
|
|
SendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(0x288, 0), 0); // F5 menu entry
|
|
PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);
|
|
|
|
|
|
SendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu);
|
|
if (!(favoritesMenu = GetSubMenu(menu, 3)))
|
|
return FALSE;
|
|
|
|
count = GetMenuItemCount(favoritesMenu);
|
|
if (count == -1) return FALSE;
|
|
if (count > 1000) count = 1000;
|
|
|
|
for (i = 3; i < count; i++) {
|
|
|
|
MENUITEMINFO info = { sizeof(MENUITEMINFO) };
|
|
WCHAR buffer[MAX_PATH];
|
|
|
|
info.fMask = MIIM_ID | MIIM_STRING;
|
|
info.dwTypeData = buffer;
|
|
info.cch = RTL_NUMBER_OF(buffer);
|
|
GetMenuItemInfo(favoritesMenu, i, TRUE, &info);
|
|
|
|
if (info.cch > 0 && _wcsicmp(FavoriteName.c_str(),buffer) == 0) {
|
|
id = info.wID;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (id == ULONG_MAX)
|
|
return FALSE;
|
|
|
|
SendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0);
|
|
PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool ShellOpenRegKey(const QString& KeyName)
|
|
{
|
|
std::wstring keyName = KeyName.toStdWString();
|
|
|
|
HWND regeditWindow = FindWindow(L"RegEdit_RegEdit", NULL);
|
|
|
|
if (!regeditWindow)
|
|
{
|
|
RegSetKeyValue(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit", L"LastKey", REG_SZ, keyName.c_str(), (keyName.size() + 1) * sizeof(WCHAR));
|
|
|
|
SHELLEXECUTEINFO sei = { sizeof(sei) };
|
|
sei.fMask = 0;
|
|
sei.lpVerb = NULL;
|
|
sei.lpFile = L"regedit.exe";
|
|
sei.lpParameters = NULL;
|
|
sei.hwnd = NULL;
|
|
sei.nShow = SW_NORMAL;
|
|
|
|
ShellExecuteEx(&sei);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// for this to work we need elevated privileges !!!
|
|
|
|
QString FavoriteName = "A_Sandbox_" + QString::number((quint32)rand(), 16);
|
|
std::wstring favoriteName = FavoriteName.toStdWString();
|
|
|
|
RegSetKeyValue(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites", favoriteName.c_str(), REG_SZ, keyName.c_str(), (keyName.size() + 1) * sizeof(WCHAR));
|
|
|
|
BOOLEAN result = SelectFavoriteInRegedit(regeditWindow, favoriteName);
|
|
|
|
HKEY key;
|
|
RegOpenKey(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites", &key);
|
|
RegDeleteValue(key, favoriteName.c_str());
|
|
RegCloseKey(key);
|
|
|
|
return result;
|
|
}
|
|
|