如何在C#中隐藏任务管理器中的进程?

36

我有一个需求,需要在任务管理器中隐藏一个进程。它是针对企业内部网络的场景,所以一切都是合法的。:)

请随意分享您拥有的任何代码(最好使用C#)或任何其他技术或在使用此方法时可能遇到的任何问题。

更新1:大多数用户都拥有管理员权限,以便运行一些旧应用程序。因此,建议之一是将其隐藏在任务管理器中。如果有其他方法可以防止用户终止进程,那将是很好的。

更新2:删除rootkit的提及。某种程度上使这篇文章看起来很消极。


1
这就是问题所在。大多数用户都拥有管理员权限来支持一些遗留应用程序。 - Gulzar Nazim
17
如果用户拥有管理员特权,那么他们就拥有这台计算机,没有其他说法。 - Joel Coehoorn
2
我很好奇他们为什么要一开始就杀掉它?我的意思是,假设(呵呵)机器运行良好,为什么要杀死一个进程?另外,你的程序是做什么的?这是为了监视那些机器上的人吗?我想不出任何合法的理由,但请给我启示。 - Till
2
合理的问题。可以把这个应用程序想象成一个病毒扫描器。我不能透露具体原因,但我们必须让它一直运行以实际帮助用户。 - Gulzar Nazim
2
我们只是想防止一些高级用户意外终止该进程。需要从技术角度考虑这种可能性。 - Gulzar Nazim
显示剩余2条评论
16个回答

73

不要试图阻止进程被终止 - 你无法做到。相反,让进程定期向一个 Web 服务呼叫。当 Web 服务注意到客户端“变得沉默”时,它可以 ping 该计算机以查看是否只是重新启动问题,并向经理(或其他人)发送电子邮件以管理谁杀死了该进程。


1
+100,我最初是想做原作者想做的事情,但这听起来是一个很好的主意。 - Zack

50
没有支持的方法来完成这个任务。进程列表可以在任何权限级别下读取。如果你希望连管理员都无法看到一个进程,那么这就是不被支持的。
要使其工作,你需要编写一个内核模式的rootkit来拦截对NtQuerySystemInformation的调用,以便SystemProcessInformation信息类别无法列出你隐藏的进程。
拦截系统调用是非常困难且不安全的,64位的Windows内核会尽力阻止这种可能性:试图修改系统调用表会导致立即蓝屏。在这些平台上将会非常困难。 索尼DRM软件就是一个试图做类似事情的rootkit的例子(并且有几个严重的问题)。

您提供的最后一个链接已不再可用。请您能否找到原始内容并发布一下呢?:) - Eru
关于索尼DRM根工具的另一个参考资料,是由原始NT开发人员之一制作的视频:https://www.youtube.com/watch?v=PqWjq2SdzpI - undefined

19
如果您想防止用户从任务管理器中终止进程,可以在进程上使用安全描述符来拒绝所有人的终止访问权限。管理员可以通过获取进程所有权并重置DACL来技术性地终止进程,但是从任务管理器中没有界面执行这些操作。 Process Explorer 可能具有相应界面。
当进程启动时,使用当前进程句柄对 SetKernelObjectSecurity 进行调用,使用 DACL_SECURITY_INFORMATION 设置一个包含零个ACL的DACL。这将拒绝所有人的访问权限,包括试图使用任务管理器终止您的进程的人。
以下是一个同时更改进程所有者的示例:
SECURITY_DESCRIPTOR sd;
ACL dacl;
SID_IDENTIFIER_AUTHORITY ntauth = SECURITY_NT_AUTHORITY;
PSID owner;

assert(InitializeAcl(&dacl, sizeof dacl, ACL_REVISION));

assert(AllocateAndInitializeSid(&ntauth, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &owner));

assert(InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION));

assert(SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE));

assert(SetSecurityDescriptorOwner(&sd, owner, FALSE));

assert(SetKernelObjectSecurity(GetCurrentProcess(), DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION, &sd));

