Access CurrentUser Registry Key for Impersonated User - Compatibility with .NET 3.5

前端 未结 2 925
故里飘歌
故里飘歌 2021-01-07 02:21

I\'ve recently written an application that impersonate user account, get a handle to CURRENT_USER registry key (using PInvoke \"LoadUserProfile\" to retrieve ProfileInfo.hPr

2条回答
  •  抹茶落季
    2021-01-07 03:18

    After days of research, and help from MSDN community to the same question, I've found the way to follow to accomplish my needs.

    The initial suggestion was to use Win Api function RegOpenKeyEx (see P/Invoke website for infos and samples); but according to this MSDN article, I've found that

    If your service or application impersonates different users, do not use this function with HKEY_CURRENT_USER. Instead, call the RegOpenCurrentUser function.

    Finally, the way to go is RegOpenCurrentUser function. (unfortunately there's still no trace of this function on P/Invoke website, but you can find some infos on MSDN)

    This is how I currently define it:

    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern int RegOpenCurrentUser(int samDesired, out IntPtr phkResult);    
    
    public enum RegistrySecurity
    {
        KEY_ALL_ACCESS = 0xF003F,
        KEY_CREATE_LINK = 0x0020,
        KEY_CREATE_SUB_KEY = 0x0004,
        KEY_ENUMERATE_SUB_KEYS = 0x0008,
        KEY_EXECUTE = 0x20019,
        KEY_NOTIFY = 0x0010,
        KEY_QUERY_VALUE = 0x0001,
        KEY_READ = 0x20019,
        KEY_SET_VALUE = 0x0002,
    KEY_WOW64_32KEY = 0x0200,
        KEY_WOW64_64KEY = 0x0100,
        KEY_WRITE = 0x20006,
    }
    
    public IntPtr GetImpersonateUserRegistryHandle(RegistrySecurity _access)
    {
        IntPtr safeHandle = new IntPtr();
        int result = RegOpenCurrentUser((int)_access, out safeHandle);
    
        return safeHandle;
    }
    
    /// 
    /// Get a registry key from a pointer.
    /// 
    /// Pointer to the registry key
    /// Whether or not the key is writable.
    /// Whether or not we own the handle.
    /// Registry key pointed to by the given pointer.
    public RegistryKey _pointerToRegistryKey(IntPtr hKey, bool writable, bool ownsHandle)
    {
        //Get the BindingFlags for private contructors
        System.Reflection.BindingFlags privateConstructors = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
    
        //Get the Type for the SafeRegistryHandle
        Type safeRegistryHandleType =
                typeof(Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid).Assembly.GetType("Microsoft.Win32.SafeHandles.SafeRegistryHandle");
    
        //Get the array of types matching the args of the ctor we want
        Type[] safeRegistryHandleCtorTypes = new Type[] { typeof(IntPtr), typeof(bool) };
    
        //Get the constructorinfo for our object
        System.Reflection.ConstructorInfo safeRegistryHandleCtorInfo = safeRegistryHandleType.GetConstructor(
                privateConstructors, null, safeRegistryHandleCtorTypes, null);
    
        //Invoke the constructor, getting us a SafeRegistryHandle
        Object safeHandle = safeRegistryHandleCtorInfo.Invoke(new Object[] { hKey, ownsHandle });
    
        //Get the type of a RegistryKey
        Type registryKeyType = typeof(RegistryKey);
    
        //Get the array of types matching the args of the ctor we want
        Type[] registryKeyConstructorTypes = new Type[] { safeRegistryHandleType, typeof(bool) };
    
        //Get the constructorinfo for our object
        System.Reflection.ConstructorInfo registryKeyCtorInfo = registryKeyType.GetConstructor(
                privateConstructors, null, registryKeyConstructorTypes, null);
    
        //Invoke the constructor, getting us a RegistryKey
        RegistryKey resultKey = (RegistryKey)registryKeyCtorInfo.Invoke(new Object[] { safeHandle, writable });
    
        //return the resulting key
        return resultKey;
    }
    

    And this is how I use it to get registry:

    IntPtr localRegistryHandle = GetImpersonateUserRegistryHandle(TestRegistryAccess.RegistrySecurity.KEY_ALL_ACCESS);
    
    using(RegistryKey localRegistry = _pointerToRegistryKey(localRegistryHandle, true, true))
    {
        // do something with local registry
    }
    

提交回复
热议问题