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

问题描述:

我有要求在任务管理器中隐藏进程。这是针对Intranet的场景。所以,一切都是合法的。 :)如何在C#中的任务管理器中隐藏进程?

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

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

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

+0

它是如何被Intranet上的一个合法的情景? 不要给他们的管理权限... – 2008-10-09 16:20:04

+0

这就是问题所在。大多数用户拥有管理员权限来支持一些旧版应用程序。 – 2008-10-09 16:22:20

+14

如果用户具有管理员权限,他们拥有机器,故事结束。 – 2008-10-09 16:34:47

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

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

拦截系统调用非常难以安全执行,而64位Windows内核去out of their way以防止这种情况发生:尝试修改syscall表导致即时蓝屏。这将是非常困难的那些平台上

Here是一个rootkit的尝试做类似(并有几个严重的问题)的例子。

我希望你不能。

更新:考虑到这种情况,我认为您可能最好在不同的管理帐户下运行它。这可能有助于提醒人们注意他们不应该杀死这个过程。

+0

我明白你的观点。 – 2008-10-09 16:27:05

如果你只是简单地伪装进程而不是完全隐藏进程,你可以将其重命名为winlogon.exe或svchost.exe,用户可能会忽略它。但正如塞尔吉奥所说,这是安全的,因为一个原因,它的名声很差。

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

+0

我讨厌这么说,但是由于用户具有管理员权限来伪装这个过程可能是他最好的选择。但请注意:防病毒软件可能会将其视为恶意行为,并阻止该程序。 – 2008-10-09 16:35:50

有没有简单或支持的方式来做到这一点。即使你编写了一个rootkit来完成它,那么未来的更新可能会很容易被打破。我会重新审视这是否是你想要做的事。

不要试图阻止它被杀 - 你不会去管理它。相反,定期打电话给家里的web服务。当网络服务通知客户“保持沉默”时,它可以ping机器以查看是否仅仅是重新启动问题,并且发送电子邮件给经理(或任何人)以约束杀死流程的人。

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

当你的进程启动时,使用当前进程句柄使用SetKernelObjectSecurityDACL_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),但我可能会误解。

或者,你可以写一个小“检查器”工具,来检查,如果应用程序正在运行,如果它不是,它会自动启动它。然后将代码添加到应用程序以检查执行相同操作的“检查器”实用程序。这样,如果一个人被终止,那么另一个人开始备份。我似乎病毒做到了这一点,而且它似乎工作得非常有效。

你怎么样只是要求用户在不杀死进程?你会花多少时间去做,因为同一家公司的员工显然是幼稚的行为。

正如上面提到的,最好的方法是2个任务,互相监视,我知道你不想浪费CPU,所以最好的方法是在任务之间建立一个事件,当一个任务被触发时关闭。

我不是如何建立挂钩完全肯定,但你不使用while循环,其不浪费CPU。

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

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

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

不知道为什么,这已处理不当还建议,但我的继承人在这个网站的第一个答案。而不是阻止用户杀死一个进程。 (需要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); 
} 

许多人可能知道如何去做,但不会在这里发布。在互联网上发布恶意代码是非常危险的。谁知道你可能有危险。问一些电脑工程师。尽管如此,我会给你这个程序的结构。

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

你的过程将不只是显示出来,因为它没有运行的程序,但在程序(资源管理器正在运行。可执行程序)。即使他使用任何类型的任务管理器,用户也不会看到该过程。

停止从永久杀死的过程中,有过程做的第一件事就是打电话“的atexit()”,并具有的atexit()函数启动过程

我知道这个问题是旧的,但我前段时间回答了一个重复的问题,其中包含一些不在这里的好消息,所以我想我会链接到它。 See My answer to the duplicate question.另外,如果您的真正目标是阻止用户杀死进程,那么我所知道的工作非常容易,尽管它有点骇人,而且我不知道这是否仍然有效,只是简单地命名您的应用程序lsass。 exe和任务管理器甚至不允许管理员用户关闭该进程。对于这种方法,哪个用户启动进程或者可执行文件驻留在文件系统的哪个位置并不重要,似乎windows只是检查进程是否被命名,然后不允许它结束。

更新:我只是试图在Windows 7上执行lsass.exe技巧,它似乎已得到修复,但我的猜测是它仍然可以在Windows XP上运行,甚至可能是xp之外的早期版本的服务包。尽管在写这篇文章的时候这已经不起作用了,但我仍然认为我会把它作为一个有趣的事实加以考虑。

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