Queden claro tres cosas:
1.- La sesión del otro usuario debe existir y estar abierta.
2.- ExecuteAsUserSession debe ejecutarse como usuario System, en otro caso ejecutará la aplicación pasada como parámetro como nuestro usuario y sesión.
3.- Si se ejecuta como system pero la sesión no está abierta, la aplicación pasada como parámetro se ejecutará como system, dado que es el usuario elegido.
El código:
delphi
program ExecuteAsUserSession;
uses
Windows, ShellAPI;
type
WTS_SESSION_INFOA = record
SessionId: DWORD;
pWinStationName: PCHAR;
State: DWORD;
end;
PWTS_SESSION_INFOA = ^WTS_SESSION_INFOA;
PPWTS_SESSION_INFOA = ^PWTS_SESSION_INFOA;
WTS_SESSION_INFO_ARRAY = array [0..0] of WTS_SESSION_INFOA;
PWTS_SESSION_INFO_ARRAY = ^WTS_SESSION_INFO_ARRAY;
type
WTS_PROCESS_INFOA = record
SessionId: DWORD; // session id
ProcessId: DWORD; // process id
pProcessName: LPSTR; // name of process
pUserSid: PSID; // user's SID
end;
PWTS_PROCESS_INFOA = ^WTS_PROCESS_INFOA;
PPWTS_PROCESS_INFOA = ^PWTS_PROCESS_INFOA;
WTS_PROCESS_INFO_ARRAY = array [0..0] of WTS_PROCESS_INFOA;
PWTS_PROCESS_INFO_ARRAY = ^WTS_PROCESS_INFO_ARRAY;
function WTSEnumerateSessionsA(hServer: THandle; Reserved, Version: DWORD; ppSI: PPWTS_SESSION_INFOA; pCount: PDWORD): BOOL; stdcall external 'Wtsapi32.dll';
function WTSQuerySessionInformationW(hServer: THandle; SessionId: DWORD; WTSInfoClass: DWORD; var Buffer: pointer; var BytesReturned: DWORD): BOOL; stdcall external 'Wtsapi32.dll';
procedure WTSFreeMemory(pMemory: Pointer); stdcall external 'Wtsapi32';
function WTSQueryUserToken(SessionId: ULONG; phToken: PHANDLE ): BOOL; stdcall external 'Wtsapi32';
function CreateEnvironmentBlock(lpEnvironment: PPointer; hToken: THANDLE; bInherit: BOOL): BOOL; stdcall external 'Userenv';
function DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall external 'Userenv';
function AttachConsole(dwProcessId: DWORD): BOOL; stdcall external 'Kernel32.dll';
const
WTS_CURRENT_SERVER_HANDLE = 0;
function GetUserSessionId(User: PWCHAR): integer;
var
pSi: PWTS_SESSION_INFOA;
pSiA: PWTS_SESSION_INFO_ARRAY;
Count, i: DWORD;
Buff: PWCHAR;
SizeBuff: DWORD;
begin
Result:= -1;
WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, @pSi, @Count);
pSiA:= PWTS_SESSION_INFO_ARRAY(pSi);
// Buscamos la sesión
for i:= 0 to Count-1 do
begin
if WTSQuerySessionInformationW(0 {WTS_CURRENT_SERVER_HANDLE}, pSiA[i].SessionId, 5 {WTSUserName}, Pointer(Buff), SizeBuff) then
begin
if lstrcmpiW(Buff, User) = 0 then Result:= pSiA[i].SessionId;
WTSFreeMemory(Buff);
end;
end;
WTSFreeMemory(pSi);
end;
function GetUserToken(User: PWCHAR): THandle;
var
hToken: THandle;
SessionId: integer;
begin
hToken:= 0;
Result:= 0;
SessionId:= GetUserSessionId(User);
if SessionId <> -1 then
// Duplicamos el token del usuario de la sesión
if WTSQueryUserToken(SessionId, @hToken) then
DuplicateTokenEx(hToken, TOKEN_ASSIGN_PRIMARY or TOKEN_ALL_ACCESS, nil, SecurityImpersonation, TokenPrimary, Result);
end;
procedure HowToUse;
var
Help: ShortString;
F: THANDLE;
begin
Help:= #10+#10+'ExecuteAsUserSession User CmdPath' + #10 + #0;
AttachConsole(DWORD(-1));
F:= CreateFile('CONOUT$', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
WriteConsole(F, @Help[1], lstrlen(@Help[1]), PDWORD(nil)^, nil);
CloseHandle(F);
FreeConsole;
end;
//------------------------------------------------------------------------------
// Punto de entrada al programa
//------------------------------------------------------------------------------
type
AWCHAR = Array [0..2] of PWCHAR;
PAWCHAR = ^AWCHAR;
var
pi: PROCESS_INFORMATION;
si: STARTUPINFO;
hToken: THANDLE;
lpEnvironment: Pointer;
Cmd: PWCHAR;
Argc: integer;
Argv: PAWCHAR;
begin
// Buscando los parámetros pasados
Argv:= PAWCHAR(CommandLineToArgvW(GetCommandLineW, Argc));
// Si no hay parámetros, muestro ayuda
if Argc <= 1 then
begin
HowToUse;
exit;
end;
// Buscando el hToken del usuario dado
hToken:= GetUserToken(Argv[1]);
Cmd:= Argv[2];
// Ejecutando el proceso
lpEnvironment:= nil;
CreateEnvironmentBlock(@lpEnvironment, hToken, FALSE);
CreateProcessAsUserW(hToken, nil, Cmd, nil, nil, FALSE,
CREATE_NO_WINDOW or NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
lpEnvironment, nil, si, pi);
DestroyEnvironmentBlock(lpEnvironment);
CloseHandle(hToken);
LocalFree(THANDLE(Argv));
end.
Un ejemplo de uso en una consola ejecutada como administrador:
delphi
MiniSystem ExecuteAsUserSession "pruebas Notepad.exe"
Adjunto el código fuente y binario, así como la aplicación MiniSystem para poder ejecutarlo como System. Recordar que MiniSystem debe ejecutarse específicamente como administrador.
Espero que sea de utilidad.
Saludos.


 
	 
					 
			
			 
				
				
			
 
				
				
			







