C# Random Exception when Getting / Setting Registr

2019-06-01 00:01发布

问题:

I've been getting a completely random exception, I can run the same set of code 1000 times (each "run" is a full end-end of the program and thus starts as its own process from commandline and then exists) and get it fail once, or even 150 times. And I mean I can run it back-back over and over and it will fail completely randomly.

System.Security.AccessControl.PrivilegeNotHeldException: The process does not possess the 'SeSecurityPrivilege' privilege which is required for this operation.
at System.Security.AccessControl.Win32.GetSecurityInfo(ResourceType resourceType, String name, SafeHandle handle, AccessControlSections accessControlSections, RawSecurityDescriptor& resultSd)
at System.Security.AccessControl.NativeObjectSecurity.CreateInternal(ResourceType resourceType, Boolean isContainer, String name, SafeHandle handle, AccessControlSections includeSections, Boolean createByName, ExceptionFromErrorCode exceptionFromErrorCode, Object exceptionContext)
at System.Security.AccessControl.RegistrySecurity..ctor(SafeRegistryHandle hKey, String name, AccessControlSections includeSections) 
at Microsoft.Win32.RegistryKey.GetAccessControl(AccessControlSections includeSections)

I can't get it to fail when debugging so am having issues trying to see why it randomly decides to fail. As its failing inside the (RegistryKey).GetAccessControl(AccessControlSections.All) method, I'm stumped as to what I should try next.

Also, I'm looping through multiple keys, and if it decides to fail with this permission exception on one, they all fail for that process.

I'm running from command line (as admin, UACed in), starting the process and then it exists. From that same command line I start the process again, and it will randomly fail.

I am loading user hives and making sure that the registry rights are elevated, and it works except for this random bug.

Also, the issue occurs on multiple machines (always running locally, not remote), both under system (psexec) and administrator accounts.

回答1:

I don't think that the System account has the SeSecurityPrivilege enabled, or an admin for that matter.

Instead of (RegistryKey).GetAccessControl(AccessControlSections.All), try: (RegistryKey).GetAccessControl(AccessControlSections.Access)

Does that still give you the error? You won't be able to get the SACL with Access though.

EDIT: I grabbed some code from pinvoke for adjusting the privileges in an access token, you'll need admin rights to do it; I modified it for the SeSecurityPrivilege, you should be able to use (RegistryKey).GetAccessControl(AccessControlSections.All) now without any errors once "SetPriv();" is called. I was able to verify that it is working by using Process Hacker 2 and checking the token before and after, it is enabling SeSecuirtyPrivilege:

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    internal static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr
    phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, string name,
    ref long pluid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
        public int Count;
        public long Luid;
        public int Attr;
    }

    internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
    internal const int TOKEN_QUERY = 0x00000008;
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    internal const string SeSecurity = "SeSecurityPrivilege";

    private bool SetPriv()
   {
       try
       {
           bool retVal;
           TokPriv1Luid tp;
           IntPtr hproc = GetCurrentProcess();
           IntPtr htok = IntPtr.Zero;
           retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
           tp.Count = 1;
           tp.Luid = 0;
           tp.Attr = SE_PRIVILEGE_ENABLED;
           retVal = LookupPrivilegeValue(null, SeSecurity, ref tp.Luid);
           retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
           return retVal;
       }
       catch (Exception ex)
       {
           throw;
           return false; 
       }

   }