Blocking mouse input from a service in Vista - winapi

I maintain a variety of managed userlabs on a university campus. These machines all currently run Windows XP and we have a windows service that is used to "lock" a machine by blocking any keyboard or mouse input. The locking happens during our scripted OS installation so that users aren't able to accidentally halt or break the process. It is also used to prevent users from logging into machines until they are checked out at the front desk of a given lab. Ctrl+Alt+Del is blocked via a keyboard filter driver and the rest of the keys and mouse are currently blocked using the BlockInput() function from user32.dll.
In XP, the service runs as Local System and the checkbox for "Allow service to interact with desktop" must be enabled from the BlockInput() call to succeed. Under Vista, this no longer works I'm guessing because of the Session 0 isolation changes. The call succeeds, but input is not actually blocked.
The keyboard filter driver still works just fine and we can use that to block the whole keyboard instead of just Ctrl+Alt+Del. But I'm at a loss as to how we're going to block the mouse now. I'm not even entirely sure the Session 0 isolation is to blame.
Can anyone recommend a fix or a workaround to allow us to block mouse input from a service in Vista and beyond? I've looked for alternative win32 API's without luck. Assuming Session 0 isolation is to blame, is there a legitimate way to call the function from Session 1 or would that sort of defeat the purpose of the isolation? Will I have to rely on an elevated companion exe that runs on user login and communicates with the service?

From a service, you can use WTSEnumerateSessions to get all logged on user sessions, WTSQueryUserToken to get the logged on user's token, and then use CreateProcessAsUser with that token to get code running on the user's desktop. This has the disadvantage that the code will run as the logged on user. Since all input is disabled, this is probably safe enough and is at least as safe as the existing XP solution.]
EDIT: BlockInput requires a high mandatory integrity level. You could try adding this group to the token, but then you have code with higher privileges running on the desktop and potentially open to attacks.
An alternative might be to use your service just to disable all HID class devices on the machine.

Related

Are Windows-GUI calls (creating visible windows, etc.) allowed in a Windows-Service?

