mirror of
https://github.com/BeneficialCode/WinArk
synced 2026-08-09 12:00:31 +00:00
248 lines
6.9 KiB
C++
248 lines
6.9 KiB
C++
#include "pch.h"
|
|
#include "SecurityHelper.h"
|
|
#include <sddl.h>
|
|
#include <shellapi.h>
|
|
#include "DriverHelper.h"
|
|
#include <WtsApi32.h>
|
|
#include <WinBase.h>
|
|
|
|
#pragma comment(lib,"wtsapi32")
|
|
|
|
bool SecurityHelper::IsSysRun() {
|
|
static bool runningSystem = false;
|
|
static bool runningSystemCheck = false;
|
|
if (runningSystemCheck)
|
|
return runningSystem;
|
|
|
|
runningSystemCheck = true;
|
|
wil::unique_handle hToken;
|
|
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, hToken.addressof()))
|
|
return false;
|
|
|
|
BYTE buffer[128];
|
|
DWORD len;
|
|
if (::GetTokenInformation(hToken.get(), TokenUser, &buffer, sizeof(buffer), &len)) {
|
|
auto user = reinterpret_cast<TOKEN_USER*>(buffer);
|
|
runningSystem = IsSystemSid(user->User.Sid);
|
|
}
|
|
return runningSystem;
|
|
}
|
|
|
|
bool SecurityHelper::IsSystemSid(PSID sid) {
|
|
return ::IsWellKnownSid(sid, WinLocalSystemSid);
|
|
}
|
|
|
|
bool SecurityHelper::IsRunningElevated() {
|
|
static bool runningElevated = false;
|
|
static bool runningElevatedCheck = false;
|
|
if (runningElevatedCheck)
|
|
return runningElevated;
|
|
|
|
runningElevatedCheck = true;
|
|
wil::unique_handle hToken;
|
|
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, hToken.addressof()))
|
|
return false;
|
|
|
|
TOKEN_ELEVATION te;
|
|
DWORD len;
|
|
if (::GetTokenInformation(hToken.get(), TokenElevation, &te, sizeof(te), &len)) {
|
|
runningElevated = te.TokenIsElevated ? true : false;
|
|
}
|
|
return runningElevated;
|
|
}
|
|
|
|
HICON SecurityHelper::GetShieldIcon() {
|
|
SHSTOCKICONINFO ssii = { sizeof(ssii) };
|
|
if(FAILED(::SHGetStockIconInfo(SIID_SHIELD,SHGSI_SMALLICON|SHGSI_ICON,&ssii)))
|
|
return nullptr;
|
|
|
|
return ssii.hIcon;
|
|
}
|
|
|
|
bool SecurityHelper::RunElevated(PCWSTR param, bool ui) {
|
|
WCHAR path[MAX_PATH];
|
|
::GetModuleFileName(nullptr, path, _countof(path));
|
|
|
|
SHELLEXECUTEINFO shi = { sizeof(shi) };
|
|
shi.lpFile = path;
|
|
shi.nShow = SW_SHOWDEFAULT;
|
|
shi.lpVerb = L"runas";
|
|
shi.lpParameters = param;
|
|
shi.fMask = (ui ? 0 : (SEE_MASK_FLAG_NO_UI | SEE_MASK_NO_CONSOLE)) | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
|
|
auto ok = ::ShellExecuteEx(&shi);
|
|
if (!ok)
|
|
return false;
|
|
|
|
DWORD rc = WAIT_OBJECT_0;
|
|
if (!ui) {
|
|
rc = ::WaitForSingleObject(shi.hProcess, 5000);
|
|
}
|
|
::CloseHandle(shi.hProcess);
|
|
return rc == WAIT_OBJECT_0;
|
|
}
|
|
|
|
// find first SYSTEM process with a good token to use
|
|
HANDLE SecurityHelper::OpenSystemProcessToken() {
|
|
PWTS_PROCESS_INFO pInfo;
|
|
DWORD count;
|
|
if (!::WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pInfo, &count)) {
|
|
return nullptr;
|
|
}
|
|
|
|
HANDLE hToken{};
|
|
for (DWORD i = 0; i < count && !hToken; i++) {
|
|
if (pInfo[i].SessionId == 0 && IsSystemSid(pInfo[i].pUserSid)
|
|
&& !_wcsicmp(pInfo[i].pProcessName,L"services.exe")) {
|
|
auto hProcess = DriverHelper::OpenProcess(pInfo[i].ProcessId, PROCESS_QUERY_INFORMATION);
|
|
if (hProcess) {
|
|
::OpenProcessToken(hProcess, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY | TOKEN_IMPERSONATE, &hToken);
|
|
::CloseHandle(hProcess);
|
|
}
|
|
}
|
|
}
|
|
|
|
::WTSFreeMemory(pInfo);
|
|
return hToken;
|
|
}
|
|
|
|
bool SecurityHelper::SysRun(PCWSTR param) {
|
|
auto hToken = OpenSystemProcessToken();
|
|
if (!hToken)
|
|
return false;
|
|
|
|
HANDLE hDupToken, hPrimary;
|
|
::DuplicateTokenEx(hToken, TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_PRIVILEGES,
|
|
nullptr, SecurityImpersonation, TokenImpersonation, &hDupToken);
|
|
::DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, nullptr, SecurityImpersonation, TokenPrimary, &hPrimary);
|
|
::CloseHandle(hToken);
|
|
|
|
if (hDupToken == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
WCHAR path[MAX_PATH];
|
|
::GetModuleFileName(nullptr, path, _countof(path));
|
|
|
|
STARTUPINFO si = { sizeof(si) };
|
|
si.lpDesktop = const_cast<wchar_t*>(L"Winsta0\\default");
|
|
|
|
PROCESS_INFORMATION pi;
|
|
BOOL impersonated = ::SetThreadToken(nullptr, hDupToken);
|
|
if (!impersonated)
|
|
return false;
|
|
|
|
HANDLE hCurrentToken = INVALID_HANDLE_VALUE;
|
|
DWORD session = 0, len = sizeof(session);
|
|
bool ok = ::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &hCurrentToken);
|
|
if (!ok)
|
|
return false;
|
|
::GetTokenInformation(hCurrentToken, TokenSessionId, &session, len, &len);
|
|
::CloseHandle(hCurrentToken);
|
|
|
|
if (!SetPrivilege(hDupToken, SE_ASSIGNPRIMARYTOKEN_NAME, true) ||
|
|
!SetPrivilege(hDupToken, SE_INCREASE_QUOTA_NAME, true)) {
|
|
return false;
|
|
}
|
|
|
|
std::wstring commandLine = path;
|
|
commandLine += L" ";
|
|
commandLine += param;
|
|
|
|
ok = ::SetTokenInformation(hPrimary, TokenSessionId, &session, sizeof(session));
|
|
|
|
GetCurrentDirectory(MAX_PATH, path);
|
|
if (!::CreateProcessAsUser(hPrimary, nullptr,
|
|
const_cast<wchar_t*>(commandLine.c_str()), nullptr, nullptr,
|
|
FALSE, 0, nullptr,path,
|
|
&si, &pi)) {
|
|
DWORD error = ::GetLastError();
|
|
if (error == ERROR_PRIVILEGE_NOT_HELD) {
|
|
if (!SetPrivilege(hDupToken, SE_IMPERSONATE_NAME, true))
|
|
return false;
|
|
if (!::CreateProcessWithTokenW(hPrimary, 0, nullptr,
|
|
const_cast<wchar_t*>(commandLine.c_str()), 0, nullptr, path,
|
|
&si, &pi)) {
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
::CloseHandle(hPrimary);
|
|
::CloseHandle(hDupToken);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SecurityHelper::EnablePrivilege(PCWSTR privName, bool enable) {
|
|
HANDLE hToken;
|
|
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
|
return false;
|
|
|
|
bool result = false;
|
|
TOKEN_PRIVILEGES tp;
|
|
tp.PrivilegeCount = 1;
|
|
tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
|
|
if (::LookupPrivilegeValue(nullptr, privName, &tp.Privileges[0].Luid)) {
|
|
if (::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), nullptr, nullptr))
|
|
result = ::GetLastError() == ERROR_SUCCESS;
|
|
}
|
|
::CloseHandle(hToken);
|
|
return result;
|
|
}
|
|
|
|
bool SecurityHelper::SetPrivilege(HANDLE hToken, PCWSTR privName, bool enable) {
|
|
TOKEN_PRIVILEGES tp;
|
|
LUID luid;
|
|
|
|
if (!::LookupPrivilegeValue(nullptr, privName, &luid))
|
|
return false;
|
|
|
|
tp.PrivilegeCount = 1;
|
|
tp.Privileges[0].Luid = luid;
|
|
if (enable)
|
|
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
else
|
|
tp.Privileges[0].Attributes = 0;
|
|
|
|
// Enable the privilege or disable all privileges.
|
|
if (!::AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) {
|
|
return false;
|
|
}
|
|
|
|
if (::GetLastError() == ERROR_NOT_ALL_ASSIGNED)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
std::wstring SecurityHelper::GetSidFromUser(PCWSTR name) {
|
|
BYTE sid[SECURITY_MAX_SID_SIZE];
|
|
DWORD size = sizeof(sid);
|
|
SID_NAME_USE use;
|
|
WCHAR domain[64];
|
|
DWORD domainSize = _countof(domain);
|
|
if (!::LookupAccountName(nullptr, name, (PSID)sid, &size, domain, &domainSize, &use))
|
|
return L"";
|
|
|
|
PWSTR ssid;
|
|
if (::ConvertSidToStringSid((PSID)sid, &ssid)) {
|
|
std::wstring result(ssid);
|
|
::LocalFree(ssid);
|
|
return result;
|
|
}
|
|
return L"";
|
|
}
|
|
|
|
HANDLE SecurityHelper::DupHandle(HANDLE hSource, DWORD sourcePid, DWORD access) {
|
|
auto h = DriverHelper::DupHandle(hSource, sourcePid, access, access == 0 ? DUPLICATE_SAME_ACCESS : 0);
|
|
if (!h) {
|
|
wil::unique_handle hProcess(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, sourcePid));
|
|
if (!hProcess)
|
|
return nullptr;
|
|
|
|
::DuplicateHandle(hProcess.get(), hSource, ::GetCurrentProcess(), &h, access, FALSE,
|
|
access == 0 ? DUPLICATE_SAME_ACCESS : 0);
|
|
}
|
|
return h;
|
|
} |