├── 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 | 
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 | 
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 | }
--------------------------------------------------------------------------------