So in the last day, A buddy of mine pointed out an issue with LanDesk ISSUR. I got to a stopping point but basically when you try to Kill the process while it is in a hung state it. So my thoughts were the ACL in memory for the process was adjusted to prevent administrators from killing the process. After running this code I found the process does not even have a handle to begin pulling its ACL. Interesting trick, Something that warrants further research.

Update: I am unable to get access to the process handle due to the ACL’s I must escalate to system first before this API will work.
Src: http://csharptest.net/1043/how-to-prevent-users-from-killing-your-service-process/index.html Also an interesting read.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using System.Windows.Forms;

namespace ProcessPermissions
{
    public partial class Form1 : Form
    {

        [StructLayoutAttribute(LayoutKind.Sequential)]
        struct SECURITY_DESCRIPTOR
        {
            public byte revision;
            public byte size;
            public short control;
            public IntPtr owner;
            public IntPtr group;
            public IntPtr sacl;
            public IntPtr dacl;
        }

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool QueryServiceObjectSecurity(IntPtr serviceHandle,
            System.Security.AccessControl.SecurityInfos secInfo,
            ref SECURITY_DESCRIPTOR lpSecDesrBuf,
            uint bufSize,
            out uint bufSizeNeeded);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool QueryServiceObjectSecurity(SafeHandle serviceHandle,
            System.Security.AccessControl.SecurityInfos secInfo,
            byte[] lpSecDesrBuf,
            uint bufSize,
            out uint bufSizeNeeded);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool SetServiceObjectSecurity(SafeHandle serviceHandle,
            System.Security.AccessControl.SecurityInfos secInfos,
            byte[] lpSecDesrBuf);

        public void SetServicePermissions(string service, string username)
        {
            System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(service, ".");
            ServiceControllerStatus status = sc.Status;
            byte[] psd = new byte[0];
            uint bufSizeNeeded;
            bool ok = QueryServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, psd, 0, out bufSizeNeeded);
            if (!ok)
            {
                int err = Marshal.GetLastWin32Error();
                if (err == 122 || err == 0)
                { // ERROR_INSUFFICIENT_BUFFER
                  // expected; now we know bufsize
                    psd = new byte[bufSizeNeeded];
                    ok = QueryServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, psd, bufSizeNeeded, out bufSizeNeeded);
                }
                else {
                    throw new ApplicationException("error calling QueryServiceObjectSecurity() to get DACL for : error code=" + err);
                }
            }
            if (!ok)
                throw new ApplicationException("error calling QueryServiceObjectSecurity(2) to get DACL for : error code=" + Marshal.GetLastWin32Error());

            // get security descriptor via raw into DACL form so ACE
            // ordering checks are done for us.
            RawSecurityDescriptor rsd = new RawSecurityDescriptor(psd, 0);
            RawAcl racl = rsd.DiscretionaryAcl;
            DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, racl);

            // Add start/stop/read access
            NTAccount acct = new NTAccount(username);
            SecurityIdentifier sid = (SecurityIdentifier)acct.Translate(typeof(SecurityIdentifier));
            // 0xf7 is SERVICE_QUERY_CONFIG|SERVICE_CHANGE_CONFIG|SERVICE_QUERY_STATUS|
            // SERVICE_START|SERVICE_STOP|SERVICE_PAUSE_CONTINUE|SERVICE_INTERROGATE
            dacl.AddAccess(AccessControlType.Allow, sid, 0xf7, InheritanceFlags.None, PropagationFlags.None);

            // convert discretionary ACL back to raw form; looks like via byte[] is only way
            byte[] rawdacl = new byte[dacl.BinaryLength];
            dacl.GetBinaryForm(rawdacl, 0);
            rsd.DiscretionaryAcl = new RawAcl(rawdacl, 0);

            // set raw security descriptor on service again
            byte[] rawsd = new byte[rsd.BinaryLength];
            rsd.GetBinaryForm(rawsd, 0);
            ok = SetServiceObjectSecurity(sc.ServiceHandle, SecurityInfos.DiscretionaryAcl, rawsd);
            if (!ok)
            {
                throw new ApplicationException("error calling SetServiceObjectSecurity(); error code=" + Marshal.GetLastWin32Error());
            }
        }

        [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);
        }
        string GetNameFromSID(SecurityIdentifier sid)
        {
            try
            {
                NTAccount ntAccount = (NTAccount)sid.Translate(typeof(NTAccount));
                return ntAccount.ToString();
            }
            catch
            {
                return null;
            }
        }
        public Form1()
        {
            InitializeComponent();
        }
        [DllImport("kernel32.dll")]
        public static extern bool WriteProcessMemory(int hProcess, int lpBaseAddress, byte lpBuffer,
                                         int nSize, int lpNumberOfBytesWritten);
        [DllImport("kernel32.dll")]
        public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
        int PROCESS_ALL_ACCESS = (0x1F0FFF);

        private void Form1_Load(object sender, EventArgs e)
        {
            //IntPtr hProcess = IntPtr.Zero;
            IntPtr hProcessToken = IntPtr.Zero;
            IntPtr securityDescriptorPtr = IntPtr.Zero;
            //Process[] hProcess = Process.GetProcessesByName("issuser");
            Process[] hProcess = Process.GetProcessesByName("notepad");
            IntPtr xAsIntPtr = new IntPtr(hProcess[0].Id);
            RawSecurityDescriptor Desc = GetProcessSecurityDescriptor(xAsIntPtr);
            System.Diagnostics.Debug.WriteLine(Desc.Owner);

            foreach (CommonAce item in Desc.DiscretionaryAcl)
            {
                System.Diagnostics.Debug.WriteLine(item.SecurityIdentifier.Value + " - " + item.SecurityIdentifier.AccountDomainSid);
                System.Diagnostics.Debug.WriteLine(GetNameFromSID(item.SecurityIdentifier));
                System.Diagnostics.Debug.WriteLine(item.AceFlags);
                System.Diagnostics.Debug.WriteLine(item.AceType);
                System.Diagnostics.Debug.WriteLine(item.AuditFlags);
                System.Diagnostics.Debug.WriteLine(item.BinaryLength);
                System.Diagnostics.Debug.WriteLine(item.InheritanceFlags);
                System.Diagnostics.Debug.WriteLine(item.IsInherited);
                System.Diagnostics.Debug.WriteLine(item.PropagationFlags);
                System.Diagnostics.Debug.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
            }

            Application.Exit(); 
        }
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax