├── diehard.jpg ├── screen.png ├── Alpha ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── Alpha.csproj ├── Bravo ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── Bravo.csproj ├── Charlie ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── Charlie.csproj ├── ProtectProcess ├── ProtectProcess.projitems ├── ProtectProcess.shproj ├── WMI.cs ├── ProcessExtensions.cs ├── DieHard.cs └── StripPermissions.cs ├── README.md └── DieHard.sln /diehard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malcomvetter/DieHard/HEAD/diehard.jpg -------------------------------------------------------------------------------- /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malcomvetter/DieHard/HEAD/screen.png -------------------------------------------------------------------------------- /Alpha/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Alpha 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | Console.WriteLine("Hello from alpha."); 11 | ProtectProcess.DieHard.DeploySgtAlPowell("bravo"); 12 | do 13 | { 14 | Thread.Sleep(500000); 15 | } while (true); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Bravo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Bravo 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | Console.WriteLine("Hello from bravo."); 11 | ProtectProcess.DieHard.DeploySgtAlPowell("alpha"); 12 | do 13 | { 14 | Thread.Sleep(500000); 15 | } while (true); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Charlie/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Charlie 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | Console.WriteLine("Hello from charlie."); 11 | new Thread(DoMainWork) { IsBackground = true, Name = "Die Hard with a Vengeance" }.Start(); 12 | ProtectProcess.DieHard.IAmJohnMcClane(); 13 | } 14 | 15 | static void DoMainWork() 16 | { 17 | using (var handle = new EventWaitHandle(false, EventResetMode.AutoReset, "Live Free or Die Hard")) 18 | { 19 | if (handle.WaitOne()) 20 | { 21 | Console.WriteLine("Welcome to the party, pal."); 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ProtectProcess/ProtectProcess.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | 30291995-7907-4be4-ae13-f17daedbf420 7 | 8 | 9 | ProtectProcess 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DIE HARD(er)! 2 | 3 | Build in Visual Studio (.net 3.5 so it runs on Win 7+). 4 | 5 | This is a proof of concept, example project that shows two patterns for how to protect userland processes on Windows written in C#: 6 | * Alpha watches Bravo - two binaries watching each other 7 | * Charlie watching itself - a single binary that spawns another instance of itself and watches the other instance 8 | 9 | ![screenshot](screen.png) 10 | 11 | Both cases will respawn their twin process if they observe it dying. All spawns are passed through WMI to "launder" the parent process (making kill process tree a little more difficult since you have to kill the WMI process as well). 12 | 13 | These are PROOF OF CONCEPT only. They're not perfect, but they're certainly a nuisance. 14 | 15 | Oh, and there are plenty of DIE HARD references for Bruce Willis fans. 16 | 17 | ![logo](diehard.jpg) 18 | 19 | -------------------------------------------------------------------------------- /ProtectProcess/ProtectProcess.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 30291995-7907-4be4-ae13-f17daedbf420 5 | 14.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ProtectProcess/WMI.cs: -------------------------------------------------------------------------------- 1 | using System.Management; 2 | 3 | namespace ProtectProcess 4 | { 5 | public class WMI 6 | { 7 | public static void Run(object executable) 8 | { 9 | Run(executable as string); 10 | } 11 | public static string Run(string executable) 12 | { 13 | return Run("localhost", executable); 14 | } 15 | public static string Run(string host, string executable) 16 | { 17 | var scope = new ManagementScope(@"\\" + host + @"\root\CIMV2"); 18 | var path = new ManagementPath("Win32_Process"); 19 | var classInstance = new ManagementClass(scope, path, null); 20 | var startupSettings = new ManagementClass("Win32_ProcessStartup"); 21 | startupSettings.Scope = scope; 22 | startupSettings["CreateFlags"] = 16777216; 23 | var inParams = classInstance.GetMethodParameters("Create"); 24 | inParams["CommandLine"] = executable; 25 | inParams["ProcessStartupInformation"] = startupSettings; 26 | var outParams = classInstance.InvokeMethod("Create", inParams, null); 27 | var result = outParams["ReturnValue"].ToString(); 28 | return result; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ProtectProcess/ProcessExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Collections.Generic; 3 | 4 | namespace Gemini 5 | { 6 | public static class ProcessExtensions 7 | { 8 | private static string FindIndexedProcessName(int pid) 9 | { 10 | var processName = Process.GetProcessById(pid).ProcessName; 11 | var processesByName = Process.GetProcessesByName(processName); 12 | string processIndexdName = null; 13 | 14 | for (var index = 0; index < processesByName.Length; index++) 15 | { 16 | processIndexdName = index == 0 ? processName : processName + "#" + index; 17 | var processId = new PerformanceCounter("Process", "ID Process", processIndexdName); 18 | if ((int)processId.NextValue() == pid) 19 | { 20 | return processIndexdName; 21 | } 22 | } 23 | 24 | return processIndexdName; 25 | } 26 | 27 | private static Process FindPidFromIndexedProcessName(string indexedProcessName) 28 | { 29 | var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName); 30 | return Process.GetProcessById((int)parentId.NextValue()); 31 | } 32 | 33 | public static Process Parent(this Process process) 34 | { 35 | return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Alpha/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Alpha")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Alpha")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c396b2f5-cd26-4f3c-bfd1-47ea57fce3d7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Bravo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Bravo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Bravo")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("14e722f0-e9ca-45f1-a3f1-0aa7d119173e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Charlie/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Charlie")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Charlie")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b577166b-211c-44d6-b63a-2bc6700caadd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Alpha/Alpha.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C396B2F5-CD26-4F3C-BFD1-47EA57FCE3D7} 8 | Exe 9 | Alpha 10 | Alpha 11 | v3.5 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Bravo/Bravo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {14E722F0-E9CA-45F1-A3F1-0AA7D119173E} 8 | Exe 9 | Bravo 10 | Bravo 11 | v3.5 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Charlie/Charlie.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B577166B-211C-44D6-B63A-2BC6700CAADD} 8 | Exe 9 | Charlie 10 | Charlie 11 | v3.5 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /DieHard.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2035 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "ProtectProcess", "ProtectProcess\ProtectProcess.shproj", "{30291995-7907-4BE4-AE13-F17DAEDBF420}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alpha", "Alpha\Alpha.csproj", "{C396B2F5-CD26-4F3C-BFD1-47EA57FCE3D7}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bravo", "Bravo\Bravo.csproj", "{14E722F0-E9CA-45F1-A3F1-0AA7D119173E}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Charlie", "Charlie\Charlie.csproj", "{B577166B-211C-44D6-B63A-2BC6700CAADD}" 13 | EndProject 14 | Global 15 | GlobalSection(SharedMSBuildProjectFiles) = preSolution 16 | ProtectProcess\ProtectProcess.projitems*{14e722f0-e9ca-45f1-a3f1-0aa7d119173e}*SharedItemsImports = 4 17 | ProtectProcess\ProtectProcess.projitems*{30291995-7907-4be4-ae13-f17daedbf420}*SharedItemsImports = 13 18 | ProtectProcess\ProtectProcess.projitems*{b577166b-211c-44d6-b63a-2bc6700caadd}*SharedItemsImports = 4 19 | ProtectProcess\ProtectProcess.projitems*{c396b2f5-cd26-4f3c-bfd1-47ea57fce3d7}*SharedItemsImports = 4 20 | EndGlobalSection 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Any CPU = Debug|Any CPU 23 | Release|Any CPU = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {C396B2F5-CD26-4F3C-BFD1-47EA57FCE3D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {C396B2F5-CD26-4F3C-BFD1-47EA57FCE3D7}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {C396B2F5-CD26-4F3C-BFD1-47EA57FCE3D7}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {C396B2F5-CD26-4F3C-BFD1-47EA57FCE3D7}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {14E722F0-E9CA-45F1-A3F1-0AA7D119173E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {14E722F0-E9CA-45F1-A3F1-0AA7D119173E}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {14E722F0-E9CA-45F1-A3F1-0AA7D119173E}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {14E722F0-E9CA-45F1-A3F1-0AA7D119173E}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {B577166B-211C-44D6-B63A-2BC6700CAADD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {B577166B-211C-44D6-B63A-2BC6700CAADD}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {B577166B-211C-44D6-B63A-2BC6700CAADD}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {B577166B-211C-44D6-B63A-2BC6700CAADD}.Release|Any CPU.Build.0 = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {6538ED5A-9C03-4590-89C5-C919380E899E} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /ProtectProcess/DieHard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading; 6 | 7 | namespace ProtectProcess 8 | { 9 | public static class DieHard 10 | { 11 | private static List MonitoredPIDs = new List(); 12 | private const string _threadName = "Now I have a machine gun, ho ho ho"; 13 | private static EventWaitHandle _waitHandle = new AutoResetEvent(false); 14 | private static int _sleep = 100; 15 | private const int _max = 2; 16 | 17 | public static void DeploySgtAlPowell(string processName) 18 | { 19 | var self = Process.GetCurrentProcess(); 20 | do 21 | { 22 | Console.WriteLine("{0} ({1}) searching for processes named {2}", self.ProcessName, self.Id, processName); 23 | var targets = Process.GetProcessesByName(processName); 24 | foreach (var target in targets) 25 | { 26 | if (MonitoredPIDs.Contains(target.Id)) 27 | { 28 | continue; 29 | } 30 | new Thread(Nakatomi) { IsBackground = true, Name = _threadName }.Start(target); 31 | _waitHandle.WaitOne(); 32 | MonitoredPIDs.Add(target.Id); 33 | } 34 | Thread.Sleep(_sleep); 35 | } 36 | while (true); 37 | } 38 | 39 | public static void IAmJohnMcClane() 40 | { 41 | Console.WriteLine("Was always kinda partial to Roy Rogers actually."); 42 | var self = Process.GetCurrentProcess(); 43 | do 44 | { 45 | var processes = new Process[0]; 46 | try 47 | { 48 | using (var mutex = new Mutex(false, "Die Hard with a Vengeance")) 49 | { 50 | if (mutex.WaitOne()) 51 | { 52 | processes = Process.GetProcessesByName(self.ProcessName); 53 | } 54 | } 55 | } catch (AbandonedMutexException) { } 56 | if (processes.Count() == 1) 57 | { 58 | Console.WriteLine("Die Hard " + DateTime.Now); 59 | var exec = self.MainModule.FileName; 60 | new Thread(Spawn) { IsBackground = true, Name = _threadName }.Start(exec); 61 | Console.WriteLine("Yippee-ki-yay!"); 62 | } 63 | if (processes.Count() > _max) 64 | { 65 | try 66 | { 67 | using (var mutex = new Mutex(false, "Die Hard with a Vengeance")) 68 | { 69 | if (mutex.WaitOne(TimeSpan.FromSeconds(2), false)) 70 | { 71 | Console.WriteLine("Too many instances, dying."); 72 | Process.GetCurrentProcess().Kill(); 73 | } 74 | } 75 | } catch (AbandonedMutexException) { } 76 | } 77 | if (processes.Count() > 1) 78 | { 79 | Console.WriteLine("Die Harder " + DateTime.Now); 80 | foreach (var process in processes) 81 | { 82 | if (process.Id != self.Id && !MonitoredPIDs.Contains(process.Id)) 83 | { 84 | new Thread(Nakatomi) { IsBackground = true, Name = _threadName }.Start(process); 85 | MonitoredPIDs.Add(process.Id); 86 | } 87 | } 88 | } 89 | Thread.Sleep(_sleep); 90 | } while (true); 91 | } 92 | 93 | private static void StripPermissions() 94 | { 95 | new Thread(Permissions.Strip) { IsBackground = true, Name = _threadName }.Start(); 96 | } 97 | 98 | static void Nakatomi(object process) 99 | { 100 | try 101 | { 102 | Console.WriteLine(_threadName); 103 | var self = Process.GetCurrentProcess(); 104 | var proc = (Process)process; 105 | var exec = proc.MainModule.FileName; 106 | Console.WriteLine("{0} ({1}) watching for {2} ({3}) to die", self.ProcessName, self.Id, proc.ProcessName, proc.Id); 107 | proc.WaitForExit(); 108 | Spawn(exec); 109 | _waitHandle.Set(); 110 | } catch { } 111 | } 112 | 113 | static void Spawn (object exec) 114 | { 115 | Spawn(exec as string); 116 | } 117 | 118 | static void Spawn (string exec) 119 | { 120 | Console.WriteLine("Hey Roy, how you feeling?"); 121 | try 122 | { 123 | using (var mutex = new Mutex(false, "Die Hard with a Vengeance")) 124 | { 125 | if (!mutex.WaitOne(TimeSpan.FromSeconds(2), false)) 126 | { 127 | return; 128 | } 129 | else 130 | { 131 | var processes = Process.GetProcessesByName(exec); 132 | new Thread(WMI.Run) { IsBackground = true, Name = _threadName }.Start(exec); 133 | Thread.Sleep(_sleep); 134 | Console.WriteLine("Pretty unappreciated, Al."); 135 | } 136 | } 137 | } catch (AbandonedMutexException) { } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /ProtectProcess/StripPermissions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Security.AccessControl; 4 | using System.ComponentModel; 5 | using System.Security.Principal; 6 | 7 | namespace ProtectProcess 8 | { 9 | public static class Permissions 10 | { 11 | //inspired from here: http://csharptest.net/1043/how-to-prevent-users-from-killing-your-service-process/index.html 12 | public static void Strip() 13 | { 14 | // Get the current process handle 15 | IntPtr hProcess = GetCurrentProcess(); 16 | // Read the DACL 17 | var dacl = GetProcessSecurityDescriptor(hProcess); 18 | // bye bye ACEs 19 | for (int i = dacl.DiscretionaryAcl.Count - 1; i > 0; i--) 20 | { 21 | dacl.DiscretionaryAcl.RemoveAce(i); 22 | } 23 | // Insert the new ACE 24 | dacl.DiscretionaryAcl.InsertAce(0, new CommonAce(AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.PROCESS_TERMINATE, new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), false, null)); 25 | dacl.DiscretionaryAcl.InsertAce(0, new CommonAce(AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.PROCESS_SUSPEND_RESUME, new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), false, null)); 26 | dacl.DiscretionaryAcl.InsertAce(0, new CommonAce(AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.WRITE_OWNER, new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), false, null)); 27 | dacl.DiscretionaryAcl.InsertAce(0, new CommonAce(AceFlags.None, AceQualifier.AccessDenied, (int)ProcessAccessRights.PROCESS_ALL_ACCESS, new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null), false, null)); 28 | // Save the DACL 29 | SetProcessSecurityDescriptor(hProcess, dacl); 30 | } 31 | 32 | [DllImport("advapi32.dll", SetLastError = true)] 33 | static extern bool GetKernelObjectSecurity(IntPtr Handle, int securityInformation, [Out] byte[] pSecurityDescriptor, uint nLength, out uint lpnLengthNeeded); 34 | 35 | public static RawSecurityDescriptor GetProcessSecurityDescriptor(IntPtr processHandle) 36 | { 37 | const int DACL_SECURITY_INFORMATION = 0x00000004; 38 | byte[] psd = new byte[0]; 39 | uint bufSizeNeeded; 40 | // Call with 0 size to obtain the actual size needed in bufSizeNeeded 41 | GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, psd, 0, out bufSizeNeeded); 42 | if (bufSizeNeeded < 0 || bufSizeNeeded > short.MaxValue) 43 | throw new Win32Exception(); 44 | // Allocate the required bytes and obtain the DACL 45 | if (!GetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, 46 | psd = new byte[bufSizeNeeded], bufSizeNeeded, out bufSizeNeeded)) 47 | throw new Win32Exception(); 48 | // Use the RawSecurityDescriptor class from System.Security.AccessControl to parse the bytes: 49 | return new RawSecurityDescriptor(psd, 0); 50 | } 51 | 52 | [DllImport("advapi32.dll", SetLastError = true)] 53 | static extern bool SetKernelObjectSecurity(IntPtr Handle, int securityInformation, [In] byte[] pSecurityDescriptor); 54 | 55 | public static void SetProcessSecurityDescriptor(IntPtr processHandle, RawSecurityDescriptor dacl) 56 | { 57 | const int DACL_SECURITY_INFORMATION = 0x00000004; 58 | byte[] rawsd = new byte[dacl.BinaryLength]; 59 | dacl.GetBinaryForm(rawsd, 0); 60 | if (!SetKernelObjectSecurity(processHandle, DACL_SECURITY_INFORMATION, rawsd)) 61 | throw new Win32Exception(); 62 | } 63 | 64 | [DllImport("kernel32.dll")] 65 | public static extern IntPtr GetCurrentProcess(); 66 | 67 | [Flags] 68 | public enum ProcessAccessRights 69 | { 70 | PROCESS_CREATE_PROCESS = 0x0080, // Required to create a process. 71 | PROCESS_CREATE_THREAD = 0x0002, // Required to create a thread. 72 | PROCESS_DUP_HANDLE = 0x0040, // Required to duplicate a handle using DuplicateHandle. 73 | 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). 74 | 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. 75 | PROCESS_SET_INFORMATION = 0x0200, // Required to set certain information about a process, such as its priority class (see SetPriorityClass). 76 | PROCESS_SET_QUOTA = 0x0100, // Required to set memory limits using SetProcessWorkingSetSize. 77 | PROCESS_SUSPEND_RESUME = 0x0800, // Required to suspend or resume a process. 78 | PROCESS_TERMINATE = 0x0001, // Required to terminate a process using TerminateProcess. 79 | PROCESS_VM_OPERATION = 0x0008, // Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory). 80 | PROCESS_VM_READ = 0x0010, // Required to read memory in a process using ReadProcessMemory. 81 | PROCESS_VM_WRITE = 0x0020, // Required to write to memory in a process using WriteProcessMemory. 82 | DELETE = 0x00010000, // Required to delete the object. 83 | 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. 84 | SYNCHRONIZE = 0x00100000, // The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state. 85 | WRITE_DAC = 0x00040000, // Required to modify the DACL in the security descriptor for the object. 86 | WRITE_OWNER = 0x00080000, // Required to change the owner in the security descriptor for the object. 87 | STANDARD_RIGHTS_REQUIRED = 0x000f0000, 88 | PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF),// All possible access rights for a process object. 89 | } 90 | } 91 | } --------------------------------------------------------------------------------