?
Solved

AdjustTokenPrivileges fails with error 87 (invalid parameter)

Posted on 2011-10-21
5
Medium Priority
?
1,255 Views
Last Modified: 2013-12-03
Hello,

I am trying to load a registry hive from C# (which requires P/Invoke).  This code is based on a sample from MS, but for some reason AdjustTokenPrivileges always fails with GetLastError = 87 (=Invalid Parameter), but I cannot see why (see line 78 below):

public class RegistryHive
    {
        private struct LUID
        {
            public long LowPart;
            public long HighPart;
        }

        private struct LUID_AND_ATTRIBUTES
        {
            public LUID pLuid;
            public long Attributes;
        }

        private class TOKEN_PRIVILEGES
        {
            public long PrivilegeCount;
            public LUID_AND_ATTRIBUTES[] Privileges = new LUID_AND_ATTRIBUTES[2];
        }

        private const int TOKEN_ADJUST_PRIVLEGES = 0x20;
        private const int TOKEN_QUERY = 0x8;
        private const int SE_PRIVILEGE_ENABLED = 0x2;
        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", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
            [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
            ref TOKEN_PRIVILEGES NewState,
            UInt32 Zero,
            IntPtr Null1,
            IntPtr Null2);

        [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 LUID _restoreLuid;
        private LUID _backupLuid;

        public RegistryHive()
        {
            if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVLEGES | 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.PrivilegeCount = 2;
            _tokenPrivileges.Privileges[0].pLuid = _restoreLuid;
            _tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
            _tokenPrivileges.Privileges[1].pLuid = _backupLuid;
            _tokenPrivileges.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;

            // ----> THIS ALWAYS FAILS WITH ERROR 87.  Why?  <----
            if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
                Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error()); 
        }

        public bool LoadHive(string filePath)
        {
            _loadUnderKeyName = "123test";
            long Retval = RegLoadKey(HKEY_USERS, _loadUnderKeyName, filePath);
            if (Retval != 0)
            {
                Console.WriteLine("RegLoadKey Error");
                return false;
            }
            return true;
        }
    }

Open in new window

 

Windows 7 (64), VS2008.  I have launched VS2008 as administrator (and added a manifest with requestedExecutionLevel = requireAdministrator), just in case.  

Any help on this would be appreciated!

0
Comment
Question by:Lars007
  • 3
  • 2
5 Comments
 
LVL 41

Accepted Solution

by:
graye earned 2000 total points
ID: 37014753
Your P/Invoke signatures are a bit off...  All of your "long's" should be "int's".

Also, an easy way to get a structure to accept an array of something is just to fake it... by putting the two instances of LUID_AND_ATTRIBUTES back-to-back.

The P/Invoke wiki is your friend!   http://pinvoke.net/default.aspx/Structures/LUID_AND_ATTRIBUTES.html
private struct LUID
        {
            public int LowPart;
            public int HighPart;
        }

        private struct LUID_AND_ATTRIBUTES
        {
            public LUID pLuid;
            public int Attributes;
        }

        private struct TOKEN_PRIVILEGES
        {
            public long PrivilegeCount;
            public LUID_AND_ATTRIBUTES LA1;
            public LUID_AND_ATTRIBUTES LA2;
        }

Open in new window

0
 

Author Comment

by:Lars007
ID: 37015728
Thanks for the reply, but I tried changing the longs to ints, to no avail - same error.  

Other suggestions?
0
 
LVL 41

Expert Comment

