4

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).

Darkslide
  • 43
  • 2

2 Answers2

2

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...

Tony Hopkinson
  • 20,172
  • 3
  • 31
  • 39
  • I really like that idea to just schedule it to run every minute, but it seems that you can't schedule an interactive task to just run for every user - you always have to give an explicit username. So I guess I'm back to my polling service... :/ Still, thanks for your input! – Darkslide Jan 04 '12 at 19:29
  • Cheat, get the app itself to set up it's own watchdog schedule task. – Tony Hopkinson Jan 04 '12 at 22:05
1

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.

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • 1
    Thanks, this is a really thorough answer. In the meantime I've found something to do what your first paragraph suggests at http://www.codeproject.com/KB/vista-security/SubvertingVistaUAC.aspx and it works great. I'll keep the security implications in mind, but those other options sound really complicated and I'm already over budget. If my application has to run elevated anyway, does it really matter from a security standpoint if it's a normal user or LocalSystem? – Darkslide Jan 05 '12 at 01:06
  • If the user is able to elevate anyway, then a local elevation of privilege vulnerability probably isn't a major issue. (On the other hand, that means they will still be able to kill the process if they want to, they'll just have to elevate first.) – Harry Johnston Jan 05 '12 at 02:24