Lars007
asked on
AdjustTokenPrivileges fails with error 87 (invalid parameter)
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):
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!
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;
}
}
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!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
ASKER
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:
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:
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;
}
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);
}
}
}
}
ASKER
Your suggestion did not solve the problem, but your reference to the p/invoke site helped.
ASKER
Other suggestions?