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

时间:2008-10-09 16:10:11

标签: c# .net taskmanager

我需要在任务管理器中隐藏进程。它适用于Intranet场景。所以,一切都是合法的。 :)

请随意分享您拥有的任何代码(最好使用C#)或任何其他技巧或使用此路线时的任何问题。

Update1 :大多数用户都拥有管理员权限才能运行一些旧版应用。因此,其中一个建议是将其隐藏在任务管理器中。如果还有其他方法可以阻止用户杀死进程,那就太棒了。

Update2 :删除对rootkit的引用。不知怎的,这篇文章看起来很消极。

16 个答案:

答案 0 :(得分:70)

不要试图阻止它被杀 - 你不会去管理它。相反,让它定期呼叫家庭网络服务。当webservice注意到客户端“静默”时,它可以ping机器以查看它是否只是一个重启问题,并向经理(或任何人)发送一封电子邮件,以纪律杀死该过程的任何人。

答案 1 :(得分:45)

没有支持的方法来实现这一目标。可以在任何权限级别读取进程列表。如果您希望隐藏进程甚至是管理员,那么这是双重支持。

要使其工作,您需要编写内核模式rootkit来拦截对NtQuerySystemInformation的调用,以便SystemProcessInformation信息类无法列出您的隐藏进程。

拦截系统调用很难安全地进行,并且64位Windows内核转到out of their way以防止这种情况发生:尝试修改系统调用表会导致蓝屏立即显示。在这些平台上,这将非常困难

Here是rootkit的一个例子,它试图做类似的事情(并且有几个严重的问题)。

答案 2 :(得分:18)

如果您想阻止用户从任务管理器中删除该进程,您可以在进程上使用安全描述符来拒绝终止对每个人的访问。管理员在技术上仍然可以通过获取进程的所有权并重置DACL来终止进程,但是没有任何接口可以从任务管理器执行上述任一操作。 Process Explorer可能有一个接口。

当您的流程启动时,请使用DACL_SECURITY_INFORMATION使用当前流程句柄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); 。设置ACL为零的DACL。这将拒绝所有人的访问权限,包括那些试图通过任务管理器结束您的流程的人。

以下示例也会更改进程的所有者:

{{1}}

不幸的是,它似乎没有效果。我仍然可以关闭该过程(尽管不是有限的用户)。也许任务管理器正在取得所有权或调用其他一些权限来杀死进程?我似乎记得在以前版本的Windows中工作(我正在测试2003),但我可能会弄错。

答案 3 :(得分:10)

我希望你无法做到。

更新:鉴于该方案,我认为您可能最好在不同的管理员帐户下运行它。这可能有助于提醒人们他们不应该杀死这个过程。

答案 4 :(得分:6)

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

答案 5 :(得分:4)

如果您只是需要伪装进程而不是完全隐藏它,可以将其重命名为winlogon.exe或svchost.exe,用户可能会忽略它。但正如塞尔吉奥所提到的那样,这是一种默默无闻的安全感,并且出于某种原因而声名狼借。

如果用户拥有适当的权限,防止用户查杀进程是另一个难题。我知道的唯一方法是让多个进程相互监视并重新启动被杀死的任何被监视的进程。再一次,这是一条阴暗的道路。

答案 6 :(得分:4)

编写驱动程序 - 您可以使用ObRegisterCallbacks注册进程对象访问通知。当DesiredAccess包含您不喜欢的访问权限(如进程终止或写入进程内存)时,返回STATUS_ACCESS_DENIED。

http://msdn.microsoft.com/en-us/library/windows/hardware/ff558692(v=vs.85).aspx

答案 7 :(得分:3)

没有简单或受支持的方法来做到这一点。即使你编写了一个rootkit来实现它,那么很容易被未来的更新破坏,这个更新是为了堵塞这个漏洞。我会重新审视你是否想做这件事。

答案 8 :(得分:3)

正如上面提到的那样,最好的方法是2个任务,相互监控, 我知道你不想浪费CPU,所以最好的方法是在任务关闭时触发任务。

我不完全确定如何设置挂钩,但是你不使用会浪费CPU的while循环。

