I'm working on a parental control app (written in WPF) and would like to disallow anybody (including administrator) to kill my process. A while back, I found the following code online and it almost works perfectly, except that it doesn't work sometimes.
static void SetAcl()
{
var sd = new RawSecurityDescriptor(ControlFlags.None, new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), null, null, new RawAcl(2, 0));
sd.SetFlags(ControlFlags.DiscretionaryAclPresent | ControlFlags.DiscretionaryAclDefaulted);
var rawSd = new byte[sd.BinaryLength];
sd.GetBinaryForm(rawSd, 0);
if (!Win32.SetKernelObjectSecurity(Process.GetCurrentProcess().Handle, SecurityInfos.DiscretionaryAcl, rawSd))
throw new Win32Exception();
}
In Win7, if the app is started by the logged in user, even the admin cannot kill the process (access denied). However, if you switch to another user account (admin or standard user), then check "Show processes for all users", then you kill the process without a problem. Can anybody give me a hint why and how to fix it?
EDIT:
I understand some people are upset by this question, but here is my dilemma. This is a parental control I wrote primarily for my own use. The main feature is that I want to monitor and limit my kids' on games (not simply turn off all games). I could assign kids a standard user account and they cannot kill the process. However, some games (e.g. Mabinogi) require admin right to be playable. So, I had to type in my admin password each time, which is annoying.
By the way, I'm not sure if it's against Stackoverflow's policy, here is my app if you'd like to check it out: https://sites.google.com/site/goppieinc/pc-screen-watcher.
EDIT:
My main point of this post is to ask if somebody could give me a hint why the posted code doesn't always work - e.g. in case you show processes for all users.
Make it so that the WPF side is just a client. The "server" in this case must be a Windows Service. Then set the Service to start automatically (this last part requires admin privileges). Bonus if it runs as a network admin.
If the service's process is killed, Windows starts it again immediately. And then no matter what users try, they can't really stop your program's logic unless they have admin powers and stop the service themselves. Use the WPF GUI just for configuration.
Some of the comments are right, you're playing a game that might very well be doomed to have no end. However, from what I can tell, setting your process as a critical kernel process appears to give you the clear victory. Any attempt to kill the process will simply BSOD your computer. Code is:
The idea here is that you call the
Protect()
method ASAP, and then callUnprotect()
when you're doing a voluntary shutdown of the app.For a WPF app, you're going to want to hook the
SessionEnding
event, and this is where you'll call theUnprotect()
method, in case someone logs off or shuts down the computer. This absolutely must be theSessionEnding
event, and not theSystemEvents.SessionEnded
event. Very often by the time theSystemEvents.SessionEnded
event is called, your application can be force terminated if you're taking too long to release the protection, leading to a BSOD every time you restart or log off. If you use theSessionEnding
event, you avoid this problem. Another interesting fact about that event is that you're able to, to some degree, contest the logoff or shutdown. Also you'll obviously want to callUnprotect()
inside theApplication.Exit
event handler.Ensure that your application is stable before deploying this mechanism, because a crash would also BSOD your computer if the process is protected.
As a note for all of the people attacking you for taking these measures, please ignore them. It doesn't matter if someone could potentially use this code to do something malicious, that's a poor excuse to stop perfectly legitimate research for a perfectly legitimate cause. In my case I have developed this as part of my own application, because adults (administrators) don't want to be able to stop my process by killing it. They explicitly desire this functionality, because it prevents themselves from being able to bypass what the software was designed to do.
The system account is higher (at least in case of OS) than administrator. The system account and admin account have the same file privileges, but they have different functions. The system account is used by the operating system and by services that run under Windows. There are many services and processes within Windows that need the capability to log on internally (for example during a Windows installation). The system account was designed for that purpose; it is an internal account, does not show up in User Manager, cannot be added to any groups, and cannot have user rights assigned to it.
So the challenge is how to elevate your application privilege to system account while on course of installation. I am not sure how to elevate your process. But worth reading following post ref 1, ref 2. In addition, even if we assume you managed to get it to system account, you might still face more challenge when it comes to managing your own application even being an exponentially super user.