我是一名学生,对 Windows 中不可终止的进程非常好奇。
出于教育目的,我想创建一个应用程序(可能在 VB6 中?),用户无法从任务管理器或 taskkill 中终止该应用程序。此类应用程序采用哪些策略和利用来实现这一目标?
我是一名学生,对 Windows 中不可终止的进程非常好奇。
出于教育目的,我想创建一个应用程序(可能在 VB6 中?),用户无法从任务管理器或 taskkill 中终止该应用程序。此类应用程序采用哪些策略和利用来实现这一目标?
与很多人认为的相反,实际上有几种方法可以做到这一点。其中一些很常见,一些很少见。他们有的弱,有的强。这一切都取决于你如何做到这一点。
让我们来看看它们的集合:
1. NT之前的RegisterServiceProcess
技巧
Windows 9x 和其他 NT 之前的操作系统在 kernel32.dll 中有一个未记录的 API,称为RegisterServiceProcess
,它(顾名思义)将进程注册为系统服务。一旦一个进程调用了这个函数,操作系统就认为它很关键,不允许任务管理器杀死它。NT 出现时此功能已被删除,因此它不适用于 XP 或更高版本。
2. 进程命名技巧
回到 WinXP,任务管理器可执行文件包含一个硬编码的进程名称列表,它会拒绝终止,而是显示一条消息,就像你提到的那样。这些基本上涵盖了关键系统服务,例如smss.exe
和rpcss.exe
. 问题是没有检查路径,因此任何其他具有相同名称的可执行文件都会导致无法终止的进程。这个技巧本身并不能阻止进程被杀死,而是阻止 Windows XP 任务管理器能够杀死进程。仍然可以使用其他工具来终止该进程。
3. 保持活动过程
这些是迄今为止最常见的。创建了两个进程,并反复检查另一个进程是否存在。如果一个人被杀,另一个人会复活它。这并不能阻止您真正终止该进程,但它确实使阻止该进程返回很烦人。
任务管理器包括一个终止进程树的选项,它允许您终止一个进程和所有子进程,这可能有助于解决此问题。在 Windows 中创建进程时,操作系统会跟踪创建它的进程 ID。终止进程树遍历所有进程并查找父 ID 等于您要终止的进程 ID 的进程。由于保持活动的进程通常在重复轮询上工作,因此您可以在它们发现任何错误之前杀死这两个进程。
对此的防御方法是创建一个虚拟进程来生成保活进程,然后让该虚拟进程退出。主进程将其 ID 传递给 dummy 进程,dummy 进程将其 ID 传递给 keep-alive 进程,但当 dummy 进程退出时,链条就断开了。这使得主进程和保活进程都在运行,但无法使用任务管理器的终止进程树功能。相反,您必须编写一个脚本来杀死它们,或者使用一个允许您同时杀死多个进程的工具。
4. 通过加载的 DLL 的用户模式挂钩
可以将 DLL 注入到正在运行的进程中。实际上,出于可扩展性的目的,Windows 提供了一项功能,可以将任何 DLL 加载到所有导入 user32.dll 的进程中。此方法称为 AppInit DLL。注入 DLL 后,它可能会操纵进程的内存。然后可以覆盖某些函数指针的值,以便将调用重定向到存根例程,然后该例程调用目标函数。该存根例程可用于过滤或操作函数调用的参数和返回值。这种技术称为挂钩,它可以非常强大。在这种情况下,可以将 DLL 注入到正在运行的进程OpenProcess
中TerminateProcess
以确保没有应用程序可以获取您的进程的句柄或终止它。这在某种程度上导致了军备竞赛,因为替代的用户模式 API 可用于终止进程,并且很难将它们全部挂钩和阻止,尤其是当我们考虑未记录的 API 时。
5. 通过注入线程的用户模式挂钩
这个技巧与 DLL 的工作原理相同,除了不需要 DLL 文件。创建目标进程的句柄,在其中分配一些内存,通过 将VirtualAllocEx
代码和数据复制到内存块中WriteProcessMemory
,并通过在进程中创建线程CreateRemoteThread
。这导致一些外部代码在目标进程中执行,然后可能会引发各种钩子以防止进程被杀死。
6.内核模式调用钩子
在内核中,有一个称为系统服务调度表 (SSDT) 的特殊结构,它将用户模式调用中的函数 ID 映射到内核 API 中的函数指针。该表用于在用户模式和内核模式之间转换。如果可以加载恶意驱动程序,它可能会修改 SSDT 以导致执行自己的函数,而不是执行正确的 API。这是一个内核模式的钩子,它构成了一个 rootkit。从本质上讲,可以通过从调用中返回虚假数据来掩盖操作系统的眼睛。实际上,可以使进程不仅不可杀死,而且不可见。在 x64 构建上存在的一个问题是 SSDT 受到内核补丁保护 (KPP) 的保护。可以禁用 KPP,但这会产生深远的影响,可能会使开发 rootkit 变得困难。
7. 直接内核对象操作(DKOM)
该技巧还涉及在操作系统上加载恶意驱动程序,但不需要更改 SSDT。系统上的进程作为EPROCESS
结构存储在内核中。请记住,此结构完全依赖于版本,并且仅由 Microsoft 部分记录,因此需要跨多个目标版本进行逆向工程,以确保代码不会尝试读取错误的指针或数据。但是,如果您可以成功地定位和枚举EPROCESS
内核中的结构,则可以对其进行操作。
进程列表中的每个条目都有一个FLink
和BLink
指针,它指向列表中的下一个和前一个进程。如果您确定您的目标进程并使其FLink
和BLink
指针指向自己,并且FLink
其BLink
兄弟姐妹的和指向彼此,则操作系统在执行任何内务操作时会跳过您的进程,例如杀死进程。这个技巧称为取消链接。这不仅会使进程对用户不可见,而且还会阻止所有用户模式 API 以进程为目标,除非在取消链接之前生成了该进程的句柄。这是一种非常强大的 rootkit 技术,尤其是因为它很难从中恢复。
8. 调试器技巧
这是一个很酷的技巧,我还没有在野外看到过,但效果很好。Windows 调试器 API 允许任何进程调试另一个进程,只要它具有这样做的权限。如果您使用调试器 API,则可以将进程置于“已调试”状态。如果此进程包含当前被调试器暂停的线程,则该进程不能被 Windows 杀死,因为当线程被阻塞时,在终止期间无法保证正确的线程控制。当然,如果您终止调试器,进程将停止调试并关闭或崩溃。但是,有时可能会产生这样一种情况,即存在一系列进程,这些进程在循环中相互调试。如果每个进程在下一个进程中停止一个虚拟线程,则没有一个可以被杀死。请注意,这是可能的电力用户手动杀死其他线程的过程中,使之无用,但它仍然不会被杀死。
9. Windows 8 DRM
这是我最近才听说的一个新的,但我不太了解它。Twitter 上有一些关于它的谣言,我在各种技术网站上到处都看到了片段,但我还没有看到任何具体的研究。我认为现在还为时尚早。从本质上讲,故事是 Windows 8 有一种机制,允许“受信任的提供者”将进程注册为 DRM 关键进程,防止它们被用户杀死或操纵。有人推测检查受信任提供者的机制很弱,可能会受到攻击。< -看起来这个是假的。谣言工厂就这么多!
更新:Harry Johnston 在评论中指出,Windows 8.1 引入了受保护的服务,这些服务旨在供 AV 和 DRM 使用,以防止被系统上的低权限代码操纵或攻击。
10. 工具操作
这个工具可能已经在野外使用了很多,但我从未见过它做得很好。本质上,这个技巧涉及通过以改变功能的方式编辑磁盘上的可执行文件来定位特定工具,例如任务管理器。这与我之前提到的用户模式挂钩技巧非常相似,但在这种情况下,它们会保留在磁盘上,并且比简单的 API 挂钩具有更广泛的影响。当然,一个问题是 Windows 文件保护 (WFP) 会阻止更改某些关键系统文件,包括任务管理器。不过有趣的是,可以通过注册表更改默认的任务管理器可执行路径。因此,不要弄乱任务管理器的可执行文件,只需将您自己的版本转储到某个地方并让操作系统使用它。
总而言之,有很多方法可以实现这一点,并且具有不同程度的稳健性。以上代表了其中的大多数,但并不详尽。事实上,我描述的许多技巧都可以通过其他方式实现,使用不同的机制或 API 来实现相同的目标。
我不相信你正在尝试做的事情是可能的。您将不得不颠覆操作系统以防止进程被杀死。所有进程都在操作系统内运行,因此操作系统可以杀死任何进程。您甚至可以杀死运行开始菜单和桌面的“explorer.exe”之类的进程。
大多数看起来“无法杀死”的程序实际上是可以杀死的,但是另一个程序正在监视它们的执行,当它看到进程关闭时,它会立即自动重新启动。当你杀死进程A时,进程B启动它,当你杀死进程B时,进程A启动它。由于您不能轻松地将两个进程完全一起杀死,因此在系统运行时很难摆脱它们。
多家反病毒供应商以及流行的反作弊程序 PunkBuster 都使用了相同的技术。
在较旧的系统上,该进程也可能作为服务运行。在 Windows XP 和 Windows 2000 中,任务管理器无法终止由服务管理器启动的进程,因为服务管理器在不同的用户上下文中运行。在这些旧系统上,创建 Windows 服务会阻止使用任务管理器直接杀死,但是较新版本的 Windows 将允许它被杀死。
如果权限被拒绝,查看进程在什么上下文下运行可能很有用。您可以使用 SysInternal 套件中的 Process Explorer 之类的工具来查看进程正在运行的用户上下文。如果任务管理器在其下运行的用户上下文无权终止在该进程所在的用户上下文下运行的进程,则终止将失败。
此问题下的超级用户提供了相关信息https://superuser.com/questions/109010/kill-a-process-which-gives-access-denied。似乎可以应用每个进程的安全设置来删除杀死的权利。这可以以编程方式完成,并且会使杀死它变得复杂,但是管理员仍然可以拥有该进程的所有权,然后将权限调整回允许杀死它。特定的 Windows API 是 CreateProcessWithTokenW 和 SetSecurityInfo。
正如 AJ 所提到的,操作系统最终负责。它决定一个进程是否可以被杀死,何时被杀死,如何被杀死等。某些进程可能被操作系统“保护”,防止它们被终止,或者在这种情况下,该进程在技术上可能是可杀死的,但是杀死进程会触发整个机器的关闭。
如果您正在编写恶意软件并希望无法杀死进程,那么您最好的办法是修改操作系统以防止它。这不是不可能的,实际上是作者已经考虑过的事情。事实上,为了保护资源而对操作系统进行修改是一个常见的话题,以至于他们给它起了一个名字:“ rootkit ”。
那么如何修改正在运行的操作系统呢?幸运的是,现代操作系统都是为允许您进行此类修改而编写的;只需编写一个内核模块(又名“驱动程序”)。甚至还有一个开发工具包可以帮助您入门。
一旦你在那里,只需挂钩处理过程控制的代码路径并放入你的小排除规则。阅读有关 Rootkit 的更多信息。
创建一个真正无法杀死的进程并不是一个好主意。然而,完全有可能保护进程不被管理员以外的任何其他用户终止。管理员拥有并且应该拥有对该进程的完全访问权限,并且他们可以终止该进程。
这样做的方法是修改进程 ACL,以使操作系统拒绝非管理员终止进程的任何尝试。
在您的进程启动代码中,您应该获取进程 DACL,对其添加限制,以便“每个人”在尝试终止进程时都会收到“拒绝访问”,然后写回进程 DACL。
如果您有兴趣,我可以为您提供有关如何执行此操作的 .NET 源代码。