代码之家  ›  专栏  ›  技术社区  ›  Gulzar Nazim

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

  •  36
  • Gulzar Nazim  · 技术社区  · 17 年前

    我需要在任务管理器中隐藏一个进程。这是针对内联网场景的。所以,一切都是合法的。 :)

    请随时分享您拥有的任何代码(最好是C#)或任何其他技术,或者在使用此路线时遇到的任何问题。

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

    更新2 :删除对rootkit的引用。不知怎么的,这篇文章看起来很负面。

    16 回复  |  直到 17 年前
        1
  •  72
  •   Jon Skeet    17 年前

    不要试图阻止它被杀死——你无法管理它。相反,让它定期呼叫网络服务。当Web服务注意到客户端“静音”时,它可以ping机器,看看是否只是重启问题,并向经理(或任何人)发送电子邮件,以惩罚杀死该进程的人。

        2
  •  46
  •   Chris Smith    9 年前

    没有支持的方法来实现这一点。可以在任何权限级别读取进程列表。如果你希望对管理员隐藏一个进程,那么这是双重不受支持的。

    为了使其工作,您需要编写一个内核模式rootkit来拦截对 NtQuerySystemInformation 因此SystemProcessInformation信息类无法列出您的隐藏进程。

    安全地拦截系统调用非常困难,64位Windows内核 out of their way 为了防止这种情况发生:尝试修改syscall表会导致立即出现蓝屏。在这些平台上,这将非常困难

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

        3
  •  19
  •   Chris Smith    17 年前

    如果你想防止用户从任务管理器中终止进程,你可以在进程上使用安全描述符来拒绝所有人的终止访问。从技术上讲,管理员仍然可以通过获取进程的所有权并重置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),但我可能错了。

        4
  •  10
  •   Marcin    17 年前

    我希望你不能。

    更新: 考虑到这种情况,我认为你最好在另一个管理员帐户下运行它。这可能有助于提醒人们,他们不应该扼杀这个过程。

        5
  •  7
  •   Chris Pietschmann    17 年前

    或者,你可以编写一个小的“检查器”实用程序,检查应用程序是否正在运行,如果没有运行,它会自动启动它。然后向应用程序添加代码,检查执行相同操作的“检查器“实用程序。这样,如果一个终止,另一个就会重新启动。我觉得病毒能做到这一点,而且似乎很有效。

        6
  •  6
  •   Uriel G.    14 年前

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

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

        7
  •  4
  •   Ben Hoffstein    17 年前

    如果你只是需要伪装进程而不是完全隐藏它,你可以将其重命名为winlogon.exe或svchost.exe,它可能会被用户忽略。但正如塞尔吉奥所说,这是默默无闻的安全保障,而且它的名声不好是有原因的。

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

        8
  •  4
  •   Cacoon    13 年前

    不知道为什么还没有人提出这个建议,但这是我在这个网站上的第一个答案。 而不是阻止用户终止进程。(需要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);
    }
    
        9
  •  3
  •   StubbornMule    17 年前

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

        10
  •  3
  •   eitama    16 年前

    如上所述,最好的方法是两个任务,相互监控, 我知道你不想浪费CPU,所以最好的方法是在任务之间建立一个事件,当一个任务关闭时,该事件将被触发。

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

        11
  •  3
  •   Sam Chad    13 年前

    许多人可能知道如何做到这一点,但只是不会在这里发布。在互联网上发布恶意代码是非常危险的。谁知道你可能有危险。问问计算机工程师。不过,我会给你介绍一下程序的结构。

    只需将程序的dll注入explorer.exe即可。

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

        12
  •  2
  •   Rick    16 年前

    你有没有考虑过写服务?这样,服务作为本地系统运行,应用程序在用户的上下文中运行,服务可以确保事情仍然按需完成,应用程序只是此服务的接口。终止应用程序只会导致用户看不到任何通知、系统托盘图标等,但服务仍在工作。

        13
  •  2
  •   E235    8 年前

    我看到@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

    动力壳变化:

    $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
  •  1
  •   pmlarocque    17 年前

    如果你只是要求用户不要终止进程呢?对于同一家公司员工明显幼稚的行为,你会花多少时间去做。

        15
  •  1
  •   Community Mohan Dere    9 年前

    我知道这个问题很老,但我刚才回答了一个重复的问题,其中包含了一些不在这里的好信息,所以我想链接到它。 See My answer to the duplicate question. 此外,如果你的真正目标是阻止用户终止进程,那么我所知道的过去很容易工作,尽管这有点黑客化,我不知道这是否仍然有效,只是简单地将你的应用程序命名为lsass.exe,任务管理器甚至不允许管理员用户关闭进程。对于这种方法,无论哪个用户启动了进程,也不管可执行文件在文件系统上的位置,windows似乎只是检查进程是否命名为this,然后不允许它结束。

    更新:我刚刚尝试在windows 7上执行lsass.exe技巧,它似乎已经修复,但我猜测它仍然适用于windows xp,甚至可能适用于xp以外版本的早期服务包。尽管在撰写本文时,这已经不起作用了,但我还是想把它作为一个有趣的事实。

        16
  •  0
  •   user3629249    11 年前

    要阻止进程被永久杀死,进程做的第一件事就是调用“atexit()”,并让atexit函数启动进程