assert(FreeSid(owner) == NULL);

不幸的是,它似乎并不起作用。我仍然可以关闭进程(尽管不能以受限用户的身份)。也许任务管理器正在获取所有权或调用其他特权来终止进程?我似乎记得在先前版本的Windows中(我当时在测试2003),这个方法是可行的,但我可能记错了。


我已经在一个示例应用程序中尝试过这个,但似乎没有任何效果(尽管所有调用都成功了)。我不想说,你能否提供一些能做到这一点的代码链接? - Stephen Deken
我正想问同样的问题。谢谢 Stephen。 - Gulzar Nazim
如果您使用assert(),当定义了NDEBUG时代码将会失败(当定义了该宏时,它被定义为空)。assert()并不能替代错误检查。 - quantum
@xiaomao - 我提供了一个代码片段来说明相关API的用法。有许多不同的错误处理策略可行,加入更复杂的内容会使代码变得混乱。assert()使我的意思明确,这就是重点;它并不是要被粘贴到任意代码库中而没有理解。此外,您可以使用强制在所有构建中使用assert()的头文件。 - Chris Smith

10

我希望你做不到。

更新:鉴于情况,我认为你最好在不同的管理员帐户下运行它。这可能有助于提醒人们不要终止该进程。


7

或者,您可以编写一个小的“检查器”实用程序来检查应用程序是否正在运行,如果没有,则自动启动它。然后添加代码到应用程序中,以检查执行相同操作的“检查器”实用程序。这样,如果其中一个被终止,另一个将重新启动它。我看过病毒也是这样做的,这似乎非常有效。


是的,这是可能的。我想避免为所有这些检查使用CPU周期。 - Gulzar Nazim

7

4
如果您只需要掩盖进程而不是完全隐藏它,您可以将其重命名为winlogon.exe或svchost.exe,这样用户很可能会忽略它。但正如Sergio所提到的那样,这是一种安全性靠隐蔽性保护的方法,因为它有一个不好的声誉。
如果用户拥有适当的权限,则防止其终止进程是另一个困难。我知道的唯一方法是拥有多个进程相互监视,并重新启动任何被终止的受监视进程。再次强调,这是一条不光彩的道路。

我不想这么说,但由于用户拥有管理员权限,伪装进程可能是他最好的选择。但要小心:防病毒软件可能会将其视为恶意行为并阻止该程序运行。 - Joel Coehoorn

4

我不确定为什么还没有人提出这个建议,但这是我在这个网站上的第一个答案。 与其防止用户杀死进程(需要rootkit hooking),你可以通过注册表输入来简单地禁用任务管理器的使用。

public static void ToggleTaskManager(bool toggle)
{
    Microsoft.Win32.RegistryKey HKCU = Microsoft.Win32.Registry.LocalMachine;
    Microsoft.Win32.RegistryKey key = HKCU.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System");
    key.SetValue("DisableTaskMgr", toggle ? 0 : 1, Microsoft.Win32.RegistryValueKind.DWord);
}

3
那么 tasklist.exetaskkill.exeProcessMonitor 呢?仅仅阻止任务管理器似乎并不是防止关闭进程的好方法。 - Oliver
6
你可以使用你的应用程序来关闭它们。 - Cacoon

3

正如上面提到的,最好的方法是两个任务相互监控,我理解你不想浪费CPU,所以最好的方式是在这两个任务之间建立一个事件,当其中一个关闭时触发。

我不太确定如何设置钩子,但这样就不需要使用while循环来浪费CPU了。


3
很多人可能知道如何做,但不会在这里发布。在互联网上发布恶意代码非常危险,谁知道你会不会处于危险之中。询问一些计算机工程师。虽然我会给你程序的结构。
只需将您的程序的dll注入explorer.exe中。
因为该进程未作为程序运行而是在一个程序(explorer.exe)中运行,所以您的进程不会显示出来。即使用户使用任何类型的任务管理器,也无法看到该进程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接