Come nascondo un processo in Task Manager in C #?

Ho il requisito di hide un processo in Task Manager. È per lo scenario Intranet. Quindi, tutto è legittimo. 🙂

Sentiti libero di condividere qualsiasi codice che possiedi (preferibilmente in C #) o qualsiasi altra tecnica o problema con questo percorso.

Update1 : la maggior parte degli utenti ha i privilegi di amministratore per poter eseguire alcune app legacy. Quindi, uno dei suggerimenti era nasconderlo nel task manager. Se ci sono altri approcci per impedire agli utenti di uccidere il processo, sarebbe grandioso.

Update2 : rimozione del riferimento a rootkit. In qualche modo ha reso questo post un aspetto negativo.

Non c’è un modo supportato per realizzare questo. L’elenco dei processi può essere letto a qualsiasi livello di privilegio. Se speravi di hide un processo anche agli amministratori, questo è doppiamente non supportato.

Per farlo funzionare, è necessario scrivere un rootkit in modalità kernel per intercettare le chiamate a NtQuerySystemInformation in modo che la class di informazioni SystemProcessInformation non riesca a elencare il processo nascosto.

Intercettare le chiamate di sistema è molto difficile da fare in sicurezza, ei kernel Windows a 64 bit fanno di tutto per impedire che ciò sia ansible: provare a modificare i risultati della tabella syscall in una schermata blu istantanea. Sarà molto difficile su quelle piattaforms

Ecco un esempio di un rootkit che tenta di fare qualcosa di simile (e ha diversi seri problemi).

Non cercare di impedire che venga ucciso: non lo gestirai. Invece, falla chiamare regolarmente a casa su un webservice. Quando il webservice rileva che un client “sta zitto”, può eseguire il ping della macchina per vedere se si tratta solo di un problema di riavvio e inviare una e-mail a un manager (oa chiunque) per disciplinare chi ha ucciso il processo.

Se si desidera impedire agli utenti di uccidere il processo da Task Manager, è sufficiente utilizzare un descrittore di sicurezza sul processo per negare l’accesso a tutti. Gli amministratori tecnicamente possono ancora uccidere il processo assumendo la proprietà del processo e reimpostando il DACL, ma non c’è alcuna interfaccia per fare una di queste cose da Task Manager. Process Explorer può avere un’interfaccia per se.

All’avvio del processo, utilizzare SetKernelObjectSecurity con DACL_SECURITY_INFORMATION utilizzando l’handle del processo corrente. Impostare un DACL con zero ACL. Ciò negherà l’accesso a tutti, compresi quelli che cercano di terminare il processo con il task manager.

Ecco un esempio che cambia anche il proprietario del processo:

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

Sfortunatamente, non sembra essere efficace. Posso ancora chiudere il processo (anche se non come utente limitato). Forse Task Manager sta assumendo la proprietà o invocando qualche altro privilegio per uccidere il processo? Mi sembra di ricordare questo lavoro nelle versioni precedenti di Windows (stavo testando il 2003), ma potrei sbagliarmi.

Spero che tu non sia in grado di farlo.

Aggiornamento: dato lo scenario, penso che sarà probabilmente meglio eseguirlo con un account amministratore diverso. Questo può aiutare ad avvisare le persone del fatto che non dovrebbero uccidere il processo.

In alternativa, è ansible scrivere una piccola utility “checker” che controlla se l’app è in esecuzione, se non lo avvia automaticamente. Quindi aggiungi il codice all’app per controllare l’utilità “checker” che fa lo stesso. In questo modo, se uno è terminato, l’altro lo riavvia. Sembra che i virus lo facciano e sembra funzionare in modo abbastanza efficace.

Se hai semplicemente bisogno di camuffare il processo e non nasconderlo completamente, puoi rinominarlo winlogon.exe o svchost.exe e sarà probabilmente ignorato dagli utenti. Ma come ha detto Sergio, questa è sicurezza per oscurità e ha una ctriggers reputazione per un motivo.

Impedire agli utenti di uccidere un processo è un’altra difficoltà se hanno i privilegi appropriati. L’unico metodo che conosco è di avere più processi che si guardano l’un l’altro e ricominciano qualsiasi processo visto che viene ucciso. Di nuovo, questo sta andando giù per un sentiero ombroso.

Non esiste un modo facile o supportato per farlo. Anche se hai scritto un rootkit per farlo, questo potrebbe facilmente essere rotto da un aggiornamento futuro che è stato fatto per tappare quel buco. Vorrei riesaminare se è qualcosa che vuoi fare.

Come menzionato sopra, il metodo migliore è 2 attività, monitorandoci a vicenda, capisco che non vuoi sprecare CPU, quindi il modo migliore è stabilire un evento tra le attività che verranno triggerste alla chiusura.

Non sono del tutto sicuro su come impostare l’hook, ma non si utilizza un ciclo while che spreca CPU.

Scrittura di un driver: è ansible utilizzare ObRegisterCallbacks per registrare la notifica di accesso agli oggetti del processo. Restituisci STATUS_ACCESS_DENIED quando DesiredAccess contiene diritti di accesso che non ti piacciono, come la terminazione del processo o la scrittura per elaborare la memoria.

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

Non so perché questo non è stato ancora suggerito ma è la mia prima risposta su questo sito. invece di impedire all’utente di uccidere un processo. (Richiede l’hooking del rootkit.) È ansible semplicemente disabilitare il task manager dall’uso con un input del registro.

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

Hai guardato a scrivere un servizio? In questo modo il servizio viene eseguito come sistema locale e l’applicazione viene eseguita nel contesto dell’utente e il servizio può garantire che le attività vengano comunque eseguite in base alle esigenze e che l’applicazione sia solo un’interfaccia per questo servizio. Uccidere l’applicazione comporterebbe semplicemente che l’utente non vedesse alcuna notifica, icona nella barra delle applicazioni, ecc., Ma il servizio sta ancora facendo il suo lavoro.

Molte persone potrebbero sapere come farlo, ma semplicemente non lo pubblicheranno qui. È molto pericoloso pubblicare codice dannoso su Internet. Chi sa che potresti essere in pericolo. Chiedi un po ‘di ingegnere informatico. Ti darò la struttura del programma però.

Basta iniettare la DLL del programma in explorer.exe.

Il tuo processo non verrà visualizzato solo perché non è in esecuzione come un programma ma viene eseguito in un programma (explorer.exe). L’utente non vedrà il processo anche se utilizza qualsiasi tipo di task manager.

Che ne dici di chiedere all’utente di non uccidere il processo? Quanto tempo dedichi a farlo, per un comportamento chiaramente infantile da parte dei dipendenti della stessa azienda.

Ho visto la risposta di @ Chrisis Smith e ho deciso di convertirla in C #.

Ecco il codice, preso da qui , per una semplice applicazione Winform:
Variazione 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); } } } 

