我需要在任务管理器中隐藏一个进程。适用于内网场景。所以,一切都是合法的。:)
请随时分享您拥有的任何代码(最好是 C# 代码)或任何其他技术或与此路线相关的任何问题。
更新 1:大多数用户拥有管理员权限才能运行一些旧版应用程序。因此,建议之一是将其隐藏在任务管理器中。如果有其他方法可以防止用户终止进程,那就太好了。
更新 2 :删除对 rootkit 的引用。不知何故,这篇文章看起来很消极。
我需要在任务管理器中隐藏一个进程。适用于内网场景。所以,一切都是合法的。:)
请随时分享您拥有的任何代码(最好是 C# 代码)或任何其他技术或与此路线相关的任何问题。
更新 1:大多数用户拥有管理员权限才能运行一些旧版应用程序。因此,建议之一是将其隐藏在任务管理器中。如果有其他方法可以防止用户终止进程,那就太好了。
更新 2 :删除对 rootkit 的引用。不知何故,这篇文章看起来很消极。
不要试图阻止它被杀死——你不会去管理它。相反,让它定期调用网络服务。当 web 服务注意到客户端“静默”时,它可以 ping 机器以查看这是否只是重新启动问题,并向经理(或任何人)发送电子邮件以惩罚终止进程的人。
没有支持的方式来实现这一点。可以在任何特权级别读取进程列表。如果您希望甚至对管理员隐藏进程,那么这是双重不受支持的。
要让它工作,您需要编写一个内核模式 rootkit 来拦截对NtQuerySystemInformation的调用,以便 SystemProcessInformation 信息类无法列出您的隐藏进程。
拦截系统调用很难安全地进行,64 位 Windows 内核竭尽全力防止这种情况发生:尝试修改系统调用表会导致即时蓝屏。在这些平台上会非常困难
这是一个尝试做类似事情的rootkit的例子(并且有几个严重的问题)。
如果你想阻止用户从任务管理器中杀死进程,你可以在进程上使用安全描述符来拒绝终止对每个人的访问。从技术上讲,管理员仍然可以通过获取进程的所有权并重置 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),但我可能弄错了。
我希望你不能。
更新:鉴于这种情况,我认为您最好在不同的管理员帐户下运行它。这可能有助于提醒人们不要终止进程。
或者,您可以编写一个小的“检查器”实用程序来检查应用程序是否正在运行,如果不是,它会自动启动它。然后将代码添加到应用程序以检查执行相同操作的“检查器”实用程序。这样,如果一个被终止,那么另一个将重新启动它。我似乎病毒会这样做,而且它似乎非常有效。
编写驱动程序 - 您可以使用 ObRegisterCallbacks 来注册进程对象访问通知。当 DesiredAccess 包含您不喜欢的访问权限时返回 STATUS_ACCESS_DENIED,例如进程终止或写入进程内存。
http://msdn.microsoft.com/en-us/library/windows/hardware/ff558692(v=vs.85).aspx
如果您只是需要伪装进程而不是完全隐藏它,您可以将其重命名为 winlogon.exe 或 svchost.exe,它可能会被用户忽略。但正如塞尔吉奥所说,这是默默无闻的安全性,它的名声不好是有原因的。
如果用户拥有适当的权限,则防止用户杀死进程是另一个困难。我知道的唯一方法是让多个进程相互监视并重新启动任何被监视的进程被杀死。再一次,这走上了一条阴暗的道路。
不知道为什么还没有建议,但这是我在这个网站上的第一个答案。而不是阻止用户杀死进程。(需要 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);
}
没有简单或受支持的方法可以做到这一点。即使您编写了一个 rootkit 来执行此操作,也很容易被未来的更新所破坏,该更新旨在填补该漏洞。我会重新检查这是否是您想要做的事情。
正如上面所说的,最好的方法是2个任务,互相监控,我理解你不想浪费CPU,所以最好的方法是在任务之间建立一个事件,当一个任务关闭时触发。
我不完全确定如何设置挂钩,但是您不会使用会浪费 CPU 的 while 循环。
很多人可能知道怎么做,但不会在这里发布。在互联网上发布恶意代码是非常危险的。谁知道你可能有危险。问一些计算机工程师。我会给你程序的结构。
只需将程序的 dll 注入 explorer.exe。
您的进程不仅会显示出来,因为它不是作为程序运行,而是在程序(explorer.exe)中运行。即使他使用任何类型的任务管理器,用户也不会看到该过程。
您是否考虑过编写服务?这样服务作为本地系统运行,应用程序在用户的上下文下运行,服务可以保证事情仍然按需要完成,而应用程序只是这个服务的一个接口。终止应用程序只会导致用户看不到任何通知、系统托盘图标等,但服务仍在执行其工作。
我看到@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
}
#>
你只是要求用户不要杀死进程呢?你会花多少时间去做这件事,因为在同一家公司的员工显然是幼稚的行为。
我知道这个问题很老,但我不久前回答了一个重复的问题,其中包含一些不错的信息,但这里没有,所以我想我会链接到它。 请参阅我对重复问题的回答。此外,如果您的真正目标是阻止用户终止该进程,那么我所知道的过去很容易工作,尽管它有点骇人听闻而且我不知道这是否仍然有效,只是简单地将您的应用程序命名为 lsass.exe并且任务管理器甚至不允许管理员用户关闭该进程。对于这种方法,哪个用户启动进程或可执行文件驻留在文件系统上的位置都没有关系,Windows 似乎只是检查进程是否被命名为 this 然后不允许它结束。
更新:我刚刚尝试在 Windows 7 上执行 lsass.exe 技巧,它似乎已修复,但我猜它仍然适用于 windows xp,甚至可能适用于 xp 以外版本的早期服务包。尽管在撰写本文时这不再有效,但我认为无论如何我都会将其作为一个有趣的事实包含在内。
要阻止进程被永久终止,让进程做的第一件事是调用“atexit()”并让 atexit() 函数启动进程