web-dev-qa-db-fra.com

Comment masquer un processus dans le gestionnaire de tâches en C #?

J'ai l'obligation de masquer un processus dans le gestionnaire de tâches. C'est pour le scénario Intranet. Donc, tout est légitime. :) 

N'hésitez pas à partager votre code (de préférence en C #) ou toute autre technique ou tout problème lié à cet itinéraire.

Update1 : La plupart des utilisateurs disposent de privilèges administrateur pour exécuter certaines applications héritées. Une des suggestions était donc de le cacher dans le gestionnaire de tâches. S'il existe d'autres approches pour empêcher les utilisateurs de tuer le processus, ce serait formidable.

Update2 : Suppression de la référence au rootkit. D'une certaine manière, ce message a l'air négatif.

32
Gulzar Nazim

Il n'y a pas de moyen supporté pour accomplir cela. La liste de processus peut être lue à n'importe quel niveau de privilège. Si vous espériez cacher un processus même aux administrateurs, il est doublement non pris en charge.

Pour que cela fonctionne, vous devez écrire un rootkit en mode noyau pour intercepter les appels à NtQuerySystemInformation afin que la classe d'informations SystemProcessInformation ne puisse pas répertorier votre processus masqué.

Intercepter les appels système est très difficile à effectuer en toute sécurité, et les noyaux Windows 64 bits passent hors de leur chemin _ pour éviter que cela ne soit possible: essayer de modifier la table syscall entraîne un écran bleu instantané. Ça va être très difficile sur ces plateformes

_ { Here } est un exemple de rootkit qui tente de faire quelque chose de similaire (et qui présente plusieurs problèmes graves).

45
Chris Smith

N'essayez pas de l'empêcher de se faire tuer - vous ne pourrez pas le gérer. Faites-le plutôt appeler régulièrement votre service Web chez vous. Lorsque le service Web remarque qu'un client "devient silencieux", il peut envoyer une requête ping à la machine pour savoir s'il s'agit simplement d'un problème de redémarrage et envoyer un courrier électronique à un responsable (ou à quiconque) pour discipliner quiconque a tué le processus.

68
Jon Skeet

Si vous souhaitez empêcher les utilisateurs de tuer le processus à partir du gestionnaire de tâches, vous pouvez simplement utiliser un descripteur de sécurité sur le processus pour refuser l'accès final à tout le monde. Techniquement, les administrateurs peuvent toujours arrêter le processus en s'appropriant le processus et en réinitialisant la liste DACL, mais il n'existe aucune interface pour effectuer ces opérations à partir du Gestionnaire des tâches. Process Explorer peut avoir une interface avec cependant.

Lorsque votre processus démarre, utilisez SetKernelObjectSecurity avec DACL_SECURITY_INFORMATION à l'aide du descripteur de processus actuel. Définissez une liste DACL avec zéro ACL. Cela refusera tout accès à tout le monde, y compris à ceux qui essaient de mettre fin à votre processus avec le gestionnaire de tâches.

Voici un exemple qui change également le propriétaire du processus:

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

