Files
2026-05-06 09:11:06 +10:00

354 lines
9.2 KiB
C++

#include "internal.h"
BOOL ControllerInjectionAcquirePrimaryTokenFromProcess(_In_ DWORD ProcessId, _Out_ HANDLE *TokenOut)
{
HANDLE processHandle = NULL;
HANDLE token = NULL;
HANDLE primaryToken = NULL;
if (TokenOut == NULL || ProcessId == 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*TokenOut = NULL;
processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, ProcessId);
if (processHandle == NULL)
{
return FALSE;
}
if (!OpenProcessToken(processHandle,
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID,
&token))
{
DWORD err = GetLastError();
CloseHandle(processHandle);
SetLastError(err);
return FALSE;
}
if (!DuplicateTokenEx(
token, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID,
NULL, SecurityImpersonation, TokenPrimary, &primaryToken))
{
DWORD err = GetLastError();
CloseHandle(token);
CloseHandle(processHandle);
SetLastError(err);
return FALSE;
}
CloseHandle(token);
CloseHandle(processHandle);
*TokenOut = primaryToken;
return TRUE;
}
static BOOL ControllerInjectionDuplicateWtsUserToken(_In_ DWORD SessionId, _Out_ HANDLE *TokenOut)
{
HANDLE userToken = NULL;
HANDLE primaryToken = NULL;
if (TokenOut == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*TokenOut = NULL;
if (SessionId == 0 || SessionId == 0xFFFFFFFFu)
{
SetLastError(ERROR_NO_TOKEN);
return FALSE;
}
if (!WTSQueryUserToken(SessionId, &userToken))
{
return FALSE;
}
if (!DuplicateTokenEx(userToken,
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID,
NULL, SecurityImpersonation, TokenPrimary, &primaryToken))
{
DWORD err = GetLastError();
CloseHandle(userToken);
SetLastError(err);
return FALSE;
}
CloseHandle(userToken);
*TokenOut = primaryToken;
return TRUE;
}
BOOL ControllerInjectionAcquireActiveInteractiveUserToken(_Out_ HANDLE *TokenOut, _Out_opt_ DWORD *SessionIdOut)
{
DWORD consoleSessionId = WTSGetActiveConsoleSessionId();
WTS_SESSION_INFOW *sessions = NULL;
DWORD sessionCount = 0;
DWORD lastErr = ERROR_NO_TOKEN;
if (TokenOut == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*TokenOut = NULL;
if (SessionIdOut != NULL)
{
*SessionIdOut = 0;
}
if (consoleSessionId != 0 && consoleSessionId != 0xFFFFFFFFu)
{
if (ControllerInjectionDuplicateWtsUserToken(consoleSessionId, TokenOut))
{
if (SessionIdOut != NULL)
{
*SessionIdOut = consoleSessionId;
}
return TRUE;
}
lastErr = GetLastError();
}
if (!WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &sessionCount))
{
DWORD err = GetLastError();
SetLastError(err == ERROR_SUCCESS ? lastErr : err);
return FALSE;
}
for (DWORD i = 0; i < sessionCount; ++i)
{
DWORD sessionId = sessions[i].SessionId;
if (sessions[i].State != WTSActive || sessionId == 0 || sessionId == consoleSessionId)
{
continue;
}
if (ControllerInjectionDuplicateWtsUserToken(sessionId, TokenOut))
{
if (SessionIdOut != NULL)
{
*SessionIdOut = sessionId;
}
WTSFreeMemory(sessions);
return TRUE;
}
lastErr = GetLastError();
}
WTSFreeMemory(sessions);
SetLastError(lastErr == ERROR_SUCCESS ? ERROR_NO_TOKEN : lastErr);
return FALSE;
}
static DWORD ControllerInjectionIntegrityRid(_In_ UINT32 IntegrityLevel)
{
switch (IntegrityLevel)
{
case BK_LAUNCH_INTEGRITY_UNTRUSTED:
return SECURITY_MANDATORY_UNTRUSTED_RID;
case BK_LAUNCH_INTEGRITY_LOW:
return SECURITY_MANDATORY_LOW_RID;
case BK_LAUNCH_INTEGRITY_MEDIUM:
return SECURITY_MANDATORY_MEDIUM_RID;
case BK_LAUNCH_INTEGRITY_HIGH:
return SECURITY_MANDATORY_HIGH_RID;
case BK_LAUNCH_INTEGRITY_SYSTEM:
return SECURITY_MANDATORY_SYSTEM_RID;
default:
return 0;
}
}
BOOL ControllerInjectionApplyRequestedIntegrity(_In_ HANDLE TokenHandle, _In_ UINT32 IntegrityLevel)
{
SID_IDENTIFIER_AUTHORITY authority = SECURITY_MANDATORY_LABEL_AUTHORITY;
PSID integritySid = NULL;
TOKEN_MANDATORY_LABEL label;
DWORD integrityRid = ControllerInjectionIntegrityRid(IntegrityLevel);
BOOL success;
if (IntegrityLevel == BK_LAUNCH_INTEGRITY_DEFAULT)
{
return TRUE;
}
if (TokenHandle == NULL || TokenHandle == INVALID_HANDLE_VALUE || integrityRid == 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!AllocateAndInitializeSid(&authority, 1, integrityRid, 0, 0, 0, 0, 0, 0, 0, &integritySid))
{
return FALSE;
}
ZeroMemory(&label, sizeof(label));
label.Label.Attributes = SE_GROUP_INTEGRITY;
label.Label.Sid = integritySid;
success = SetTokenInformation(TokenHandle, TokenIntegrityLevel, &label, sizeof(label) + GetLengthSid(integritySid));
if (!success)
{
DWORD err = GetLastError();
FreeSid(integritySid);
SetLastError(err);
return FALSE;
}
FreeSid(integritySid);
return TRUE;
}
BOOL ControllerInjectionEnablePrivilege(_In_z_ PCWSTR PrivilegeName)
{
HANDLE token = NULL;
TOKEN_PRIVILEGES privileges;
LUID luid;
DWORD err;
if (PrivilegeName == NULL || PrivilegeName[0] == L'\0')
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
{
return FALSE;
}
if (!LookupPrivilegeValueW(NULL, PrivilegeName, &luid))
{
err = GetLastError();
CloseHandle(token);
SetLastError(err);
return FALSE;
}
ZeroMemory(&privileges, sizeof(privileges));
privileges.PrivilegeCount = 1;
privileges.Privileges[0].Luid = luid;
privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, FALSE, &privileges, sizeof(privileges), NULL, NULL))
{
err = GetLastError();
CloseHandle(token);
SetLastError(err);
return FALSE;
}
err = GetLastError();
CloseHandle(token);
if (err == ERROR_NOT_ALL_ASSIGNED)
{
SetLastError(err);
return FALSE;
}
SetLastError(ERROR_SUCCESS);
return TRUE;
}
BOOL ControllerInjectionQueryPipeClientSession(_In_ HANDLE PipeHandle, _Out_opt_ DWORD *ClientProcessIdOut,
_Out_ DWORD *SessionIdOut)
{
DWORD clientPid = 0;
DWORD sessionId = 0;
if (SessionIdOut == NULL || PipeHandle == NULL || PipeHandle == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
*SessionIdOut = 0;
if (ClientProcessIdOut != NULL)
{
*ClientProcessIdOut = 0;
}
if (!GetNamedPipeClientSessionId(PipeHandle, &sessionId))
{
return FALSE;
}
if (ClientProcessIdOut != NULL)
{
if (GetNamedPipeClientProcessId(PipeHandle, &clientPid))
{
*ClientProcessIdOut = clientPid;
}
}
*SessionIdOut = sessionId;
return TRUE;
}
static BOOL ControllerInjectionQueryTokenSession(_In_ HANDLE TokenHandle, _Out_ DWORD *SessionIdOut)
{
DWORD sessionId = 0;
DWORD bytesReturned = 0;
if (TokenHandle == NULL || TokenHandle == INVALID_HANDLE_VALUE || SessionIdOut == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!GetTokenInformation(TokenHandle, TokenSessionId, &sessionId, sizeof(sessionId), &bytesReturned))
{
return FALSE;
}
*SessionIdOut = sessionId;
return TRUE;
}
BOOL ControllerInjectionEnsureTokenSession(_In_ HANDLE TokenHandle, _In_ DWORD DesiredSessionId,
_Out_opt_ DWORD *OriginalSessionIdOut, _Out_opt_ DWORD *TokenSessionIdOut)
{
DWORD tokenSessionId = 0;
if (OriginalSessionIdOut != NULL)
{
*OriginalSessionIdOut = 0;
}
if (TokenSessionIdOut != NULL)
{
*TokenSessionIdOut = 0;
}
if (!ControllerInjectionQueryTokenSession(TokenHandle, &tokenSessionId))
{
return FALSE;
}
if (OriginalSessionIdOut != NULL)
{
*OriginalSessionIdOut = tokenSessionId;
}
if (tokenSessionId != DesiredSessionId)
{
DWORD desired = DesiredSessionId;
if (!SetTokenInformation(TokenHandle, TokenSessionId, &desired, sizeof(desired)))
{
return FALSE;
}
tokenSessionId = desired;
}
if (TokenSessionIdOut != NULL)
{
*TokenSessionIdOut = tokenSessionId;
}
return TRUE;
}