-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTokenPrivilegeHelper.cs
111 lines (93 loc) · 4.15 KB
/
TokenPrivilegeHelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Optimizer
{
/*
* Allows clients to obtain a Windows token privilege for a well-defined scope simply by "using" an instance of this class.
*/
sealed class TokenPrivilegeHelper : IDisposable
{
private enum PrivilegeAction : uint
{
Disable = 0x0,
Enable = 0x2
}
public static TokenPrivilegeHelper Backup => new TokenPrivilegeHelper("SeBackupPrivilege");
public static TokenPrivilegeHelper Restore => new TokenPrivilegeHelper("SeRestorePrivilege");
public static TokenPrivilegeHelper TakeOwnership => new TokenPrivilegeHelper("SeTakeOwnershipPrivilege");
private readonly string privilegeName;
private TokenPrivilegeHelper(string privilegeName)
{
this.privilegeName = privilegeName;
Apply(PrivilegeAction.Enable);
}
private void Apply(PrivilegeAction action)
{
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out IntPtr tokenHandle);
LookupPrivilegeValue(null, privilegeName, out Luid luid);
var tokenPrivilege = new TokenPrivileges(luid, (uint)action);
UpdateTokenPrivileges(tokenHandle, tokenPrivilege);
}
private void UpdateTokenPrivileges(IntPtr tokenHandle, TokenPrivileges privilegeInfo)
{
bool successful = AdjustTokenPrivileges(tokenHandle, false, ref privilegeInfo, 0, IntPtr.Zero, IntPtr.Zero);
if (!successful || Marshal.GetLastWin32Error() == ERROR_NOT_ALL_ASSIGNED)
throw new SecurityException($"Can't adjust token privilege {privilegeName}");
}
public void Dispose()
{
Apply(PrivilegeAction.Disable);
}
#region P/Invoke structs and methods
private const int ERROR_NOT_ALL_ASSIGNED = 1300;
[StructLayout(LayoutKind.Sequential)]
private struct TokenPrivileges
{
// We can use this struct only with one privilege since CLR doesn't support marshalling dynamic-sized arrays
public TokenPrivileges(Luid luid, uint attributes)
{
Count = 1;
Privileges = new[] {
new LuidAndAttributes(luid, attributes)
};
}
private uint Count;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
private LuidAndAttributes[] Privileges;
}
[StructLayout(LayoutKind.Sequential)]
private readonly struct LuidAndAttributes
{
public LuidAndAttributes(Luid luid, uint attributes)
{
Luid = luid;
Attributes = attributes;
}
private readonly Luid Luid;
private readonly uint Attributes;
}
[StructLayout(LayoutKind.Sequential)]
private readonly struct Luid
{
private readonly uint LowPart;
private readonly int HighPart;
}
private const int TOKEN_QUERY = 0x8;
private const int TOKEN_ADJUST_PRIVILEGES = 0x20;
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
bool disableAllPrivileges,
ref TokenPrivileges newState,
int bufferLength,
IntPtr previousState,
IntPtr returnLength);
[DllImport("kernel32.dll")]
private static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(IntPtr processHandle, int desiredAccess, out IntPtr tokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LookupPrivilegeValue(string systemName, string privilegeName, out Luid privilegeLuid);
#endregion
}
}