First off, I know some proper ways of making a truly interactive Windows Service.
The situation is, I do have a tool that does not interact with the user as such. However, it does display non-blocking notifications both via popup windows and via the Windows Notification Area (aka System Tray). It also writes a logfile of the notifications it displays.
This tool is normally spawned by a main user application and as long as the main application is a normal application, these notifications do work as intended.
When this tool is spawned by a Windows Service, no notifications are displayed, naturally. (The Desktop Session for the service isn't visible.) But this would be OK, we have the logfile and these notifications are just - notifications, nothing the user absolutely must see under all circumstances.
The question now becomes: Is a process running in the context of a Service (the Service itself or any process it starts) "allowed" to make Windows API calls that display a visible GUI?
Will most Windows API calls (e.g. creating and showing a window, using Shell_NotifyIcon, etc.) behave the same in the invisible session of the service?
Or would I have to make sure throughout the source code, that no GUI displaying/modifying stuff is called in the context of the service?
And yes, calling ::MessageBox is a bad idea because it will block. But I can handle these calls.
And yes, this could be designed better, but it's what I have at the moment and it would be nice if I hadn't to rip the whole tool apart to make sure no GUI related code is run in the service.
GUI elements from a Windows Service are shown on Session 0. On Windows XP & 2003, users were allowed to log in to Session 0 and interact normally with the windows created by a service, but Microsoft put a knife in the heart of interactive services in Vista (and beyond) by isolating Session 0.
So, to answer your specific questions:
Is a process running in the context of a Service (the Service itself
or any process it starts) "allowed" to make Windows API calls that
display a visible GUI?
Will most Windows API calls (e.g. creating and showing a window, using Shell_NotifyIcon, etc.) behave the same in the invisible session
of the service?
Yes, GUI calls are allowed and should succeed as normal. The only notable exceptions that I know of are those related to tray icons because the process providing the task bar (explorer.exe) is not running in the isolated Session 0.
Or would I have to make sure throughout the source code, that no GUI displaying/modifying stuff is called in the context of the service?
That should not be necessary, though you should proceed cautiously with any GUI interaction from your service. Test thoroughly!
I would like to provide some info wrt. Raymonds Chen's comment to the other answer
You should avoid presenting UI in a service because you may trigger
the UI Detection Service which will switch the user to your service UI
temporarily. – Raymond Chen
I find these good articles:
What is Interactive Services Detection and Why is it Blinking at Me?
Inside Session 0 Isolation and the UI Detection Service, Part1, Part2
Where one can find explanation on what the UI detection service (UI0Detect) is and does and how it's supposed to work.
Interactive Services Detection (the blinking button on the taskbar) is
a mitigation for legacy applications that detects if a service is
trying to interact with the desktop. This is handled by the
Interactive Services Detection (UI0Detect) service.
However, one must note that this only can work if the service that is trying to view a GUI has the flag "Allow service to interact with desktop" set, because only then the service process will be running on WinSta0of Session0 even allowing it to show anything at all.
Alex Ionescu mentions this:
If UI0Detect.exe ...
the SCM has started it at the request of the Window Hook DLL. The
service will proceed ...
The service first does some
validation to make sure it’s running on the correct WinSta0\Default
windowstation and desktop and then notifies the SCM of success or
failure.
So, to come back to Raymond's comment: As far as I can see, as long as a service doesn't tick the type= interact option (see sc.exe), and normally you don't tick this, the UI0Detect service doesn't do anything and there shouldn't be any "danger" of triggering it.
Note: The information above is based on my limited research and tests on only a single Windows 7 PC.

Preventing cross-process SendMessage Calls

Say I have a Windows GUI applications with a buttons on it. I am able to simulate a click on that button by using sendMessage winapi calls with BM_CLICK as the parameter to the call.
Now, from a security perspective, I do not want this to happen. i.e. my target process should ignore sendMessage calls from another process. Is there a provision to do this at all ? A way to authenticate the sendMessage calls ?
EDIT: In other words, how can I prevent applications such as Enabler, TurnitOn http://www.raymond.cc/blog/how-to-enable-and-access-disabled-grayed-out-buttons-windows-and-checkboxes/ from accessing functionality that is not meant to be accessed by the user ?
If the application is running in the user's own context, then it can only do what the user can do. The corollary of this, often overlooked, is that anything that the application can do, the user can do.
So there's not really any point in worrying too much about whether a button on such an application is "really" disabled or not. The user can always find another way to do whatever the button was going to do anyway. (This might be by using a registry editor, obtaining another application with the same functionality, or, if nothing else is convenient, they can run the application inside a debugger and force it to re-enable the button.)
The appropriate solution depends on the context:
In many cases, the most appropriate solution is to stop worrying about it. You should be able to trust your users, and if you can't, that's an HR problem, not a technical problem.
If the application is providing an interface to something running in a higher context, such as, for example, the front end for anti-virus software, then the security decisions (is the user allowed to do this?) should be happening at the back end. That is, the security decisions need to be taken by code that isn't in the user's control.
If you're a system administrator trying to lock down a kiosk machine - a machine that is going to be used by untrusted users, typically using a single guest account of some sort - then you use AppLocker or Software Restriction Policy to define which applications the user is allowed to run. Since Enabler and TurnItOn won't be on your list, the user won't be able to run them to bypass your security policy.

How can I autostart a UI-application under windows that a non-admin user cannot close?

I have developed a C# Windows Forms application that runs in the background as a systray icon and does some stuff when it's clicked. It is supposed to launch when Windows starts and run continously, and a normal user without administrator rights shall not be allowed to shut it down.
What is the best way to do this? I initially intended to run it on the LocalSystem account through Task Scheduler, but then I learned (the hard way) about Session 0 isolation (i.e. the application will run but its UI elements do not show). When I run it with the logged in user, even if it runs elevated, the user can still shut it down through task manager (without requiring elevation).
Is there any way to give a process from LocalSystem access to the UI? I have a winlogon and a csrss process from LocalSystem running in session 1, so I guess it can be done, I just don't know how. Or is there maybe an easier way to disallow users to shut down a process of their own through the task manager? The only other option I can think of is to create an extra Windows Service that keeps polling if the app is running, and immediately launches it again if someone kills it - but that seems incredibly clumsy (also, I want it to stay dead when it crashed by itself, to avoid a single bug causing infinite loops of process creation).
Deponds on why they can't shut it down.
The natural way to go would to have created a service, started by a high priv account, and then had the desktop app just show what it was doing.
If there's something that they should see, but don't becasue they aren't running the service monitor app. (and acknowledge message back to the service), send them an email, send their boss an email, send yourself one and then go shout at them.....
Be a lot easier than trying to get the lid back on this tin of worms.
A nice way to make sure the desktop app is ruuning, would be simply to schedule it to run every X, but drop out immediately if it already is or the somethingwenthorriblywrong flkag is set.
Not worth writing a service to check if it's still there, as they could kill that as well, unless you want to make that a service they can't kill. :(
You are trying to be too draconian with this. Add some sort of auditing so you can see it dies or was shutdown, monitor that and deal with any adverse reports. It's a heck of a lot easier, and gives manage something to do...
You can run an administrative process in the user's logon session. One method would be to for a master process (a system service) to duplicate its own token, use SetTokenInformation to change the session associated with the token, and then call CreateProcessAsUser. The lpStartupInfo parameter can be used to associate the process with a particular window station and desktop. It may be necessary to explicitly change the permissions on the window station and desktop first.
HOWEVER, this is a bad idea from a security standpoint, because GUI applications are vulnerable to malicious messages sent from other processes on the same desktop ("shatter attacks").
It would be safer to run the process in the user's own context but apply an ACL to it. This can be done using the lpProcessAttributes parameter to CreateProcess or CreateProcessAsUser, or with the SetSecurityInfo function. I've never tried this, but it should in theory prevent the user from using task manager to close the process.
If you are creating the process from the user's context, then the user will be the owner, so a sufficiently knowledgeable person could change the permissions back in order to terminate the process. If you need to block this hole, using CreateProcessAsUser from a privileged master process (the token can be duplicated from one of the existing processes in the user's session) should (again, in theory) mean that the user is not the process owner.
Another potential issue: if you listen for messages indicating that the user is logging out (in order to exit) such a message could be faked. If you don't then you need to find some other way of exiting when the user logs out. You may need to experiment here, I'm not sure how the system will react.

Starting an Application from Windows Service

I am building a Windows service that will watch for specific occurrences of events and disk activity. When such an event occurs my plan is to alert the user to the event via a client app, and provide remediation if necessary. I have (mostly) completed both the client and service components, which work great... unless the client app isn't running.
In short, I am looking for a way to start up the client app from the Windows service via CreateProcess to provide information to the user. However, it appears the service can't even see the file/folder of the client app to execute it. I suspect this is due to the credentials under which the service is running, or maybe due to service level restrictions, but wanted to reach out for some advise before I get into this any deeper.
So, the obvious question first... am I thinking about this clearly? Is the architecture plan sound, or should I look at another method? I would prefer not to re-do any of the work I have already completed, but obviously want to make sure the plan and process is solid.
Question #2, what are the limitations I face with this model? Is there a service account that will allow this level of access?
I am obviously struggling with this right now, so any thoughts or assistance will be greatly appreciated!
Thanks,
Kris
As others have mentioned already, you can't (easily) launch an application directly from the service, so I think the easiest way around the problem is to create a process that starts on login and runs with the credentials of the logged in user, eg an app that sits in the system tray, and it opens up a named pipe or a network port to the service. If the service needs to alert the user, it sends a message down that channel and then the client process can either show its own UI or launch an application. Interprocess communication using pipes or ports are the simplest way to deal with the restrictions on session 0 processes.
A Windows service does not have access to the user session in Vista and above, so it is blocked from starting an executable on that session. You can download a white paper from Microsoft that goes into detail: Impact of Session 0 Isolation on Services and Drivers in Windows.
Since Vista, services run in session 0 and the user's desktop is always in a different session. Thus you need to work hard to start a service on the user's desktop.
It can be done but it is pretty tricky. Details can be found here: http://blogs.msdn.com/b/winsdk/archive/2009/07/14/launching-an-interactive-process-from-windows-service-in-windows-vista-and-later.aspx?wa=wsignin1.0

How can I enumerate the open windows (~EnumWindows) of another user session

I have an application that can list the opened windows of the current session. It uses the EnumWindows method from the user32.dll.
I would like to run this code from a windows service, but as the service is not attached to a user session, it returns nothing obviously.
So the question is, how can I enumerate the open windows of another user session (e.g. with a specific logon user)?
Similarly to EnumWindows, I also would like to get the foreground window of the user session as well (like GetForegroundWindow works for the current user).
As far as I'm aware, you can't access the windows of one session from another. It's also worth noting that there's not really any such thing as "the current session" - there may be multiple users logged on through terminal services, or XP's fast user switching.
One approach to this would be to add a program to each user's profile with no UI that just communicates with your service. You'd still have to cope with the fact that there could be multiple active sessions, though.
According to this document you can create a process in an other user's logon session using CreateProcessAsUser, and could enumerate the windows there. You will still need some IPC mechanism to communicate with the service.
The accepted answer is not correct.
So the question is, how can I enumerate the open windows of another user session?
You can enumerate the open windows of any session if you're running as a service running as the local System account.
To do this first enumerate the sessions with WTSEnumerateSessions. Then enumerate the window stations inside each session with EnumWindowStations. Then enumerate the desktops for each Window Station with EnumDesktops. Finally you an enumerate the Windows in those Desktops with EnumWindows.
(e.g. with a specific logon user)
There can be many concurrent logged on users via Terminal services or fast user switching.
Similarly to EnumWindows, I also would like to get the foreground window of the user session as well (like GetForegroundWindow works for the current user).
This can be done by launching an app with a found user token in the Session, Window Station, and Desktop. From there you can call any Win32 API like GetForegroundWindow and report the info back to your parent process.
You can learn more about how Sessions, Window Stations, and Desktops work here.

Resources