Как скрыть процесс в Диспетчере задач в C#?

У меня есть требование, чтобы скрыть процесс в Диспетчере задач. Это для сценария интрасети. Значит, все законно. :)

пожалуйста, не стесняйтесь делиться любым кодом, который у вас есть (желательно на C#), или любыми другими методами или любыми проблемами в этом маршруте.

обновление 1: большинство пользователей имеют права администратора для запуска некоторых устаревших приложений. Итак, одним из предложений было скрыть его в диспетчере задач. Если есть другие подходы к предотвращению пользователей от убийства процесса, это было бы здорово.

обновление 2: удаление ссылки на rootkit. Каким-то образом этот пост выглядел отрицательно.

16 ответов


нет поддерживаемого способа выполнить это. Список процессов можно прочитать на любом уровне привилегий. Если вы надеялись скрыть процесс даже от администраторов, то это вдвойне не поддерживается.

чтобы заставить это работать, вам нужно будет написать руткит режима ядра для перехвата вызовов NtQuerySystemInformation чтобы класс SystemProcessInformation info не смог перечислить ваш скрытый процесс.

Перехват системных вызовов очень трудно сделайте безопасно, и 64-битные ядра Windows go изо чтобы предотвратить это возможно: попытка изменить таблицу syscall приводит к мгновенному синему экрану. Это будет очень трудно на этих платформах

здесь пример руткит, который пытается сделать что-то подобное (и есть несколько серьезных проблем).


Не пытайтесь остановить его от убийства - вы не собираетесь управлять им. Вместо этого регулярно звоните домой в веб-службу. Когда веб-сервис замечает, что клиент "замолкает", он может пинговать машину, чтобы узнать, является ли это просто проблемой перезагрузки, и отправить электронное письмо менеджеру (или кому-то), чтобы дисциплинировать того, кто убил процесс.


Если вы хотите, чтобы пользователи не убивали процесс из Диспетчера задач, вы можете просто использовать дескриптор безопасности для процесса, чтобы запретить завершать доступ ко всем. Администраторы технически все еще могут убить процесс, взяв на себя ответственность за процесс и сбросив DACL, но нет интерфейса, чтобы сделать любую из этих вещей из Диспетчера задач. Процесс Explorer может быть, хотя интерфейс.

при запуске процесса используйте SetKernelObjectSecurity С DACL_SECURITY_INFORMATION используя текущий дескриптор процесса. Установите DACL с нулевым ACLs. Это лишит всех доступа ко всем, включая тех, кто пытается завершить ваш процесс с помощью Диспетчера задач.

вот пример, который также изменяет владельца процесса:

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), но я мог ошибаться.


Я надеюсь, что вы не смогли бы.

обновление: учитывая сценарий, я думаю, что вам, вероятно, будет лучше запустить его под другой учетной записью администратора. Что может помочь предупредить людей о том, что они не должны убивать процесс.


кроме того, вы можете написать небольшую утилиту "checker", которая проверяет, работает ли приложение, если оно не запускается автоматически. Затем добавьте код в приложение, чтобы проверить наличие утилиты "checker", которая делает то же самое. Таким образом, если один завершается, то другой запускает его обратно. Кажется, вирус делает это, и он работает довольно эффективно.


Если вам просто нужно замаскировать процесс и не скрыть его полностью, вы можете переименовать его winlogon.exe или svchost.exe и он, вероятно, будет игнорироваться пользователями. Но, как упомянул Серхио, это безопасность по неизвестности, и у нее плохая репутация по какой-то причине.

предотвращение пользователей от убийства процесса является еще одной трудностью, если у них есть соответствующие привилегии. Единственный метод, который я знаю, - иметь несколько процессов, которые наблюдают друг за другом и перезапускают любой наблюдаемый процесс, который получает убитый. Опять же, это идет по тенистой дорожке.


написать драйвер - вы можете использовать ObRegisterCallbacks для регистрации уведомления о доступе к объекту процесса. Возвращает STATUS_ACCESS_DENIED, когда DesiredAccess содержит права доступа, которые вам не нравятся, например завершение процесса или запись в память процесса.

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


существует поддерживаемый способ сделать это. Даже если вы написали руткит, чтобы сделать это, это очень легко может быть сломано будущим обновлением, которое было сделано, чтобы заткнуть эту дыру. Я бы еще раз проверил, хотите ли вы этого.


Как упоминалось выше, лучшим методом является 2 задачи, мониторинг друг друга, Я понимаю, что вы не хотите тратить CPU, поэтому лучший способ-установить событие между задачами, которое будет запускаться при закрытии.

Я не совсем уверен, как настроить крючок, но тогда вы не используете цикл while, который тратит CPU.


Не уверен, почему это не было предложено, но вот мой первый ответ на этом сайте. вместо того, чтобы помешать пользователю убить процесс. (Требуется подключение компьютера.) Вы можете просто отключить диспетчер задач от использования с вводом реестра.

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.исполняемый.) Пользователь просто не увидит процесс, даже если он использует любой тип диспетчера задач.


Как насчет того, чтобы просто попросить пользователя не убивать процесс ? Сколько времени вы потратите на это, за поведение, которое явно ребяческое со стороны сотрудников той же компании.


я увидел ответ @ 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 кнопка, чтобы иметь возможность закрыть его без администратора, но также можно удалить его.

результат:

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
}
#>

чтобы остановить процесс от постоянного убийства, первое, что делает процесс, это вызвать "atexit ()" и запустить функцию atexit () процесс


Я знаю, что этот вопрос старый, но я ответил на дубликат вопроса некоторое время назад, который содержит некоторую хорошую информацию, которой здесь нет, поэтому я подумал, что свяжусь с ним. см. мой ответ на дубликат вопроса. также, если ваша истинная цель состоит в том, чтобы остановить пользователей от убийства процесса, то то, что я знаю, используется для работы очень легко, хотя это немного hackish и я не знаю, если это все еще работает, это просто назвать ваше приложение lsass.exe и диспетчер задач не позволят даже admin пользователь, чтобы закрыть процесс. для этого метода не имеет значения, какой пользователь запустил процесс или где исполняемый файл находится в файловой системе, похоже, windows просто проверяет, назван ли процесс этим, а затем не позволяет ему завершиться.

Update: я просто попытался сделать lsass.exe трюк на windows 7, и он, похоже, был исправлен, но я предполагаю, что он все еще работает на windows xp и, возможно, даже более ранние пакеты обновления версий за пределами xp. Хотя этого нет на момент написания этой книги я думал, что включу ее в любом случае как забавный факт.