• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1948
  • Last Modified:

Loading & modifying value in registry hive from .NET (C#)

I am trying to load a registry hive from .NET, but RegLoadKey fails with a return code of 8589934613 (test code is at the end of the post).  

VS 2008 is started as administrator and the NTUSER.DAT is a copy in a temp directory, so it is not likely to be permission or a file lock.

Does anyone have a working C# sample that loads an NTUSER.DAT file & modifies a value in it?

Environment: Windows 7 (64), VS 2008.

Thanks.

public class RegistryHive
{
    [StructLayout(LayoutKind.Sequential)]
    private struct LUID
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LUID_AND_ATTRIBUTES
    {
        public LUID pLuid;
        public UInt32 Attributes;
    }

    private class TOKEN_PRIVILEGES
    {
        public UInt32 PrivilegeCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)]
        public LUID_AND_ATTRIBUTES[] Privileges = new LUID_AND_ATTRIBUTES[2];
    }

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

    private const Int32 ANYSIZE_ARRAY = 1;
    private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
    private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
    private const UInt32 TOKEN_QUERY = 0x0008;

    private const uint HKEY_USERS = 0x80000003;
    private const string SE_RESTORE_NAME = "SeRestorePrivilege";
    private const string SE_BACKUP_NAME = "SeBackupPrivilege";

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

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

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern long RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern long RegUnLoadKey(UInt32 hKey, string lpSubKey);

    private string _loadUnderKeyName;
    private IntPtr _myToken;
    //private TOKEN_PRIVILEGES _tokenPrivileges = new TOKEN_PRIVILEGES();
    private TokPriv1Luid _tokenPrivileges = new TokPriv1Luid();

    private LUID _restoreLuid;
    private LUID _backupLuid;

    public RegistryHive()
    {
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out _myToken))
            Console.WriteLine("OpenProcess Error");

        if (!LookupPrivilegeValue(null, SE_RESTORE_NAME, out _restoreLuid))
            Console.WriteLine("LookupPrivilegeValue Error");

        if (!LookupPrivilegeValue(null, SE_BACKUP_NAME, out _backupLuid))
            Console.WriteLine("LookupPrivilegeValue Error");

        _tokenPrivileges.Attr = SE_PRIVILEGE_ENABLED;
        _tokenPrivileges.Luid = _restoreLuid;
        _tokenPrivileges.Count = 1;

        if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
            Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());

        // --> THIS CALL FAILS: <--
        long retVal = RegLoadKey(HKEY_USERS, "123test", @"E:\temp\NTUSER.DAT");
        if (retVal != 0)
        {
            Console.WriteLine("RegLoadKey Error:" + retVal);
        }
        //  Since the RegLoadKey fails, this returns nothing:
        string test = Registry.GetValue(@"HKEY_LOCAL_MACHINE\123test\Environment", "TEMP", "") as string;
    }
}

Open in new window

0
Lars007
Asked:
Lars007
  • 6
  • 3
1 Solution
 
Craig WagnerSoftware ArchitectCommented:
I realize this doesn't answer the question, but I am curious as to why you're using P/Invoke rather than using the Microsoft.Win32.Registry* classes.
0
 
Lars007Author Commented:
There is no RegLoadKey functionality in .NET, you have to use p/invoke.
0
 
Lars007Author Commented:
Here is the solution (got an answer elsewhere):

The return value of RegLoadKey is a Win32 Long, which is 32 bit, while a C# long is 64 bit, so the method definition should be changed from:
static extern long RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);
to
static extern Int32 RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);

0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
Lars007Author Commented:
In case it helps someone, here is my complete test code for loading an off-line registry hive, modifying a value and unloading the hive.
public class RegistryTest
{
    [StructLayout(LayoutKind.Sequential)]
    private struct LUID
    {
        public uint LowPart;
        public int HighPart;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LUID_AND_ATTRIBUTES
    {
        public LUID pLuid;
        public UInt32 Attributes;
    }

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

    private const Int32 ANYSIZE_ARRAY = 1;
    private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
    private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
    private const UInt32 TOKEN_QUERY = 0x0008;

    private const uint HKEY_USERS = 0x80000003;
    private const string SE_RESTORE_NAME = "SeRestorePrivilege";
    private const string SE_BACKUP_NAME = "SeBackupPrivilege";

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

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

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern Int32 RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern Int32 RegUnLoadKey(UInt32 hKey, string lpSubKey);

    private IntPtr _myToken;
    private TokPriv1Luid _tokenPrivileges = new TokPriv1Luid();
    private TokPriv1Luid _tokenPrivileges2 = new TokPriv1Luid();

    private LUID _restoreLuid;
    private LUID _backupLuid;

    public RegistryTest()
    {
        if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out _myToken))
            Console.WriteLine("OpenProcess Error");

        if (!LookupPrivilegeValue(null, SE_RESTORE_NAME, out _restoreLuid))
            Console.WriteLine("LookupPrivilegeValue Error");

        if (!LookupPrivilegeValue(null, SE_BACKUP_NAME, out _backupLuid))
            Console.WriteLine("LookupPrivilegeValue Error");

        _tokenPrivileges.Attr = SE_PRIVILEGE_ENABLED;
        _tokenPrivileges.Luid = _restoreLuid;
        _tokenPrivileges.Count = 1;

        _tokenPrivileges2.Attr = SE_PRIVILEGE_ENABLED;
        _tokenPrivileges2.Luid = _backupLuid;
        _tokenPrivileges2.Count = 1;

        if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
            Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());
        
        if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges2, 0, IntPtr.Zero, IntPtr.Zero))
            Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());

        int retVal = RegLoadKey(HKEY_USERS, "123test", @"D:\temp\NTUSER.DAT");
        if (retVal != 0)
            Console.WriteLine("RegLoadKey Error:" + retVal);

        string oldShell = Registry.GetValue(@"HKEY_Users\123test\Software\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", "") as string;
        string newShell = @"test.exe";
        Registry.SetValue(@"HKEY_Users\123test\Software\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", newShell);
        
        retVal = RegUnLoadKey(HKEY_USERS, "123test");
    }
}

Open in new window

0
 
Lars007Author Commented:
I am accepting my own comment as a solution, since it solves the issue.
0
 
Bob LearnedCommented:
I am curious what you can't get from Microsoft.Win32.Registry class?

Registry Class
http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx
0
 
Lars007Author Commented:
As I said, there is no way to load an off-line registry-hive (NTUSER.DAT file) with .NET native classes.  You really should do some research before you object to information you might not fully understand.

A couple of links you can get more data from:
http://www.csharphelp.com/2007/01/registry-ins-and-outs-using-c/
http://www.experts-exchange.com/Programming/Languages/.NET/Q_24296791.html


Excerpt from the first link: "The.NET Framework supports a lot and in C# the RegistryKey class is very powerfuland can be used well to manipulate the registry. Most of the Win32 APIs which we would have had to use previously have been built in however there are a few that are not, and this is where i refer to my Article "Advance Registry Work in C#". These are RegLoadKey() and RegUnloadKey(). These two calls allow you to load registry Hives into the registry and then manipulate them. "

0
 
Bob LearnedCommented:
I didn't object, I was trying to learn something.
0
 
Lars007Author Commented:
I'm sorry, I did not realize that - it came through to me as "Objection posted" (not sure why), and I thought I already answered your question earlier.  
0
 
Bob LearnedCommented:
That's OK, that wasn't me posting before.  I was late to the question, and I wanted to know why you couldn't access a hive, since I never tried to access one with the Registry classes.  It was a perfect opportunity to learn something new, so thank you for the clarification.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 6
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now