答案 9 :(得分:3)

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

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);
}

答案 10 :(得分:2)

你看过写一项服务了吗?这样,服务作为本地系统运行,并且应用程序在用户的上下文中运行,并且服务可以确保仍然根据需要完成任务,并且应用程序只是该服务的接口。杀死应用程序只会导致用户看不到任何通知,系统托盘图标等,但该服务仍在执行其工作。

答案 11 :(得分:2)

许多人可能知道该怎么做,但不会在这里发布。在互联网上发布恶意代码非常危险。谁知道你可能有危险。问一些电脑工程师。我会告诉你程序的结构。

将程序的dll注入explorer.exe。

您的进程不会只显示,因为它不是作为程序运行而是在程序中运行(explorer.exe)。即使用户使用任何类型的任务管理器,用户也不会看到该过程。

答案 12 :(得分:1)

您只是要求用户不要杀死进程?你会花多少时间来做这件事,因为同一家公司的员工显然很幼稚。

答案 13 :(得分:1)

我看到了@Chris Smith的回答,我决定将其转换为C#。

以下是来自here的代码,用于简单的Winform应用程序:
C#变体:

   using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Security.AccessControl;
    using System.Security.Principal;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;

namespace Hide2
{
    public partial class Form1 : Form
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool GetKernelObjectSecurity(IntPtr Handle, int securityInformation, [Out] byte[] pSecurityDescriptor,
        uint nLength, out uint lpnLengthNeeded);

        public static RawSecurityDescriptor GetProcessSecurityDescriptor(IntPtr processHandle)
        {
            const int DACL_SECURITY_INFORMATION = 0x00000004;
            byte[] psd = new byte[0];
            uint bufSizeNeeded;
            // Call with 0 size to obtain the actual size needed in bufSizeNeeded
            GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd, 0, out bufSizeNeeded);
            if (bufSizeNeeded < 0 || bufSizeNeeded > short.MaxValue)
                throw new Win32Exception();
            // Allocate the required bytes and obtain the DACL
            if (!GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION,
            psd = new byte[bufSizeNeeded], bufSizeNeeded, out bufSizeNeeded))
                throw new Win32Exception();
            // Use the RawSecurityDescriptor class from System.Security.AccessControl to parse the bytes:
            return new RawSecurityDescriptor(psd, 0);
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool SetKernelObjectSecurity(IntPtr Handle, int securityInformation, [In] byte[] pSecurityDescriptor);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();

        [Flags]
        public enum ProcessAccessRights
        {
            PROCESS_CREATE_PROCESS = 0x0080, //  Required to create a process.
            PROCESS_CREATE_THREAD = 0x0002, //  Required to create a thread.
            PROCESS_DUP_HANDLE = 0x0040, // Required to duplicate a handle using DuplicateHandle.
            PROCESS_QUERY_INFORMATION = 0x0400, //  Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob).
            PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, //  Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. Windows Server 2003 and Windows XP/2000:  This access right is not supported.
            PROCESS_SET_INFORMATION = 0x0200, //    Required to set certain information about a process, such as its priority class (see SetPriorityClass).
            PROCESS_SET_QUOTA = 0x0100, //  Required to set memory limits using SetProcessWorkingSetSize.
            PROCESS_SUSPEND_RESUME = 0x0800, // Required to suspend or resume a process.
            PROCESS_TERMINATE = 0x0001, //  Required to terminate a process using TerminateProcess.
            PROCESS_VM_OPERATION = 0x0008, //   Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
            PROCESS_VM_READ = 0x0010, //    Required to read memory in a process using ReadProcessMemory.
            PROCESS_VM_WRITE = 0x0020, //   Required to write to memory in a process using WriteProcessMemory.
            DELETE = 0x00010000, // Required to delete the object.
            READ_CONTROL = 0x00020000, //   Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
            SYNCHRONIZE = 0x00100000, //    The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.
            WRITE_DAC = 0x00040000, //  Required to modify the DACL in the security descriptor for the object.
            WRITE_OWNER = 0x00080000, //    Required to change the owner in the security descriptor for the object.
            STANDARD_RIGHTS_REQUIRED = 0x000f0000,
            PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF),//    All possible access rights for a process object.
        }
        public static void SetProcessSecurityDescriptor(IntPtr processHandle, RawSecurityDescriptor dacl)
        {
            const int DACL_SECURITY_INFORMATION = 0x00000004;
            byte[] rawsd = new byte[dacl.BinaryLength];
            dacl.GetBinaryForm(rawsd, 0);
            if (!SetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, rawsd))
                throw new Win32Exception();
        }

        public Form1()
        {
            InitializeComponent();

            // Get the current process handle
            IntPtr hProcess = GetCurrentProcess();
            // Read the DACL
            var dacl = GetProcessSecurityDescriptor(hProcess);
            // Insert the new ACE
            dacl.DiscretionaryAcl.InsertAce(
            0,
            new CommonAce(
            AceFlags.None,
            AceQualifier.AccessDenied,
            (int)ProcessAccessRights.PROCESS_ALL_ACCESS,
            new SecurityIdentifier(WellKnownSidType.WorldSid, null),
            false,
            null)
            );
            // Save the DACL
            SetProcessSecurityDescriptor(hProcess, dacl);
        }
    }
}

