我有一个需求,需要在任务管理器中隐藏一个进程。它是针对企业内部网络的场景,所以一切都是合法的。:)
请随意分享您拥有的任何代码(最好使用C#)或任何其他技术或在使用此方法时可能遇到的任何问题。
更新1:大多数用户都拥有管理员权限,以便运行一些旧应用程序。因此,建议之一是将其隐藏在任务管理器中。如果有其他方法可以防止用户终止进程,那将是很好的。
更新2:删除rootkit的提及。某种程度上使这篇文章看起来很消极。
我有一个需求,需要在任务管理器中隐藏一个进程。它是针对企业内部网络的场景,所以一切都是合法的。:)
请随意分享您拥有的任何代码(最好使用C#)或任何其他技术或在使用此方法时可能遇到的任何问题。
更新1:大多数用户都拥有管理员权限,以便运行一些旧应用程序。因此,建议之一是将其隐藏在任务管理器中。如果有其他方法可以防止用户终止进程,那将是很好的。
更新2:删除rootkit的提及。某种程度上使这篇文章看起来很消极。
没有简单或支持的方法来做到这一点。即使您编写了一个rootkit来执行此操作,那么它也很容易被未来更新破坏以填补这个漏洞。我建议重新考虑是否需要这样做。
我看到@Chris Smith的回答,决定将其转换为C#。
这里是从这里取得的简单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
,以便在没有管理员的情况下关闭它,但也可以将其删除。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
}
#>
你考虑过编写服务吗?这样服务将以本地系统身份运行,应用程序在用户上下文中运行,服务可以确保按需完成工作,而应用程序只是该服务的接口。关闭应用程序只会导致用户看不到任何通知、系统托盘图标等,但服务仍在执行其工作。
我知道这个问题很老,但是我之前回答过一个重复的问题,那里包含了一些很好的信息,这里没有,所以我想链接到那里。请查看我的回答。另外,如果你的真正目标是阻止用户杀死进程,那么我知道的方法非常简单,虽然有点hackish,并且我不知道它是否仍然有效,就是将你的应用程序命名为lsass.exe,任务管理器甚至不允许管理员用户关闭该进程。对于这种方法,无论哪个用户启动了进程或可执行文件位于文件系统的何处,都没有关系,似乎Windows只是检查进程是否被命名为这个名称,然后不允许其结束。
更新:我刚刚尝试在Windows 7上使用lsass.exe技巧,但似乎已经被修复了,但我猜它仍然适用于Windows XP甚至是XP之后版本的早期服务包。虽然在撰写本文时这种方法已经不再有效,但我还是想把它作为一个有趣的事实包含在内。
你为什么不直接要求用户不要杀死进程呢?这样做需要花费多少时间,而这种行为显然是同一公司员工的幼稚表现。