You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.9 KiB

6 years ago
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace Microsoft.Win32.Security
  4. {
  5. using DWORD = UInt32;
  6. using BOOL = Int32;
  7. /// <summary>
  8. /// Encapsulation of a Win32 token handle.
  9. /// The object is disposable because it maintains the Win32 handle.
  10. /// </summary>
  11. public abstract class AccessToken : DisposableObject
  12. {
  13. /// The win32 token handle.
  14. private IntPtr _handle;
  15. protected internal AccessToken(IntPtr handle)
  16. {
  17. _handle = handle;
  18. }
  19. protected override void Dispose(bool disposing)
  20. {
  21. if (_handle != IntPtr.Zero)
  22. {
  23. // We don't want to throw an exception here, because there's not
  24. // much we can do when failing to close a handle.
  25. BOOL rc = Win32.CloseHandle(_handle);
  26. if (rc != Win32.FALSE)
  27. _handle = IntPtr.Zero;
  28. }
  29. }
  30. /// <summary>
  31. /// Enable a single privilege on the process.
  32. /// </summary>
  33. /// <param name="privilege"></param>
  34. /// <exception cref="">Throws an exception if the privilege is not present
  35. /// in the privilege list of the process</exception>
  36. public void EnablePrivilege(TokenPrivilege privilege)
  37. {
  38. var privs = new TokenPrivileges {privilege};
  39. EnableDisablePrivileges(privs);
  40. }
  41. private void EnableDisablePrivileges(TokenPrivileges privileges)
  42. {
  43. UnsafeEnableDisablePrivileges(privileges);
  44. }
  45. private unsafe void UnsafeEnableDisablePrivileges(TokenPrivileges privileges)
  46. {
  47. byte[] privBytes = privileges.GetNativeTokenPrivileges();
  48. fixed (byte* priv = privBytes)
  49. {
  50. UInt32 cbLength;
  51. Win32.SetLastError(Win32.SUCCESS);
  52. BOOL rc = Win32.AdjustTokenPrivileges(
  53. _handle,
  54. Win32.FALSE,
  55. (IntPtr) priv,
  56. 0,
  57. IntPtr.Zero,
  58. out cbLength);
  59. Win32.CheckCall(rc);
  60. // Additional check: privilege can't be added, and in that case,
  61. // rc indicates a success, but GetLastError() has a specific meaning.
  62. if (Marshal.GetLastWin32Error() == Win32.ERROR_NOT_ALL_ASSIGNED)
  63. Win32.ThrowLastError();
  64. }
  65. }
  66. }
  67. /// <summary>
  68. /// Access token for a process
  69. /// </summary>
  70. public class AccessTokenProcess : AccessToken
  71. {
  72. public AccessTokenProcess(int pid, TokenAccessType desiredAccess)
  73. : base(OpenProcessToken(pid, desiredAccess))
  74. {
  75. }
  76. private static IntPtr TryOpenProcessToken(int pid, TokenAccessType desiredAccess)
  77. {
  78. IntPtr processHandle = Win32.OpenProcess(
  79. ProcessAccessType.PROCESS_QUERY_INFORMATION,
  80. Win32.FALSE,
  81. (uint) pid);
  82. if (processHandle == IntPtr.Zero)
  83. return IntPtr.Zero;
  84. Win32.CheckCall(processHandle);
  85. try
  86. {
  87. IntPtr handle;
  88. BOOL rc = Win32.OpenProcessToken(processHandle, desiredAccess, out handle);
  89. if (rc == Win32.FALSE)
  90. return IntPtr.Zero;
  91. return handle;
  92. }
  93. finally
  94. {
  95. Win32.CloseHandle(processHandle);
  96. }
  97. }
  98. private static IntPtr OpenProcessToken(int pid, TokenAccessType desiredAccess)
  99. {
  100. IntPtr handle = TryOpenProcessToken(pid, desiredAccess);
  101. if (handle == IntPtr.Zero)
  102. Win32.ThrowLastError();
  103. return handle;
  104. }
  105. }
  106. }