by:graye
ID: 37017766
Well, here is a VB.Net example that I've got handy....
<StructLayout(LayoutKind.Sequential, Pack:=4)> _
    Private Structure LUID_AND_ATTRIBUTES
        Dim Luid As Long
        Dim Attributes As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=4)> _
    Private Structure TOKEN_PRIVILEGES
        Dim PrivilegeCount As Integer
        Dim Privilege1 As LUID_AND_ATTRIBUTES
        Dim Privilege2 As LUID_AND_ATTRIBUTES
    End Structure

    <DllImport("advapi32.dll")> _
    Private Function OpenProcessToken _
        (ByVal ProcessHandle As IntPtr, _
         ByVal DesiredAccess As Integer, _
         ByRef TokenHandle As IntPtr) _
        As Boolean
    End Function

    <DllImport("advapi32.dll")> _
    Private Function LookupPrivilegeValue _
        (ByVal lpSystemName As String, _
         ByVal lpName As String, _
         ByRef lpLuid As Long) _
         As Boolean
    End Function

    <DllImport("advapi32.dll")> _
    Private Function AdjustTokenPrivileges _
        (ByVal TokenHandle As IntPtr, _
         ByVal DisableAllPrivileges As Boolean, _
         ByRef NewState As TOKEN_PRIVILEGES, _
         ByVal BufferLength As Integer, _
         ByVal PreviousState As IntPtr, _
         ByVal ReturnLength As IntPtr) _
         As Boolean
    End Function

    Const TOKEN_QUERY As Integer = &H8
    Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20
    Const SE_TAKE_OWNERSHIP_NAME As String = "SeTakeOwnershipPrivilege"
    Const SE_RESTORE_NAME As String = "SeRestorePrivilege"
    Const SE_PRIVILEGE_ENABLED As Integer = &H2

    Public Function SetPrivileges() As Boolean
        Dim hProc, hToken As IntPtr
        Dim luid_TakeOwnership, luid_Restore As Long
        Dim tp As New TOKEN_PRIVILEGES

        ' get the current process's token
        hProc = Process.GetCurrentProcess().Handle
        hToken = IntPtr.Zero
        If Not OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, hToken) Then
            Return False
        End If

        ' get the LUIDs for the  privileges (provided they already exists)
        luid_TakeOwnership = 0
        If Not LookupPrivilegeValue(Nothing, SE_TAKE_OWNERSHIP_NAME, luid_TakeOwnership) Then
            Return False
        End If
        luid_Restore = 0
        If Not LookupPrivilegeValue(Nothing, SE_RESTORE_NAME, luid_Restore) Then
            Return False
        End If

        tp.PrivilegeCount = 2
        tp.Privilege1.Luid = luid_TakeOwnership
        tp.Privilege1.Attributes = SE_PRIVILEGE_ENABLED
        tp.Privilege2.Luid = luid_Restore
        tp.Privilege2.Attributes = SE_PRIVILEGE_ENABLED

        ' enable the privileges
        If Not AdjustTokenPrivileges(hToken, False, tp, 0, IntPtr.Zero, IntPtr.Zero) Then
            Return False
        End If

        Return True
    End Function

Open in new window

0
 

Author Comment

by:Lars007
ID: 37022447
The VB example gave me the same result, but I looked closer at the P/Invoke site you referred me to, and got AdjustTokenPrivileges to no longer return an error.

For some reason the TOKEN_PRIVILEGES caused the error when multi-privileges version.  When I changed to a single-privilege struct, the error went away:
Instead of this:
private class TOKEN_PRIVILEGES
{
    public UInt32 PrivilegeCount;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)]
    public LUID_AND_ATTRIBUTES[] Privileges = new LUID_AND_ATTRIBUTES[2];
}

I now use this (no attribute array):
[StructLayout(LayoutKind.Sequential, Pack = 1)]
private struct TokPriv1Luid
{
    public int Count;
    public LUID Luid;
    public UInt32 Attr;
}

Open in new window


The only issue now is that RegLoadKey returns a non-zero value that is not a valid windows error message code (8589934613).  I will open a separate question for this.

Thanks.

Ps. Here is the full test code, in case it would help someone:
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());

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

Open in new window

0
 

Author Closing Comment

by:Lars007
ID: 37022453
Your suggestion did not solve the problem, but your reference to the p/invoke site helped.
0

Featured Post

Free Backup Tool for VMware and Hyper-V

Restore full virtual machine or individual guest files from 19 common file systems directly from the backup file. Schedule VM backups with PowerShell scripts. Set desired time, lean back and let the script to notify you via email upon completion.  

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

By default the complete memory dump option is disabled in windows . If we want to enable the complete memory dump for a diagnostic purpose, we have a solution for it. here we are using the registry method to enable this.
High user turnover can cause old/redundant user data to consume valuable space. UserResourceCleanup was developed to address this by automatically deleting user folders when the user account is deleted.
This Micro Tutorial will teach you how to change your appearance and customize your Windows 7 interface to your unique preference. This will be demonstrated using Windows 7 operating system.
The viewer will learn how to successfully create a multiboot device using the SARDU utility on Windows 7. Start the SARDU utility: Change the image directory to wherever you store your ISOs, this will prevent you from having 2 copies of an ISO wit…

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question