wpf 如何防止应用程序在任务管理器中被杀死?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16968581/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:56:49  来源:igfitidea点击:

How to prevent an app from being killed in task manager?

c#wpfacltaskmanager

提问by newman

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.

我正在开发一个家长控制应用程序(用 WPF 编写),并希望禁止任何人(包括管理员)终止我的进程。不久前,我在网上找到了以下代码,它几乎可以完美运行,只是有时不起作用。

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?

在 Win7 中,如果应用程序是由登录用户启动的,即使是管理员也无法终止该进程(拒绝访问)。但是,如果您切换到另一个用户帐户(管理员或标准用户),然后选中“为所有用户显示进程”,那么您可以毫无问题地终止该进程。任何人都可以给我一个提示为什么以及如何解决它?

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.

编辑:
我知道有些人对这个问题感到不安,但这是我的困境。这是我主要为自己使用而编写的家长控制。主要功能是我想监控和限制我孩子的游戏(而不是简单地关闭所有游戏)。我可以为孩子们分配一个标准的用户帐户,他们不能终止进程。但是,某些游戏(例如 Mabinogi)需要管理员权限才能玩。所以,我每次都必须输入我的管理员密码,这很烦人。

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.

顺便说一句,我不确定这是否违反 Stackoverflow 的政策,如果您想查看,这里是我的应用程序: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.

编辑:
我这篇文章的主要观点是问是否有人可以给我一个提示,为什么发布的代码并不总是有效 - 例如,如果你为所有用户显示进程。

回答by

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:

有些评论是对的,你正在玩一个很可能注定没有结局的游戏。但是,据我所知,将您的进程设置为关键内核进程似乎会给您带来明显的胜利。任何终止进程的尝试只会使您的计算机蓝屏。代码是:

/*
Copyright ? 2017 Jesse Nicholson  
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/


using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace MyRedactedNamespace
{
    /// <summary>
    /// Class responsible for exposing undocumented functionality making the host process unkillable.
    /// </summary>
    public static class ProcessProtection
    {
        [DllImport("ntdll.dll", SetLastError = true)]
        private static extern void RtlSetProcessIsCritical(UInt32 v1, UInt32 v2, UInt32 v3);

        /// <summary>
        /// Flag for maintaining the state of protection.
        /// </summary>
        private static volatile bool s_isProtected = false;

        /// <summary>
        /// For synchronizing our current state.
        /// </summary>
        private static ReaderWriterLockSlim s_isProtectedLock = new ReaderWriterLockSlim();

        /// <summary>
        /// Gets whether or not the host process is currently protected.
        /// </summary>
        public static bool IsProtected
        {
            get
            {
                try
                {
                    s_isProtectedLock.EnterReadLock();

                    return s_isProtected;
                }
                finally
                {
                    s_isProtectedLock.ExitReadLock();
                }
            }
        }

        /// <summary>
        /// If not alreay protected, will make the host process a system-critical process so it
        /// cannot be terminated without causing a shutdown of the entire system.
        /// </summary>
        public static void Protect()
        {
            try
            {
                s_isProtectedLock.EnterWriteLock();

                if(!s_isProtected)
                {
                    System.Diagnostics.Process.EnterDebugMode();
                    RtlSetProcessIsCritical(1, 0, 0);
                    s_isProtected = true;
                }
            }
            finally
            {
                s_isProtectedLock.ExitWriteLock();
            }
        }

        /// <summary>
        /// If already protected, will remove protection from the host process, so that it will no
        /// longer be a system-critical process and thus will be able to shut down safely.
        /// </summary>
        public static void Unprotect()
        {
            try
            {
                s_isProtectedLock.EnterWriteLock();

                if(s_isProtected)
                {
                    RtlSetProcessIsCritical(0, 0, 0);
                    s_isProtected = false;
                }
            }
            finally
            {
                s_isProtectedLock.ExitWriteLock();
            }
        }
    }
}

The idea here is that you call the Protect()method ASAP, and then call Unprotect()when you're doing a voluntary shutdown of the app.

这里的想法是您Protect()尽快调用该方法,然后Unprotect()在您自愿关闭应用程序时调用。

For a WPF app, you're going to want to hook the SessionEndingevent, and this is where you'll call the Unprotect()method, in case someone logs off or shuts down the computer. This absolutely must be the SessionEndingevent, and not the SystemEvents.SessionEndedevent. Very often by the time the SystemEvents.SessionEndedevent 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 the SessionEndingevent, 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 call Unprotect()inside the Application.Exitevent handler.

对于 WPF 应用程序,您将希望挂钩该SessionEnding事件,这是您调用该Unprotect()方法的地方,以防有人注销或关闭计算机。这绝对是SessionEnding事件,而不是SystemEvents.SessionEnded事件。通常在SystemEvents.SessionEnded调用事件时,如果您花费太长时间来释放保护,您的应用程序可能会被强制终止,从而导致每次重新启动或注销时出现 BSOD。如果使用该SessionEnding事件,则可以避免此问题。关于该事件的另一个有趣事实是,在某种程度上,您可以对注销或关闭提出异议。此外,您显然希望Unprotect()Application.Exit事件处理程序内部调用。

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.

作为对所有攻击您采取这些措施的人的说明,请忽略它们。是否有人可能会使用此代码来做一些恶意的事情并不重要,这是一个为完全合法的原因停止完全合法的研究的糟糕借口。就我而言,我已将此作为我自己的应用程序的一部分进行开发,因为成年人(管理员)不希望通过杀死它来停止我的进程。他们明确希望使用此功能,因为它可以防止自己绕过软件的设计目的。

回答by Renan

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.

使 WPF 端只是一个客户端。在这种情况下,“服务器”必须是 Windows 服务。然后将服务设置为自动启动(最后一部分需要管理员权限)。如果它以网络管理员身份运行,则额外奖励。

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.

如果服务的进程被终止,Windows 会立即再次启动它。然后无论用户尝试什么,除非他们拥有管理员权限并自己停止服务,否则他们无法真正停止您的程序逻辑。仅将 WPF GUI 用于配置。

回答by Nair

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.

系统帐户高于管理员(至少在操作系统的情况下)。系统帐户和管理员帐户具有相同的文件权限,但它们具有不同的功能。系统帐户由操作系统和在 Windows 下运行的服务使用。Windows 中有许多服务和进程需要能够在内部登录(例如在 Windows 安装期间)。系统帐户就是为此目的而设计的;它是一个内部帐户,不显示在用户管理器中,不能添加到任何组,也不能分配用户权限。

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.

因此,挑战在于如何在安装过程中将您的应用程序权限提升为系统帐户。我不确定如何提升您的流程。但值得阅读以下帖子ref 1ref 2。此外,即使我们假设您设法将其添加到系统帐户,但在管理自己的应用程序时,即使是指数级超级用户,您仍可能面临更多挑战。