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

发布于 2024-07-06 06:34:00 字数 277 浏览 7 评论 0原文

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

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

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

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

I have a requirement to hide a process in Task Manager. It is for Intranet scenario. So, everything is legitimate. :)

Please feel free to share any code you have (preferably in C#) or any other techniques or any issues in going with this route.

Update1: Most of the users have admin privileges in order to run some legacy apps. So, one of the suggestion was to hide it in task manager. If there are other approaches to prevent users from killing the process, that would be great.

Update2: Removing the reference to rootkit. Somehow made this post look negative.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

南风几经秋 2024-07-13 06:34:01

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

Alternatively, you could write a small "checker" utility that checks if the app is running, if it isn't it automatically starts it. Then add code to the app to check for the "checker" utility that does the same. This way if one is terminated, then the other starts it back up. I've seem virus's do this, and it seems to work pretty effectively.

吃→可爱长大的 2024-07-13 06:34:01

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

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

Write a driver - You can use ObRegisterCallbacks to register process object access notification. Return STATUS_ACCESS_DENIED when DesiredAccess contains access rights you don't like, like process termination, or writing to process memory.

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

成熟稳重的好男人 2024-07-13 06:34:01

如果您只是需要伪装该进程而不是完全隐藏它,您可以将其重命名为winlogon.exe或svchost.exe,它很可能会被用户忽略。 但正如 Sergio 提到的,这种安全性是默默无闻的,而且它的名声不好也是有原因的。

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

If you simply need to disguise the process and not hide it completely, you can rename it winlogon.exe or svchost.exe and it will likely be ignored by users. But as Sergio mentioned, that's security by obscurity and it's got a bad reputation for a reason.

Preventing users from killing a process is another difficulty if they have proper privileges. The only method I know is to have multiple processes that watch each other and restart any watched process which gets killed. Again, this is going down a shady path.

め可乐爱微笑 2024-07-13 06:34:01

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

Not sure why this hasnt been suggested yet but heres my first answer on this site.
instead of preventing the user from killing a process. (Requires rootkit hooking.)
You can simply disable the task manager from being used with a registry input.

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);
}
池木 2024-07-13 06:34:01

没有简单或受支持的方法可以做到这一点。 即使您编写了一个 Rootkit 来执行此操作,也很容易被为填补该漏洞而进行的未来更新所破坏。 我会重新审视这是否是你想做的事情。

There is no easy or supported way to do this. Even if you wrote a rootkit to do it then that could very easily get broken by a future update that was made to plug that hole. I would reexamine whether that is something you want to do.

彻夜缠绵 2024-07-13 06:34:01

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

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

As people mentioned above, the best method is 2 tasks, monitoring each other,
I understand you don't want to waste CPU, so the best way is to establish an event between the tasks which will be triggered when one closes.

I am not entirely sure on how to set up the hook, but then you don't use a while loop which does waste CPU.

半步萧音过轻尘 2024-07-13 06:34:01

很多人可能知道怎么做,但只是不会在这里发布。 在互联网上发布恶意代码是非常危险的。 谁知道你可能会遇到危险。 询问一些计算机工程师。 不过我会给你程序的结构。

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

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

Many people might know how to do it, but just won't post it here. It is very dangerous to post malicious code on the internet. Who knows you might be in danger. Ask some computer engineer. I'll give you the structure of the program though.

Just inject your program's dll into explorer.exe.

Your process won't just show up because it is not running as a program but is being ran in a program (explorer.exe). The user just won't see the process even if he uses any kind of task manager.

夜巴黎 2024-07-13 06:34:01

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

Have you looked at writing a service? This way the service runs as the local system, and the application runs under the user's context, and the service can ensure that things are still done as needed, and the application is just an interface to this service. Killing the application would just result in the user not seeing any notices, system tray icon, etc, but the service is still doing its job.

梦中楼上月下 2024-07-13 06:34:01

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

I saw @Chris Smith answer and I decided to convert it to C#.

Here is the code, taken from here, for a simple Winform application:
C# variation:

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

After running it as a limited user, I can't kill it from the task manager, only as administrator.
I left the X button to be able to close it without an admin but it also possible to remove it.

The result:

enter image description here

Powershell variation:

$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
}
#>
一袭水袖舞倾城 2024-07-13 06:34:01

你只是要求用户不要终止进程怎么样? 对于同一公司员工明显幼稚的行为,你会花多少时间来做这件事。

