from: http://blog.163.com/chmail@yeah/blog/static/63739109201011177484668/http://rohna.w.blog.163.com/blog/static/1457416520115195531957/
Windows Vista has made great changes to Fast User Switching, user account permissions, and the session space that the service program runs so that some of the previously available programs are no longer working properly, and we have to make some improvements to keep up with Vista. Our software has a system service installed in the Windows Nt/2000/xp/vista system that is responsible for starting our main program with system privileges. After our main program is started, we will add an icon to the system tray and click this icon to eject the Control menu, which can also activate the dialog box for configuring the program preferences. Our programs can work correctly under Windows nt/2000/xp. Oh no, our problem has arisen when XP has a fast User Switching capability. After XP starts we log in as user A, our icon appears in the system tray, all work is normal, but when we use Fast User Switching, switch to User B (user A is also logged in at this time, and does not log off), although User B is already a local console session (the Sessions property is console) But our icons are no longer available, and the Natural menu and dialog boxes are much more impossible to talk about. Our program is related to the local console desktop, this situation is undoubtedly a flaw. Let's take a look at the Vista platform. The system starts to log in as User A, our icons do not appear, view the process list in the Process manager found that our program has been started, when we check our services from the far end, and find that we have been working properly, and try to telnet our services, Vista A message box pops up on the local console, prompting for an interactive service message, whether to view the message or not, click immediately to view the discovery and switch to another desktop. So we began to analyze the cause of this situation. In Windows nt/2000, users of the system service process and the native console interactive logon are running in Session0, and the default user desktop is running at the WinSta0 window station, so our program is still in the same session as the native user when the service program starts. Even if there are situations where a dialog box cannot be popped or the system tray icon cannot be added, only the process desktop can be modified to Winsta0\default (refer to MSDN openinputdesktop, SetThreadDesktop , and so on, as described in API). XP brings us Fast User Switching, and it also lets us use the software architecture issues that emerge. When we quickly switch to User B, user A is still in session (SESSION0) while User B is in a newly initiated session (Session1 or other), at which point the serviceProgram and native console program is not in the same session, Openinputdesktop,setthreaddesktop, such as the scope of the work of the API is limited to the sessions, user A did not quit, Session0 still exist but is Disconnected state, when the session is in the disconnected state, calling Openinputdesktop returns the wrong "invalid API". The sessions to which processes and threads belong are determined by the Tokensessionid in their TOKEN structure (see Settokeninformation and Token_information_class Descriptions in MSDN). I try to modify the Tokensessionid information of the running processes and threads to the purpose of modifying the desktop environment with the relevant API provided by Microsoft, so far it has not been successful (perhaps we can try to refer to the rootkit technology, but even if the modification succeeds in the end, we are not sure whether our requirements will be met) Our process is not able to cross the bounds of the session, and naturally cannot interact with the desktop of the current active,l . What's the picture in Vista? In terms of security and other considerations, Vista and all the service programs in the Session0, and for the first interactive login for the user to create a Session1, fast switch to User B is Session2, whether it is the user of the local login, fast switch after the user, or Remote Desktop logon users no longer have the service process in the same session, our program is also running in the Session0, natural our tray icon is no user can see. In fact, this icon can still appear. Session0 because it is not an interactive session so it does not start the Explorer program the same way that other user environments initialize, but we can start it by hand and start the explorer in Session0 After the taskbar appears we still see our icon (the specific launch of the Explorer method we do not discuss in this article), menu, dialog box can also be used. Since our program must be running in Session0 and we have no way to put our icons, dialogs in a flash to the next door session of the user desktop up, can only think of other ways. Microsoft also does not advocate us this kind of service program directly provides the GUI and the user to interact directly the way, but they proposed uses the C/s structure, the client/server uses the SOCKET/PIPE/RPC and so on the communication, so we only then the Client entireThe process is placed in the user session to interact with the user, and then the configuration information and other content through the above channels to the server, the service side in making the corresponding response can be. The separation of the GUI is not so difficult, and then in the previous direct call to the place with a communication through the pipe interface, so that the GUI (Client) can be flexible to run the control. Initially I wanted to put the user interface program into startup and start automatically with the user login. That way, when both users A and B are logged in, there will be two user interface programs running, and our service is only interacting with the currently active console logged-on user, so this does not meet the requirements. Next we need to see how to determine which session is currently active, and then how to start our user interface program in this active session. Microsoft has provided us with a set of API for Windows Terminal Service from xp/2003, which starts with WTS (please install MSDN2005 to check the instructions), and there are more than one way to get an active session. The simplest thing is to use it directly.DWORDWtsgetactiveconsolesessionid (void);To get the active session Id. To use these APIs in your program requires the latest platform SDK (if you are using Visual Studio 2005 then it already has the relevant header files and library files that can be used directly) if you are using VC + + 6.0 You have no or no intention of installing the latest SDK then you can use LoadLibrary () to load wtsapi32.dll and then use GetProcAddress () to get the address of the relevant function to call them. We can use the SessionID after we get the activity.BOOLWtsqueryusertoken ( ULONGSessionId, PhandlePhtoken);To get the user token (Token) in the current active session, with this Token, we can create a new process in the active sessions.BOOLCreateProcessAsUser ( HANDLEHtoken, LPCTSTRLpapplicationname, LPTSTRlpCommandLine, lpsecurity_attributesLpprocessattributes, lpsecurity_attributesLpthreadattributes, BOOLbInheritHandles, DWORDdwCreationFlags, lpvoidLpenvironment, LPCTSTRLpcurrentdirectory, LpstartupinfoLpstartupinfo, lpprocess_informationLpprocessinformation);Take the token we obtained as the first parameter of this API, you can try running a Notepad.exe to see how. You can see the new process on the console desktop. Then look at the list of processes that the user name of the process is the user who is logged on by the current console. But here we have a problem, we need to collect some information about the current computer-logged user, and some operations require high privileges to complete, and Vista even the Administraotrs user group members by default to start the process with users permissions, So the new process we created has only users permission, and we can't do anything, and of course we can use the UI provided by Vista to ask the user to elevate to admin rights, but some operations even the admin token can not complete, and require the user to confirm that the usability is greatly compromised, So I decided to start our user interaction in the active session with system privileges. Obviously Wtsqueryusertoken () is a bad idea. Before, we mentioned that the session that the process belongs to is determined by the Tokensessionid in the process token, so we can copy the token of the service process and then modify the Tokensessionid. To create a new process with system permissions on the user's desktop. The answer is yes. This is the code to implement this operation, in order to reduce the length I removed the exception handling code
HANDLE htokenthis = NULL; HANDLE htokendup = NULL; HANDLE hthisprocess = getcurrentprocess (); OpenProcessToken (hthisprocess, token_all_access, & Htokenthis); Duplicatetokenex (htokenthis, maximum_allowed, NULL, Securityidentification, Tokenprimary, & HTokenDup); DWORD Dwsessionid = Wtsgetactiveconsolesessionid (); Settokeninformation (Htokendup, Tokensessionid, & Dwsessionid, sizeof (DWORD)); Startupinfo si; process_information Pi; ZeroMemory (& si, sizeof (startupinfo)); ZeroMemory (& Pi, sizeof (process_information)); Si. CB = sizeof (STARTUPINFO); Si. Lpdesktop = "Winsta0\\default"; LPVOID penv = NULL; DWORD dwcreationflag = normal_priority_class | create_new_console; Createenvironmentblock (& penv, htokendup, FALSE); CreateProcessAsUser ( Htokendup, NULL, ( Char *) "Notepad", NULL , NULL, FALSE, Dwcreationflag, penv, NULL, & Si, & nbsp; & PI); |
Here we have done most of the work, we also need to do is to monitor the activity session changes, is the user's login, logoff, fast switching. The WTS Series API and provides us with these capabilities of the API, roughly can be used in several ways to achieve: 1. Set up a timer, use Wtsgetactiveconsolesessionid () polling the Active Desktop ID, when detected changes to allow users to pay The previous instance of the interop program exits and creates a new process in the new active session. 2. Use the WTSRegisterSessionNotification () function to register a window to receive wtssession_notification messages to determine the session change. 3. Use Wtsenumeratesessions to enumerate all sessions and then judge the session status based on the State member in the returned Wts_session_info structure, and find the session in the active state. Choose one of these with your other requirements and then respond to it. This article is simply a simple description of the problems I encountered when I moved to Windows Vista and my solution, omissions and fallacies. Please advise the reader, you have a good idea and realization also please enlighten me.