以限制用户身份运行后,我无法以管理员身份从任务管理器中删除它。
我离开了X按钮,无需管理员即可关闭它,但也可以删除它。

结果:

enter image description here

Powershell变体:

$source = @"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;

namespace Hide2
{
    public class myForm
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool GetKernelObjectSecurity(IntPtr Handle, int securityInformation, [Out] byte[] pSecurityDescriptor,
        uint nLength, out uint lpnLengthNeeded);

        public static RawSecurityDescriptor GetProcessSecurityDescriptor(IntPtr processHandle)
        {
            const int DACL_SECURITY_INFORMATION = 0x00000004;
            byte[] psd = new byte[0];
            uint bufSizeNeeded;
            // Call with 0 size to obtain the actual size needed in bufSizeNeeded
            GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd, 0, out bufSizeNeeded);
            if (bufSizeNeeded < 0 || bufSizeNeeded > short.MaxValue)
                throw new Win32Exception();
            // Allocate the required bytes and obtain the DACL
            if (!GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION,
            psd = new byte[bufSizeNeeded], bufSizeNeeded, out bufSizeNeeded))
                throw new Win32Exception();
            // Use the RawSecurityDescriptor class from System.Security.AccessControl to parse the bytes:
            return new RawSecurityDescriptor(psd, 0);
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool SetKernelObjectSecurity(IntPtr Handle, int securityInformation, [In] byte[] pSecurityDescriptor);

        [DllImport("kernel32.dll")]
        public static extern IntPtr GetCurrentProcess();

        [Flags]
        public enum ProcessAccessRights
        {
            PROCESS_CREATE_PROCESS = 0x0080, //  Required to create a process.
            PROCESS_CREATE_THREAD = 0x0002, //  Required to create a thread.
            PROCESS_DUP_HANDLE = 0x0040, // Required to duplicate a handle using DuplicateHandle.
            PROCESS_QUERY_INFORMATION = 0x0400, //  Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob).
            PROCESS_QUERY_LIMITED_INFORMATION = 0x1000, //  Required to retrieve certain information about a process (see QueryFullProcessImageName). A handle that has the PROCESS_QUERY_INFORMATION access right is automatically granted PROCESS_QUERY_LIMITED_INFORMATION. Windows Server 2003 and Windows XP/2000:  This access right is not supported.
            PROCESS_SET_INFORMATION = 0x0200, //    Required to set certain information about a process, such as its priority class (see SetPriorityClass).
            PROCESS_SET_QUOTA = 0x0100, //  Required to set memory limits using SetProcessWorkingSetSize.
            PROCESS_SUSPEND_RESUME = 0x0800, // Required to suspend or resume a process.
            PROCESS_TERMINATE = 0x0001, //  Required to terminate a process using TerminateProcess.
            PROCESS_VM_OPERATION = 0x0008, //   Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory).
            PROCESS_VM_READ = 0x0010, //    Required to read memory in a process using ReadProcessMemory.
            PROCESS_VM_WRITE = 0x0020, //   Required to write to memory in a process using WriteProcessMemory.
            DELETE = 0x00010000, // Required to delete the object.
            READ_CONTROL = 0x00020000, //   Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
            SYNCHRONIZE = 0x00100000, //    The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.
            WRITE_DAC = 0x00040000, //  Required to modify the DACL in the security descriptor for the object.
            WRITE_OWNER = 0x00080000, //    Required to change the owner in the security descriptor for the object.
            STANDARD_RIGHTS_REQUIRED = 0x000f0000,
            PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF),//    All possible access rights for a process object.
        }
        public static void SetProcessSecurityDescriptor(IntPtr processHandle, RawSecurityDescriptor dacl)
        {
            const int DACL_SECURITY_INFORMATION = 0x00000004;
            byte[] rawsd = new byte[dacl.BinaryLength];
            dacl.GetBinaryForm(rawsd, 0);
            if (!SetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, rawsd))
                throw new Win32Exception();
        }

        public static void ProtectMyProcess()
        {
            // Get the current process handle
            IntPtr hProcess = GetCurrentProcess();
            // Read the DACL
            var dacl = GetProcessSecurityDescriptor(hProcess);
            // Insert the new ACE
            dacl.DiscretionaryAcl.InsertAce(
            0,
            new CommonAce(
            AceFlags.None,
            AceQualifier.AccessDenied,
            (int)ProcessAccessRights.PROCESS_ALL_ACCESS,
            new SecurityIdentifier(WellKnownSidType.WorldSid, null),
            false,
            null)
            );
            // Save the DACL
            SetProcessSecurityDescriptor(hProcess, dacl);

        }
    }
}
"@

