Session 0 isolation introduces a problem for Services that need to display UI to the user. Since the Service is now running in a different Session and Desktop, the UI would not be visible to the end user and hence the application would appear to hang. Windows Vista has a temporary mitigation for this. In this article, you will see how Windows Vista notifies you to switch to the Session 0 desktop to respond to interaction from legacy Services.
Determining the Application Session
Follow these steps to determine which session your application runs under.
- Open Task Manager (Click Windows Key + r and type "taskmgr")
- Select the Process tab.
- Go To View Menu, Select Columns
- In the dialog, click the checkbox for "Session ID".
- Focus on the Session IDs for various applications. Notice that Services and applications run under the same session. (earlier version of Windows). Under Windows Vista, the user applications do not run in Session 0, only the services run in Session 0.
Fixing Service interactive (Session) issues with applications on Windows Vista
In pre-windows operating systems services, applications are running in session zero. This mechanism has some security issues. So in order to avoid this Microsoft has implemented a mechanism such that only services and other critical process run in session zero.
A detailed description of Session 0 is given in the article below.
Mitigations for this Issue:
- Right click on the .exe, go to properties. In the properties wizard, in compatibility tab change the compatibility mode then run the application.
- Change the application name as setup.exe name and run the application
- In services.msc right click on the application and go to properties. In logon tab disable the option "Allow services to interact with the desktop".
- Now run the application.
This problem can also be solved using Shims which are available with Application Compatibility Toolkit.
From Compatibility Administrator use the "Session Shim" to fix this issue.
Now, create a package with applying shims on the application and deliver this application as a package. This will fix the issue and help the deployment team to distribute the package at ease.
This mitigation is not the right way of solving this issue. The recommended way of showing UI is CreateProcessAsUser function to create a process in the user's session. When the system detects that a service running in Session 0 is trying to communicate with the user, it displays a dialog similar to the one shown below. The developer can now switch to a desktop in Session 0 to interact with the dialog. Otherwise the service would be waiting for input and appear to hang.
As mentioned above, the recommended way of showing UI is to use the CreateProcessAsUser function to create a process in the user's session.
BOOL CreateProcessAsUser (
The first parameter is a HANDLE to a token and is a primary token that identifies the user. The immediate question before us is "How do i get a token for the user?" Another function LogonUser can be used to obtain the token for a user. However, LogonUser requires that one pass the user id and password in plain text format :) which is certainly not desirable.
How to use logonUser function:
Using LogonUser it creates a new security token and obtains a handle to it.
bool returnValue = LogonUser(
ref tokenHandle); // tokenHandle is a new security token
The OpenProcessToken function can be used to get a handle to the primary token of a process. Use the OpenThreadToken function to get a handle to the impersonation token of a thread.
To obtain a primary token that identifies a user.
- Call OpenProcess with PROCESS_ALL_ACCESS and open a user process. If the call is successful, it returns a handle to the process.
- Use the handle obtained above to make a call to OpenProcessToken and specify TOKEN_ASSIGN_PRIMARY and TOKEN_DUPLICATE as the desired access. If the call is successful, it returns a handle to the process token.
- Use the token handle obtained in step 2 above, and call DuplicateTokenEx function and specify TOKEN_ASSIGN_PRIMARY and TOKEN_ALL_ACCESS as the access rights. Also specify token type as TokenPrimary. If the call succeeds, it returns you a handle to a token which can be used as a primary token.
- Call CreateProcessAsUser function to create an application in the user's session.
Few clarifications on the sequence of operations to be performed.
- Every process that is launched by a user has the user's token associated with the process. This is done so that a particular process can be mapped back to the user who launched it.
- The OpenProcessToken only returns an impersonated token which cannot be used in functions that require a primary token.
- Further to step 2 above, we need to convert the impersonated token into a primary token and thus we use the function DuplicateTokenEx to achieve the same goal.
- Once we convert the impersonated token into a primary token, we can use it in all the functions that need a primary token.
- Once we are done using the token, we have to close it by calling CloseHandle.
CreateProcessAsUser details are extracted from MSDN.