0

I have a problem to access the HKEY_CURRENT_USER registry key for an impersonated user.

After some research, I'm currently using Win32 Api RegOpenCurrentUser. Since there's no documentation in P/Invoke website, I've retrieved this signature from what I've found on this MSDN page:

[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern int RegOpenCurrentUser(int samDesired, out IntPtr phkResult);

I'm using it this way:

public class LocalRegistryAccess
{
    [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 GetImpersonatedUserRegistryHandle(RegistrySecurity _access)
    {
        IntPtr safeHandle = new IntPtr();
        int result = RegOpenCurrentUser((int)_access, out safeHandle);

        return safeHandle;
    }

    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;
    }
}

public class UserManagement
{
    LocalRegistryAccess regAccess = new LocalRegistryAccess();

    using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(token))
    {
        IntPtr localRegistryHandle = regAccess.GetImpersonatedUserRegistryHandle(LocalRegistryAccess.RegistrySecurity.KEY_ALL_ACCESS);
        using(RegistryKey localRegistry = regAccess._pointerToRegistryKey(localRegistryHandle, true, true))
        {
            // Manage HKCU for impersonated user
        }
    }
}

This code seems to work correctly on Windows 7, but does not work in Windows XP Embedded: my method GetImpersonatedUserRegistryHandle always return an empty handle.

Any thought? Am I missing some instruction in order to make this code compatible with Windows XP Embedded?

Spaceman
  • 547
  • 8
  • 25
  • What's the value of `int result = RegOpenCurrentUser(...)` ? – Simon Mourier May 29 '13 at 11:49
  • @SimonMourier: it's quite strange... I've repeated the test just now and `int result = RegOpenCurrentUser(...)` returns `result = 0`, with a valid handle and without any errors. When I've made the test this morning, it returned an `handle = 0` but I don't remember which was the value of `result`. – Spaceman May 29 '13 at 12:33
  • P.S.: I haven't made any change in code since yesterday. – Spaceman May 29 '13 at 12:34
  • *Never* skip error checking when you pinvoke winapi functions. You don't have the friendly .NET exceptions anymore to keep you out of trouble. You have to throw them yourself. – Hans Passant May 29 '13 at 12:34
  • I'd switch to C++ to debug this. Once you are sure that what you attempt is possible, then switch to p/invoke. And yes, check for errors always. – David Heffernan May 29 '13 at 15:29
  • @HansPassant: thanks for the reminder. I will enclose all my pinvoke functions in try/catch statement, with custom exception thrown. – Spaceman May 31 '13 at 08:23
  • @DavidHeffernan: I currently don't have the specific tools (and enough knowledge...) to make a C++ debug. Thanks anyway for the suggestion, I'll consider it for future scenarios. – Spaceman May 31 '13 at 08:31
  • 1
    *Never* enclose your pinvoke with try/catch, that will still hide errors. Including the really nasty stuff you *never* want to hide, like AccessViolation. – Hans Passant May 31 '13 at 08:44
  • 1
    It would be far easier, even for you, to write the code in C++. It's the same code but without all the horrid p/invoke. Regarding error handling, Hans is suggesting that you start checking for errors in code, instead of ignoring them. Win32 api calls won't throw, so you've got to check for errors as described in the documentation for each function. You'll need to start doing that. – David Heffernan May 31 '13 at 08:46

0 Answers0