Malheureusement, cela ne semble pas être efficace. Je peux toujours fermer le processus (mais pas en tant qu'utilisateur limité). Peut-être que le Gestionnaire des tâches est en train de s’approprier ou d’invoquer un autre privilège pour tuer le processus? Je semble me souvenir que cela fonctionnait dans les versions précédentes de Windows (je testais 2003), mais je peux me tromper.

18
Chris Smith

J'espère que vous ne pourrez pas.

Mise à jour: / Étant donné le scénario, je pense que vous feriez mieux de l’exécuter sous un autre compte administrateur. Cela peut aider à alerter les gens sur le fait qu’ils ne devraient pas tuer le processus.

10
Marcin

Alternativement, vous pouvez écrire un petit utilitaire "vérificateur" qui vérifie si l'application est en cours d'exécution, sinon elle le démarre automatiquement. Ajoutez ensuite du code à l'application pour vérifier que l'utilitaire "vérificateur" fait de même. De cette façon, si l’un s’arrête, l’autre le redémarre. J'ai l'impression que les virus le font, et cela semble fonctionner assez efficacement.

6

Je ne sais pas pourquoi cela n’a pas encore été suggéré, mais voici ma première réponse sur ce site ... au lieu d’empêcher l’utilisateur de tuer un processus. (Nécessite l'installation d'un rootkit.) Vous pouvez simplement désactiver l'utilisation du gestionnaire de tâches avec une entrée de registre.

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

Écrire un pilote - Vous pouvez utiliser ObRegisterCallbacks pour enregistrer la notification d'accès aux objets de processus. Renvoie STATUS_ACCESS_DENIED lorsque DesiredAccess contient des droits d'accès que vous n'aimez pas, tels que l'arrêt du processus ou l'écriture dans la mémoire de processus. 

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

4
Uriel G.

Si vous avez simplement besoin de dissimuler le processus et de ne pas le cacher complètement, vous pouvez le renommer winlogon.exe ou svchost.exe et il sera probablement ignoré des utilisateurs. Mais comme l'a mentionné Sergio, la sécurité est obscure et sa réputation n'est pas bonne.

Empêcher les utilisateurs de tuer un processus est une autre difficulté s'ils disposent des privilèges appropriés. La seule méthode que je connaisse consiste à avoir plusieurs processus qui se surveillent et à redémarrer tout processus surveillé qui est tué. Encore une fois, cela suit un chemin louche.

4
Ben Hoffstein

Il n'y a pas de moyen facile ou supporté de le faire. Même si vous aviez écrit un rootkit pour le faire, cela pourrait très facilement être détruit par une future mise à jour destinée à boucher ce trou. Je voudrais réexaminer si c'est quelque chose que vous voulez faire.

3
StubbornMule

Comme mentionné ci-dessus, la meilleure méthode consiste à utiliser deux tâches, se surveillant mutuellement, .__ Je comprends que vous ne voulez pas gaspiller le processeur, le meilleur moyen consiste donc à établir un événement entre les tâches qui seront déclenchées à la fermeture.

Je ne suis pas tout à fait sûr de la configuration du hook, mais vous n'utilisez pas de boucle while qui gaspille le processeur.

3
eitama

Avez-vous envisagé d'écrire un service? De cette façon, le service s'exécute en tant que système local et l'application s'exécute dans le contexte de l'utilisateur. Le service peut ainsi s'assurer que les tâches sont toujours exécutées en fonction des besoins, et l'application n'est qu'une interface pour ce service. Si vous tuez l'application, l'utilisateur ne verra plus aucun avis, icône de la barre d'état système, etc., mais le service continuera à faire son travail.

2
Rick

Beaucoup de gens savent peut-être le faire, mais ne le publieront pas ici. Il est très dangereux de poster du code malveillant sur Internet. Qui sait que vous pourriez être en danger. Demandez à un ingénieur en informatique. Je vous donnerai cependant la structure du programme.

Il suffit d’injecter la DLL de votre programme dans Explorer.exe.

Votre processus ne s'affichera pas simplement car il ne s'exécute pas en tant que programme, mais dans un programme (Explorer.exe). L'utilisateur ne verra tout simplement pas le processus, même s'il utilise un gestionnaire de tâches quelconque.

2
ABCDWHAT

J'ai vu @Chris Smith répondre et j'ai décidé de le convertir en C #. 

Voici le code, extrait de ici , pour une application Winform simple:
Variation 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);
        }
    }
}

Après l'avoir exécuté en tant qu'utilisateur limité, je ne peux pas le supprimer à partir du gestionnaire de tâches, uniquement en tant qu'administrateur.
J'ai laissé le bouton X pour pouvoir le fermer sans un administrateur mais il est également possible de le supprimer. 

Le résultat: 

 enter image description here

Variation 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
}
#>
1
E235

Et si vous demandiez simplement à l'utilisateur de ne pas tuer le processus? Combien de temps passerez-vous à le faire, pour un comportement clairement enfantin de la part des employés de la même entreprise.

1
pmlarocque

Je sais que cette question est ancienne, mais j’ai répondu à une question en double il y a un moment, qui contient des informations intéressantes qui n’y figurent pas ici; j’ai donc pensé à créer un lien vers celle-ci. Voir ma réponse à la question en double. De plus, si votre véritable objectif est d'empêcher les utilisateurs de tuer le processus, alors ce que je savais fonctionnait très facilement, bien que ce soit un peu fictif et que je ne sache pas si cela fonctionne toujours, est simplement de nommer votre application lsass .exe et le gestionnaire de tâches ne permettront même pas à un utilisateur administrateur de fermer le processus. pour cette méthode, quel que soit l'utilisateur qui a lancé le processus ou l'emplacement de l'exécutable sur le système de fichiers, il semble que Windows vérifie simplement si le processus est nommé, puis ne le permet pas.

Mise à jour: je viens d'essayer de faire le tour de lsass.exe sur Windows 7 et il semble avoir été corrigé, mais je suppose que cela fonctionne toujours sur Windows XP et peut-être même sur les anciens Service Packs des versions situées au-delà de xp. Même si cela ne fonctionne plus au moment d'écrire ces lignes, j'ai pensé l'inclure de toute façon comme un fait amusant.

0
MitchellKrenz

pour empêcher le processus d'être définitivement tué, la première chose à faire est d'appeler 'atexit ()' et de faire démarrer la fonction atexit ()

0
user3629249