I have read tons of SO questions on this matter, but I didn't find a real definitive guide for doing this the right way.
My goal is to enumerate [disconnected and active] user console sessions and start a process in each one of them. Every user session process requires at least these rights in its DACL :
TOKEN_QUERY
(for GetTokenInformation())TOKEN_QUERY_SOURCE
(for GetTokenInformation())
PROCESS_QUERY_INFORMATION
(for OpenProcessToken())PROCESS_QUERY_INFORMATION | PROCESS_VM_READ
(for GetModuleFileNameEx())PROCESS_VM_OPERATION
(used with GetTokenInformation() to get other processes' username later with LookupAccountSid())
But as you can read here (at the bottom) : "Windows Vista introduces protected processes to enhance support for Digital Rights Management. The system restricts access to protected processes and the threads of protected processes."
So I thought maybe only with PROCESS_QUERY_LIMITED_INFORMATION
I can get some information about other processes. I tried QueryFullProcessImageName() for elevated processes starting from Vista (see Giori's answer) but it doesn't work anymore as it seems.
Solution : CreateProcessAs_LOCAL_SYSTEM using a duplicated token of the Windows service.
Problem : The spawned processes should have the respective logged on user's environment variables set to be able to locate network printers and mapped drives among other things. But if I use the service's token I inherit its PEB and I can't even translate the mapped drives to their UNC paths.
So I started looking for ways to "elevate" the process and bypassing the UAC prompt, I tried :
- Enabling some privileges like
SE_DEBUG_PRIVILEGE
in the token using AdjustTokenPrivileges() (does not work if the token does not have those privileges, verification can be done first using LookUpPrivilegeValue()) - using the token from
winlogon.exe.
(does not work) - Changing the DACL (source code) (didn't work)
The steps I'm following are :
- Enumerate sessions using WTSEnumerateSessions()
- Get the token (two choices) :
- SYSTEM token : OpenProcessToken(GetCurrentProcess(),TokenAccessLevels.MaximumAllowed, out hProcessToken)
- User token : WTSQueryUserToken(sessionId, out hUserToken)
- Duplicate the token using DuplicateTokenEx()
- LookUpPrivilegeValue() / AdjustTokenPrivileges() (useless ?)
- CreateEnvironmentBlock()
- CreateProccessAsUser(), flags :
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT
, Startup info's desktop :"WinSta0\Default"
- Change process DACL (see link above, useless ?)
- Dispose/Clean : destroy PEB created, close opened handles and free memory.
My question : how to grant the process created using CreateProccessAsUser() from a Windows Service running under LOCAL_SYSTEM
account enough privileges/rights to get information on other processes (from other sessions; of other users and different integrity levels) without losing the user's environment variables ?