implementation
uses
System.IOUtils,
Winapi.Windows, System.SysUtils;
class function TLocalProcessLauncher.createSessionToken(): THandle;
const
SE_DEBUG_NAME = '
SeDebugPrivilege';
desiredAccess: DWORD =
TOKEN_ADJUST_PRIVILEGES
or
TOKEN_QUERY
or
TOKEN_DUPLICATE
or
TOKEN_ASSIGN_PRIMARY
or
TOKEN_ADJUST_SESSIONID
or
TOKEN_READ
or
TOKEN_WRITE;
var
sessionID: DWORD;
serviceToken: THandle;
userToken: THandle;
tokenPriv: TTokenPrivileges;
luid: TLargeInteger;
//wtf?
begin
sessionID := WTSGetActiveConsoleSessionId();
Win32Check(
OpenProcessToken(
GetCurrentProcess(),
desiredAccess,
serviceToken
)
);
try
Win32Check( LookupPrivilegeValue(
nil, SE_DEBUG_NAME, luid) );
tokenPriv.PrivilegeCount := 1;
tokenPriv.Privileges[0].Luid := luid;
tokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
Win32Check(
DuplicateTokenEx(
serviceToken,
MAXIMUM_ALLOWED,
nil,
WinApi.Windows.SecurityIdentification,
WinApi.Windows.TokenPrimary,
userToken
)
);
Win32Check( SetTokenInformation(userToken, TokenSessionId, @sessionID, SizeOf(sessionID)) );
finally
CloseHandle(serviceToken);
end;
Result := userToken;
end;
class procedure TLocalProcessLauncher.launchProcess(
const absolutePath, arguments:
String);
var
token: THandle;
args: PChar;
startupInfo: TStartupInfo;
processInfo: TProcessInformation;
begin
if arguments.IsEmpty()
then args :=
nil else args := PChar(arguments);
token := createSessionToken();
try
startupInfo :=
Default(TStartupInfo);
startupInfo.cb := SizeOf(TStartupInfo);
startupInfo.lpDesktop := '
winsta0\Default';
Win32Check(
CreateProcessAsUser(
token,
PChar(absolutePath),
args,
nil,
nil,
false,
NORMAL_PRIORITY_CLASS
or CREATE_NEW_CONSOLE,
nil,
nil,
startupInfo,
processInfo
)
);
finally
CloseHandle(token);
end;
end;