What about you just ask the user to don't kill the process ? How much time you'll spend doing it, for a behavior that is clearly childish from employees in the same company.

囚你心 2024-07-13 06:34:01

我知道这个问题很旧,但我不久前回答了一个重复的问题,其中包含一些不在这里的好信息,所以我想我会链接到它。 请参阅我对重复问题的回答。此外,如果您的真正目标是阻止用户终止进程,那么我所知道的过去工作起来非常容易,尽管它有点hackish,我不知道这是否仍然有效,只需将您的应用程序命名为lsass.exe,任务管理器甚至不允许管理员用户关闭该进程。 对于这种方法,哪个用户启动该进程或可执行文件驻留在文件系统上的位置并不重要,Windows 似乎只是检查该进程是否被命名为 this,然后不允许其结束。

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

I know this question is old but I answered a duplicate question a while ago that contains some nice information there that isn't here so I thought I'd link to it. See My answer to the duplicate question. Also if your true goal is to stop the users from killing the process then what I know used to work very easily, although it is a bit hackish and I don't know if this still works, is to simply name your application lsass.exe and task manager will not allow even an admin user to close the process. for this method it doesn't matter which user started the process or where the executable resides on the file system, it seems windows just checks to see if the process is named this then do not allow it to be ended.

Update: I just tried to do the lsass.exe trick on windows 7 and it appears to have been fixed, but my guess is it still works on windows xp and maybe even the earlier service packs of the versions beyond xp. Even though this no longer works at the time of this writing I thought I'd include it anyway as a fun fact.

丿*梦醉红颜 2024-07-13 06:34:01

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

to stop the process from being permanently killed, have the first thing the process does is to call 'atexit()' and have the atexit() function start the process

深陷 2024-07-13 06:34:00

不要试图阻止它被杀死——你无法做到这一点。 相反,让它定期调用网络服务。 当网络服务注意到客户端“变得沉默”时,它可以 ping 机器以查看是否只是重新启动问题,并向经理(或任何人)发送电子邮件以对终止该进程的人进行纪律处分。

Don't try to stop it from being killed - you're not going to manage it. Instead, make it regularly call home to a webservice. When the webservice notices a client "going silent" it can ping the machine to see if it's just a reboot issue, and send an email to a manager (or whoever) to discipline whoever has killed the process.

仙气飘飘 2024-07-13 06:34:00

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

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

安全地拦截系统调用非常困难,64 位 Windows 内核会出局他们的方式来防止这种情况发生:尝试修改系统调用表会导致立即蓝屏。 在这些平台上这将非常困难

这个索尼 DRM 软件 是一个 rootkit 的示例,它试图执行类似的操作(并且有几个严重的问题) )。

There is no supported way to accomplish this. The process list can be read at any privilege level. If you were hoping to hide a process from even Administrators, then this is doubly unsupported.

To get this to work, you would need to write a kernel mode rootkit to intercept calls to NtQuerySystemInformation so that the SystemProcessInformation info class fails to list your hidden process.

Intercepting system calls is very difficult to do safely, and the 64 bit Windows kernels go out of their way to prevent this from being possible: trying to modify the syscall table results in an instant blue screen. It's going to be very difficult on those platforms

This Sony DRM software is an example of a rootkit that tries to do something similar (and has several serious problems).

掩饰不了的爱 2024-07-13 06:34:00

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

If you want to prevent users from killing the process from task manager, you can just use a security descriptor on the process to deny terminate access to everyone. Administrators technically can still kill the process by taking ownership of the process and resetting the DACL, but there is no interface to do either of these things from Task Manager. Process Explorer may have an interface to though.

When your process starts, use SetKernelObjectSecurity with DACL_SECURITY_INFORMATION using the current process handle. Set a DACL with zero ACLs. This will deny all access to everyone, including those trying to end your process with task manager.

Here is an example that also changes the process's owner:

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

Unfortunately, it doesn't seem to be effective. I can still close the process (although not as a limited user). Perhaps Task Manager is taking ownership or invoking some other privilege to kill the process? I seem to remember this working in previous versions of Windows (I was testing 2003), but I could be mistaken.

深巷少女 2024-07-13 06:34:00

我希望你不能。

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

I hope that you would not be able to.

Update: given the scenario, I think that you will probably be best off running it under a different admin account. That may help alert people to the fact that they should not kill the process.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文