-
-
Save TheWover/53f70ca038563f1687275144e46f14aa to your computer and use it in GitHub Desktop.
Process Armor - Prevent users from killing your service or process
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Reflection; | |
using System.ComponentModel; | |
using System.Security.AccessControl; | |
using System.Security.Principal; | |
using System.Runtime.InteropServices; | |
using System.Configuration.Install; | |
/* | |
Step One: | |
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:procarmor.exe ProcessArmor.cs | |
Step Two: | |
C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U procarmor.exe | |
Reference: http://csharptest.net/1043/how-to-prevent-users-from-killing-your-service-process/ | |
Note: An administrator can still kill the process. Just buys you time really. :-) | |
Chink in ProcArmor: | |
procarmor.exe chink | |
procarmor.exe choke | |
*/ | |
namespace ProcessArmor | |
{ | |
[System.ComponentModel.RunInstaller(true)] | |
public class Sample : System.Configuration.Install.Installer | |
{ | |
//The Methods can be Uninstall/Install. Install is transactional, and really unnecessary. | |
public override void Uninstall(System.Collections.IDictionary savedState) | |
{ | |
Console.WriteLine("Hello There From Uninstall"); | |
Program.Main(null); | |
} | |
} | |
class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
if (args != null && args.Length > 0 && args[0].Equals("chink", StringComparison.OrdinalIgnoreCase)) | |
{ | |
Console.WriteLine("Find Chink in Armor..."); | |
Chink(); | |
return; | |
} | |
if (args != null && args.Length > 0 && args[0].Equals("choke", StringComparison.OrdinalIgnoreCase)) | |
{ | |
Console.WriteLine("Find Choke in Armor..."); | |
Choke(); | |
return; | |
} | |
Console.WriteLine("Hello World!"); | |
IntPtr hProcess = GetCurrentProcess(); | |
// Read the DACL | |
var dacl = GetProcessSecurityDescriptor(hProcess); | |
// Remove ACE | |
ThreadACE(); | |
for (int i = 0; i < dacl.DiscretionaryAcl.Count; i++) | |
{ | |
dacl.DiscretionaryAcl.RemoveAce(i); | |
} | |
SetProcessSecurityDescriptor(hProcess, dacl); | |
Console.WriteLine("ACE Removed"); | |
Console.Write("Press any key to continue . . . "); | |
Console.ReadKey(true); | |
} | |
public static void Choke() | |
{ | |
Process[] processlist = Process.GetProcesses(); | |
int nProcessID = Process.GetCurrentProcess().Id; | |
foreach (Process theprocess in processlist) | |
{ | |
if (theprocess.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && theprocess.Id != nProcessID) | |
{ | |
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id); | |
IntPtr procPtr = OpenProcess(ProcessAccessRights.WRITE_DAC, false, theprocess.Id); | |
Console.WriteLine("--->Opening {0} for WRITE_DAC {1}", theprocess.Id, procPtr); | |
//get current process DACL | |
IntPtr hProcess = GetCurrentProcess(); | |
var dacl = GetProcessSecurityDescriptor(hProcess); | |
SetProcessSecurityDescriptor(procPtr, dacl); | |
Console.WriteLine("--->Resetting DACL", theprocess.Id, procPtr); | |
CloseHandle(procPtr); | |
procPtr = OpenProcess(ProcessAccessRights.PROCESS_TERMINATE, false, theprocess.Id); | |
Console.WriteLine("--->Terminating process...", theprocess.Id, procPtr); | |
TerminateProcess(procPtr, 1); | |
} | |
} | |
} | |
public static void Chink() | |
{ | |
Process[] processlist = Process.GetProcesses(); | |
int nProcessID = Process.GetCurrentProcess().Id; | |
foreach (Process theprocess in processlist) | |
{ | |
if (theprocess.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && theprocess.Id != nProcessID) | |
{ | |
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id); | |
foreach (ProcessThread td in theprocess.Threads) | |
{ | |
Console.WriteLine("+---Thread ID: {0}", td.Id); | |
if (theprocess.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && theprocess.Id != nProcessID) | |
{ | |
IntPtr tdPtr = OpenThread(ThreadAccess.TERMINATE, false, (uint)td.Id); | |
Console.WriteLine("--->Exploiting Chink in ProcArmor on thread {0} - {1}", td.Id, TerminateThread(tdPtr)); | |
} | |
} | |
} | |
} | |
} | |
public static void ThreadACE() | |
{ | |
Process[] processlist = Process.GetProcesses(); | |
int nProcessID = Process.GetCurrentProcess().Id; | |
foreach (Process theprocess in processlist) | |
{ | |
if (theprocess.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && theprocess.Id == nProcessID) | |
{ | |
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id); | |
foreach (ProcessThread td in theprocess.Threads) | |
{ | |
Console.WriteLine("+---Thread ID: {0}", td.Id); | |
if (theprocess.ProcessName.Equals(Process.GetCurrentProcess().ProcessName) && theprocess.Id == nProcessID) | |
{ | |
IntPtr tdPtr = OpenThread(ThreadAccess.THREAD_ALL_ACCESS, false, (uint)td.Id); | |
var tdacl = GetProcessSecurityDescriptor(tdPtr); | |
for (int i = 0; i < tdacl.DiscretionaryAcl.Count; i++) | |
{ | |
tdacl.DiscretionaryAcl.RemoveAce(i); | |
} | |
Console.WriteLine("+---Thread ACE Removed: {0}", td.Id); | |
SetProcessSecurityDescriptor(tdPtr, tdacl); | |
} | |
} | |
} | |
} | |
} | |
[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("kernel32.dll", SetLastError = true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode); | |
[DllImport("advapi32.dll", SetLastError = true)] | |
static extern bool SetKernelObjectSecurity(IntPtr Handle, int securityInformation, [In] byte[] pSecurityDescriptor); | |
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(); | |
} | |
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)] | |
public static extern int TerminateThread(IntPtr hThread); | |
[DllImport("kernel32.dll")] | |
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId); | |
[Flags] | |
public enum ThreadAccess : int | |
{ | |
TERMINATE = (0x0001), | |
SUSPEND_RESUME = (0x0002), | |
GET_CONTEXT = (0x0008), | |
SET_CONTEXT = (0x0010), | |
SET_INFORMATION = (0x0020), | |
QUERY_INFORMATION = (0x0040), | |
SET_THREAD_TOKEN = (0x0080), | |
IMPERSONATE = (0x0100), | |
DIRECT_IMPERSONATION = (0x0200), | |
SYNCHRONIZE = (0x00100000), | |
STANDARD_RIGHTS_REQUIRED = 0x000f0000, | |
THREAD_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3FF) | |
} | |
[DllImport("kernel32.dll")] | |
public static extern IntPtr GetCurrentProcess(); | |
[DllImport("kernel32.dll")] | |
public static extern IntPtr OpenProcess( | |
ProcessAccessRights processAccess, | |
bool bInheritHandle, | |
int processId | |
); | |
public static IntPtr OpenProcess(Process proc, ProcessAccessRights flags) | |
{ | |
return OpenProcess(flags, false, proc.Id); | |
} | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern bool CloseHandle(IntPtr hHandle); | |
[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. | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment