I have legacy C++ code that changes a process DACL and am trying to use the managed code classes in .NET 3.5. I found code on the web where someone created a SetAclOnServices class that extends the NativeObjectSecurity class for services. I thought that I could implement this and just change the ResourceType.Service to ResourceType.KernelObject but when I call GetAccessControl it fails with File Not Found error.
+2
A:
Merry Christmas.
public class ProcessSecurity : NativeObjectSecurity
{
public ProcessSecurity(SafeHandle processHandle)
: base(false, ResourceType.KernelObject, processHandle, AccessControlSections.Access)
{
}
public void AddAccessRule(ProcessAccessRule rule)
{
base.AddAccessRule(rule);
}
// this is not a full impl- it only supports writing DACL changes
public void SaveChanges(SafeHandle processHandle)
{
Persist(processHandle, AccessControlSections.Access);
}
public override Type AccessRightType
{
get { return typeof(ProcessAccessRights); }
}
public override AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
{
return new ProcessAccessRule(identityReference, (ProcessAccessRights)accessMask, isInherited, inheritanceFlags, propagationFlags, type);
}
public override Type AccessRuleType
{
get { return typeof(ProcessAccessRule); }
}
public override AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
{
throw new NotImplementedException();
}
public override Type AuditRuleType
{
get { throw new NotImplementedException(); }
}
}
public class ProcessAccessRule : AccessRule
{
public ProcessAccessRule(IdentityReference identityReference, ProcessAccessRights accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
: base(identityReference, (int)accessMask, isInherited, inheritanceFlags, propagationFlags, type)
{
}
public ProcessAccessRights ProcessAccessRights { get { return (ProcessAccessRights)AccessMask; } }
}
[Flags]
public enum ProcessAccessRights
{
STANDARD_RIGHTS_REQUIRED = (0x000F0000),
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.
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.
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF, //All possible access rights for a process object.
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),
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.
SYNCHRONIZE = (0x00100000), // Required to wait for the process to terminate using the wait functions.
}
nitzmahone
2009-12-16 00:18:59
Thank you and Merry Christmas to you too! I've implemented this, adding a SafeHandle class and my process security descriptor can be modified but it doesn't appear to be doing what I want it to do. I'm trying to deny the program terminate right. I get the security descriptor before and after I add a deny rule and it looks like it should work, but I can still terminate the program. Do I need to set the access control on the process security descriptor?
Marcy Black
2009-12-16 19:35:54
It may have something to do with the fact that you're the owner- there could be some undocumented special cases around automatic privilege extension for Process ACLs. A deny ACE *should* always take precedence over an allow. Maybe try changing the owner to see if that has any effect.
nitzmahone
2009-12-16 20:54:45
Sorry, yeah- you'll need to add a call to the protected Persist method to actually write the ACL to the process. I didn't look at NativeObjectSecurity closely enough. I added a "SaveChanges" method that passes the process handle to Persist, and that did the trick.
nitzmahone
2009-12-16 21:14:35
Thanks for your effort, I really appreciate your help. Unfortunately I still can't get it to work as I’m able to terminate this process via TaskManager. Here's the SDDL before setting the deny access rights for PROCESS_TERMINATED:(A;;0x1f0fff;;;SY)(A;;0x1f0fff;;;S-1-5-213...-the rest of my ID)Here's the SDDL after the call to AddAccessRule and SaveChangesD:(D;;CC;;;S-1-5-21-213S-1-5-213...the rest of my ID)(A;;0x1f0fff;;;SY)(A;;0x1f0fff;;;S-1-5-21-213S-1-5-213...the rest of my ID)
Marcy Black
2009-12-17 18:18:07
It looks like the DACL was modified correctly. You said you have an unmanaged version of the code that works- does it produce the same ACL? I'm not able to prevent myself from terminating a process as its owner on my own box, but the ACL code is working fine (eg, I can add the right for others to terminate, etc, and that works). I'm still thinking it's an issue of ownership.
nitzmahone
2009-12-17 18:32:54
I don't have the source code for the unmanaged code,just the c++ executable and the small code snippet that handles the ACL modification. I tried creating a basic c++ program with that logic and it doesn't work for me there either. Again, thanks for your help.
Marcy Black
2009-12-17 19:28:29
Happy New Year! I'm happy to report that your code works beautifully. The reason why I could still terminate my process was due to the Debug programs security setting in Local Security Settings. Once I removed Administrators from the security setting I was unable to terminate. Thanks so much!
Marcy Black
2010-01-12 13:18:28
Accept answer then? :)
nitzmahone
2010-01-12 21:20:09
Thanks for this; I recently adapted it for setting service rights, and it worked beautifully.
Miral
2010-09-09 00:46:49