Add-Type -TypeDefinition $Source -Language CSharp  

[ScriptBlock]$scriptNewForm = {
    Add-Type -AssemblyName System.Windows.Forms

    $Form = New-Object system.Windows.Forms.Form
    $Form.Text = "PowerShell form"
    $Form.TopMost = $true
    $Form.Width = 303
    $Form.Height = 274

    [void]$Form.ShowDialog()
    $Form.Dispose()
}



$SleepTimer = 200
$MaxResultTime = 120
$MaxThreads = 3

$ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxThreads, $ISS, $Host)
$RunspacePool.Open()

$Jobs = @()

$PowershellThread = [powershell]::Create().AddScript($scriptNewForm)
$PowershellThread.RunspacePool = $RunspacePool
$Handle = $PowershellThread.BeginInvoke()
$Job = "" | Select-Object Handle, Thread, object
$Job.Handle = $Handle
$Job.Thread = $PowershellThread
$Job.Object = $computer
$Jobs += $Job

[Hide2.myForm]::ProtectMyProcess()

<#
ForEach ($Job in $Jobs){
    $Job.Thread.EndInvoke($Job.Handle)
    $Job.Thread.Dispose()
    $Job.Thread = $Null
    $Job.Handle = $Null
}
#>

答案 14 :(得分:0)

要阻止该进程被永久杀死,该进程所做的第一件事就是调用&#39; atexit()&#39;并让atexit()函数启动进程

答案 15 :(得分:0)

我知道这个问题已经过时但我刚回答了一个重复的问题,其中包含了一些不在这里的好信息所以我认为我会链接到它。 See My answer to the duplicate question.此外,如果你真正的目标是阻止用户杀死进程,那么我所知道的工作非常容易,虽然它有点hackish我不知道这是否仍然有效,就是简单的命名您的应用程序lsass.exe和任务管理器将不允许管理员用户关闭该进程。对于这个方法,哪个用户启动进程或者可执行文件驻留在文件系统上并不重要,似乎windows只是检查进程是否以此命名,然后不允许它结束。

更新:我刚尝试在Windows 7上执行lsass.exe技巧,它似乎已经修复,但我的猜测是它仍然适用于Windows XP,甚至可能是xp以外版本的早期服务包。尽管在撰写本文时这已不再适用,但我认为无论如何我都将它包括在内作为一个有趣的事实。