Dopo averlo eseguito come utente limitato, non posso ucciderlo dal task manager, solo come amministratore.
Ho lasciato il pulsante X per poterlo chiudere senza un amministratore ma è anche ansible rimuoverlo.

Il risultato:

inserisci la descrizione dell'immagine qui

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

per impedire che il processo venga definitivamente ucciso, la prima cosa che fa il processo è chiamare ‘atexit ()’ e fare in modo che la funzione atexit () avvii il processo

So che questa domanda è vecchia ma ho risposto a una domanda doppia di qualche tempo fa che contiene alcune belle informazioni che non sono qui, quindi ho pensato di collegarmi ad essa. Vedi la mia risposta alla domanda duplicata. Inoltre, se il tuo vero objective è impedire agli utenti di uccidere il processo, quello che so funzionava molto facilmente, anche se è un po ‘hacker e non so se funziona ancora, è semplicemente dare un nome all’applicazione lsass.exe e il task manager non consente nemmeno a un utente amministratore di chiudere il processo. per questo metodo non importa quale utente abbia avviato il processo o dove l’eseguibile risiede nel file system, sembra che Windows controlli solo per vedere se il processo è chiamato così, quindi non permettere che sia terminato.

Aggiornamento: Ho appena provato a eseguire il trucco lsass.exe su Windows 7 e sembra che sia stato corretto, ma credo che funzioni ancora su Windows XP e forse anche sui precedenti Service Pack delle versioni oltre xp. Anche se questo non funziona più al momento in cui scrivo, ho pensato di includerlo comunque come un fatto divertente.