Skip to content

Instantly share code, notes, and snippets.

@flowerinthenight
Last active December 20, 2021 13:25
Show Gist options
  • Save flowerinthenight/a5ab54fec75bbabf6dac33b917b44c9b to your computer and use it in GitHub Desktop.
Save flowerinthenight/a5ab54fec75bbabf6dac33b917b44c9b to your computer and use it in GitHub Desktop.
BOOL StartSystemUserProcess(
wchar_t *pszCmd,
wchar_t *pszParam,
WINSTA0_DESKTOP winstaDesktop,
DWORD *pdwExitCode,
BOOL bWaitTerm,
DWORD dwWaitMs)
{
wchar_t szCmd[MAX_PATH];
DWORD dwDirSize = sizeof(szCmd);
STARTUPINFO si;
BOOL bResult = FALSE;
BOOL bReturn = FALSE;
DWORD dwSessionId = 0xf, winlogonPid = 0xf;
HANDLE hUserToken, hUserTokenDup, hPToken, hProcess;
DWORD dwCreationFlags;
PROCESSENTRY32 procEntry;
PROCESS_INFORMATION pi;
StringCchPrintf(szCmd, MAX_PATH, L"\"%s\" %s", pszCmd, pszParam);
dwSessionId = WTSGetActiveConsoleSessionId();
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) return FALSE;
procEntry.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hSnap, &procEntry)) return FALSE;
do {
if (_wcsicmp(procEntry.szExeFile, L"winlogon.exe") == 0) {
// We found the 'winlogon' process
DWORD winlogonSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &winlogonSessId)
&& winlogonSessId == dwSessionId) {
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));
WTSQueryUserToken(dwSessionId, &hUserToken);
dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
switch (winstaDesktop) {
case WINSTA0_DEFAULT:
si.lpDesktop = L"winsta0\\default";
break;
case WINSTA0_WINLOGON:
si.lpDesktop = L"winsta0\\WinLogon";
break;
default:
si.lpDesktop = L"winsta0\\default";
break;
}
ZeroMemory(&pi, sizeof(pi));
TOKEN_PRIVILEGES tp;
LUID luid;
hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);
bResult = OpenProcessToken(
hProcess,
TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY |
TOKEN_DUPLICATE |
TOKEN_ASSIGN_PRIMARY |
TOKEN_ADJUST_SESSIONID |
TOKEN_READ |
TOKEN_WRITE,
&hPToken);
if (!bResult) {
EventWriteLastError(M, FL, FN, L"OpenProcessToken", GetLastError());
}
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
EventWriteLastError(M, FL, FN, L"LookupPrivilegeValue", GetLastError());
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hUserTokenDup);
SetTokenInformation(hUserTokenDup, TokenSessionId, (void*)dwSessionId, sizeof(DWORD));
bResult = AdjustTokenPrivileges(
hUserTokenDup,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
NULL);
if (!bResult) {
EventWriteLastError(M, FL, FN, L"AdjustTokenPrivileges", GetLastError());
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
EventWriteErrorW(M, FL, FN, L"ERROR_NOT_ALL_ASSIGNED: Token does not have the privilege.");
}
LPVOID pEnv = NULL;
if (CreateEnvironmentBlock(&pEnv, hUserTokenDup, TRUE)) {
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
} else {
pEnv = NULL;
}
// Launch the process in the client's logon session.
bResult = CreateProcessAsUser(
hUserTokenDup,
NULL,
szCmd,
NULL,
NULL,
FALSE,
dwCreationFlags,
pEnv,
NULL,
&si,
&pi);
bReturn = bResult ? TRUE : FALSE;
if (bWaitTerm == TRUE) {
if (WaitForSingleObject(pi.hProcess, dwWaitMs) == WAIT_OBJECT_0) {
if (pdwExitCode) {
GetExitCodeProcess(pi.hProcess, pdwExitCode);
}
}
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(hProcess);
CloseHandle(hUserToken);
CloseHandle(hUserTokenDup);
CloseHandle(hPToken);
return bReturn;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment