CherryDT

Enabling and checking token privileges in VB.NET

Apr 27th, 2016
861
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 20.16 KB | None | 0 0
  1. ' ***********************************************************************
  2. ' This is what I used for testing this Stack Overflow answer I wrote:
  3. ' http://stackoverflow.com/a/36862571/1871033
  4. ' Especially the way the NativeMethods are defined and imported again
  5. ' are not how it should be, but it didn't matter for the answer, I just
  6. ' tried to get things to work quickly. So I share this full code for
  7. ' reference, so others don't have to puzzle it together like I had to,
  8. ' but it's not supposed to be a perfect example.
  9. ' Note that I only wrote parts of this code, the other part was written
  10. ' by SO user ElektroStudios.
  11. ' ***********************************************************************
  12.  
  13. Imports System.Runtime.InteropServices
  14. Imports WindowsApplication1.Form1.NativeMethods
  15. Imports System.ComponentModel
  16.  
  17. Public Class Form1
  18.     Public Class NativeMethods
  19.  
  20.         ' http://msdn.microsoft.com/en-us/library/windows/desktop/aa379295%28v=vs.85%29.aspx
  21.         <DllImport("advapi32.dll", SetLastError:=True)>
  22.         Public Shared Function OpenProcessToken(ByVal processHandle As IntPtr,
  23.                                             ByVal desiredAccess As TokenAccess,
  24.                                             ByRef tokenHandle As IntPtr
  25.         ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  26.         End Function
  27.  
  28.         ' http://msdn.microsoft.com/en-us/library/windows/desktop/aa379180%28v=vs.85%29.aspx
  29.         <DllImport("Advapi32.dll", SetLastError:=True, CharSet:=CharSet.Auto, BestFitMapping:=False, ThrowOnUnmappableChar:=True)>
  30.         Public Shared Function LookupPrivilegeValue(ByVal lpSystemName As String,
  31.                                                 ByVal lpName As String,
  32.                                                 ByRef lpLuid As Luid
  33.         ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  34.         End Function
  35.  
  36.         ' http://msdn.microsoft.com/es-es/library/windows/desktop/aa375202%28v=vs.85%29.aspx
  37.         <DllImport("Advapi32.dll", SetLastError:=True)>
  38.         Public Shared Function AdjustTokenPrivileges(ByVal tokenHandle As IntPtr,
  39.                                                  ByVal disableAllPrivileges As Boolean,
  40.                                                  ByRef newState As TokenPrivileges,
  41.                                                  ByVal bufferLength As Integer,
  42.                                                  ByRef refPreviousState As TokenPrivileges,
  43.                                                  ByRef refReturnLength As IntPtr
  44.         ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  45.         End Function
  46.  
  47.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa379304%28v=vs.85%29.aspx
  48.         <DllImport("Advapi32.dll", SetLastError:=True)>
  49.         Public Shared Function PrivilegeCheck(ByVal token As IntPtr,
  50.                               <[In], Out> ByRef privileges As PrivilegeSet,
  51.                                           ByRef refResult As Boolean
  52.         ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  53.         End Function
  54.  
  55.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa446616%28v=vs.85%29.aspx
  56.         <DllImport("advapi32.dll", SetLastError:=True)>
  57.         Public Shared Function DuplicateToken(ByVal tokenHandle As IntPtr,
  58.                                           ByVal impersonationLevel As SecurityImpersonationLevel,
  59.                                           ByRef duplicateTokenHandle As IntPtr
  60.         ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  61.         End Function
  62.  
  63.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671%28v=vs.85%29.aspx
  64.         <DllImport("Advapi32.dll", SetLastError:=True)>
  65.         Public Shared Function GetTokenInformation(ByVal tokenHandle As IntPtr,
  66.                                                ByVal tokenInformationClass As TokenInformationClass,
  67.                                                ByVal tokenInformation As IntPtr,
  68.                                                ByVal tokenInformationLength As Integer,
  69.                                                ByRef refReturnLength As Integer
  70.         ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  71.         End Function
  72.  
  73.         ' http://msdn.microsoft.com/en-us/library/windows/desktop/aa374905%28v=vs.85%29.aspx
  74.         <Flags>
  75.         Public Enum TokenAccess As UInteger
  76.             ' THIS ENUMERATION IS PARTIALLY DEFINED.
  77.             ' **************************************
  78.             AdjustPrivileges = &H20UI
  79.             Query = &H8UI
  80.             Duplicate = &H2UI
  81.         End Enum
  82.  
  83.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa379630%28v=vs.85%29.aspx
  84.         <Flags>
  85.         Public Enum TokenPrivilegeAttributes As UInteger
  86.             PrivilegeDisabled = &H0UI
  87.             PrivilegeEnabledByDefault = &H1UI
  88.             PrivilegeEnabled = &H2UI
  89.             PrivilegeRemoved = &H4UI
  90.             PrivilegeUsedForAccess = &H80000000UI
  91.         End Enum
  92.  
  93.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572(v=vs.85).aspx
  94.         Public Enum SecurityImpersonationLevel As Integer
  95.             SecurityAnonymous = 0
  96.             SecurityIdentification = 1
  97.             SecurityImpersonation = 2
  98.             SecurityDelegation = 3
  99.         End Enum
  100.  
  101.         ' http://msdn.microsoft.com/en-us/library/windows/desktop/aa379261%28v=vs.85%29.aspx
  102.         <StructLayout(LayoutKind.Sequential)>
  103.         Public Structure Luid
  104.             Public LowPart As UInteger
  105.             Public HighPart As Integer
  106.         End Structure
  107.  
  108.         ' http://msdn.microsoft.com/en-us/library/windows/desktop/aa379263%28v=vs.85%29.aspx
  109.         <StructLayout(LayoutKind.Sequential)>
  110.         Public Structure LuidAndAttributes
  111.             Public Luid As Luid
  112.             Public Attributes As TokenPrivilegeAttributes
  113.         End Structure
  114.  
  115.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa379630%28v=vs.85%29.aspx
  116.         <StructLayout(LayoutKind.Sequential)>
  117.         Public Structure TokenPrivileges
  118.             Public PrivilegeCount As UInteger
  119.  
  120.             <MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)>
  121.             Public Privileges As LuidAndAttributes()
  122.         End Structure
  123.  
  124.         ' https://msdn.microsoft.com/en-us/library/windows/desktop/aa379307%28v=vs.85%29.aspx
  125.         <StructLayout(LayoutKind.Sequential)>
  126.         Public Structure PrivilegeSet
  127.             Public PrivilegeCount As UInteger
  128.             Public Control As UInteger
  129.  
  130.             <MarshalAs(UnmanagedType.ByValArray, SizeConst:=1)>
  131.             Public Privileges As LuidAndAttributes()
  132.         End Structure
  133.  
  134.         Public Enum TokenInformationClass As UInteger
  135.             TokenUser = 1
  136.             TokenGroups
  137.             TokenPrivileges
  138.             TokenOwner
  139.             TokenPrimaryGroup
  140.             TokenDefaultDacl
  141.             TokenSource
  142.             TokenType
  143.             TokenImpersonationLevel
  144.             TokenStatistics
  145.             TokenRestrictedSids
  146.             TokenSessionId
  147.             TokenGroupsAndPrivileges
  148.             TokenSessionReference
  149.             TokenSandBoxInert
  150.             TokenAuditPolicy
  151.             TokenOrigin
  152.  
  153.         End Enum
  154.  
  155.         <DllImport("kernel32.dll", SetLastError:=True)> _
  156.         Public Shared Function CloseHandle(handle As IntPtr) As Boolean
  157.         End Function
  158.  
  159.         <DllImport("Advapi32.dll", SetLastError:=True, CharSet:=CharSet.Auto, BestFitMapping:=False, ThrowOnUnmappableChar:=True)>
  160.         Public Shared Function LookupPrivilegeName( _
  161.                                                   lpSystemName As String, _
  162.                                                   ByRef lpLuid As Luid, _
  163.                                                   lpName As System.Text.StringBuilder, _
  164.                                                   ByRef cchName As Integer _
  165.                                                   ) As <MarshalAs(UnmanagedType.Bool)> Boolean
  166.         End Function
  167.     End Class
  168.  
  169.     Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  170.         Dim pHandle As IntPtr = Process.GetCurrentProcess().Handle
  171.         Dim privilegeName As String = "SeShutdownPrivilege"
  172.         Dim tokenAccess As TokenAccess = (tokenAccess.AdjustPrivileges Or tokenAccess.Query Or tokenAccess.Duplicate)
  173.         Dim hToken As IntPtr
  174.         Dim hTokenDup As IntPtr
  175.  
  176.         Try
  177.             ' ****************************************************************************
  178.             ' 1st Step: Enable the "SeShutdownPrivilege" privilege in the current process.
  179.             ' ****************************************************************************
  180.  
  181.             Dim win32Err As Integer
  182.  
  183.             ' Get the process token.
  184.             NativeMethods.OpenProcessToken(pHandle, tokenAccess, hToken)
  185.  
  186.             ' Set up a LuidAndAttributes structure containing the privilege to enable,
  187.             ' getting the LUID that corresponds to the privilege.
  188.             Dim luAttr As New LuidAndAttributes
  189.             luAttr.Attributes = TokenPrivilegeAttributes.PrivilegeEnabled
  190.             NativeMethods.LookupPrivilegeValue(Nothing, privilegeName, luAttr.Luid)
  191.  
  192.             ' Set up a TokenPrivileges structure containing only the source privilege.
  193.             Dim newState As New TokenPrivileges
  194.             newState.PrivilegeCount = 1
  195.             newState.Privileges = New LuidAndAttributes() {luAttr}
  196.  
  197.             ' Set up a TokenPrivileges structure for the previous (modified) privileges.
  198.             Dim prevState As New TokenPrivileges
  199.             prevState = New TokenPrivileges
  200.             ReDim prevState.Privileges(CInt(newState.PrivilegeCount))
  201.  
  202.             ' Apply the TokenPrivileges structure to the source process token.
  203.             Dim bufferLength As Integer = Marshal.SizeOf(prevState)
  204.             Dim returnLength As IntPtr
  205.             If Not NativeMethods.AdjustTokenPrivileges(hToken, False, newState, bufferLength, prevState, returnLength) Then
  206.                 win32Err = Marshal.GetLastWin32Error
  207.                 MessageBox.Show("AdjustTokenPrivileges failed.")
  208.                 Throw New Win32Exception(win32Err)
  209.             End If
  210.  
  211.             ' *********************************************************************
  212.             ' Everything OK at this point,
  213.             ' as AdjustTokenPrivileges dididn't failed, I assume the privilege Is enabled in the process.
  214.             '
  215.             ' 2n Step: Check whether the privilege is enabled or not...
  216.             ' *********************************************************************
  217.  
  218.             ' Set up a new one LuidAndAttributes structure containing the privilege to check,
  219.             ' getting the LUID that corresponds to the privilege.
  220.             luAttr = New LuidAndAttributes
  221.             NativeMethods.LookupPrivilegeValue(Nothing, privilegeName, luAttr.Luid)
  222.  
  223.             ' *********************************************************************
  224.             ' Trying PrivilegeCheck and Duplicatetoken methodology...
  225.             ' *********************************************************************
  226.  
  227.             NativeMethods.DuplicateToken(hToken, SecurityImpersonationLevel.SecurityImpersonation, hTokenDup)
  228.             win32Err = Marshal.GetLastWin32Error
  229.  
  230.             If (hTokenDup <> IntPtr.Zero) Then
  231.                 Dim result As Boolean
  232.                 Dim pSet As New PrivilegeSet
  233.                 pSet.Control = 0
  234.                 pSet.PrivilegeCount = 1
  235.                 pSet.Privileges = New LuidAndAttributes() {luAttr}
  236.  
  237.                 If Not NativeMethods.PrivilegeCheck(hToken, pSet, result) Then
  238.                     win32Err = Marshal.GetLastWin32Error
  239.                     MessageBox.Show("PrivilegeCheck using original access-token failed.")
  240.                     ' Ignore exception, to continue with the GetTokenInformation methodology.
  241.                     ' Throw New Win32Exception(win32Err)
  242.  
  243.                 Else
  244.                     MessageBox.Show(String.Format("{0} (original token) state is: {1}",
  245.                                                       privilegeName, pSet.Privileges(0).Attributes.ToString()))
  246.  
  247.                     If Not NativeMethods.PrivilegeCheck(hTokenDup, pSet, result) Then
  248.                         win32Err = Marshal.GetLastWin32Error
  249.                         MessageBox.Show("PrivilegeCheck using impersonated access-token failed.")
  250.                         ' Ignore exception, to continue with the GetTokenInformation methodology.
  251.                         ' Throw New Win32Exception(win32Err)
  252.                     Else
  253.                         MessageBox.Show(String.Format("{0} (impersonated token) state is: {1}",
  254.                                                       privilegeName, pSet.Privileges(0).Attributes.ToString()))
  255.  
  256.                     End If
  257.  
  258.                 End If
  259.  
  260.             Else
  261.                 MessageBox.Show("DuplicateToken failed.")
  262.                 ' Ignore exception, to continue with the GetTokenInformation methodology.
  263.                 ' Throw New Win32Exception(win32Err)
  264.  
  265.             End If
  266.  
  267.             ' *********************************************************************
  268.             ' Trying GetTokenInformation methodology...
  269.             ' *********************************************************************
  270.  
  271.             Dim tkp As New TokenPrivileges
  272.             Dim tkpHandle As IntPtr = IntPtr.Zero ' <<< will be set later
  273.             Dim tkInfoLength As Integer = 0
  274.  
  275.             ' Here we call GetTokenInformation the first time to receive the length of the data it would like to store.
  276.             NativeMethods.GetTokenInformation(hToken, TokenInformationClass.TokenPrivileges, IntPtr.Zero, tkInfoLength, tkInfoLength)
  277.             win32Err = Marshal.GetLastWin32Error
  278.  
  279.             ' Since the "current" length we pass is 0, we'll always get "error" 122, which is fine. We also get the required length returned.
  280.             If (win32Err <> 122) Then
  281.                 MessageBox.Show("GetTokenInformation failed in the attempt to get the TokenPrivileges's size.")
  282.                 Throw New Win32Exception(win32Err)
  283.             Else
  284.                 Try
  285.                     ' Here we allocate memory for receiving the actual data. By now, tkInfoLength contains the size of the memory block we need to allocate.
  286.                     tkpHandle = Marshal.AllocHGlobal(tkInfoLength)
  287.  
  288.                     ' This time, we shouldn't get an error 122, because this time we already have set the correct buffer size. GetTokenInformation should now write the data into the memory block we just allocated.
  289.                     If Not NativeMethods.GetTokenInformation(hToken, TokenInformationClass.TokenPrivileges, tkpHandle, tkInfoLength, tkInfoLength) Then
  290.                         win32Err = Marshal.GetLastWin32Error
  291.                         MessageBox.Show("GetTokenInformation failed in the attempt to get the TokenPrivileges.")
  292.                         Throw New Win32Exception(win32Err)
  293.  
  294.                     Else
  295.                         ' We will now ask PtrToStructure to read the raw data out of the memory block and convert it to a managed structure of type TokenPrivileges which we can use in our code. That's it!
  296.                         tkp = Marshal.PtrToStructure(tkpHandle, GetType(TokenPrivileges))
  297.  
  298.                         ' We have to iterate over all privileges listed in the TokenPrivileges structure to find the one we are looking for
  299.                         Dim found As Boolean = False
  300.                         For i As Integer = 0 To tkp.PrivilegeCount - 1
  301.                             ' There is a problem: Marshal.PtrToStructure can't marshal variable-length structures, but the array TokenPrivileges::Privileges has
  302.                             ' a variable length determined by the value of TokenPrivileges::PrivilegeCount! Since we don't know the size at compile time, the
  303.                             ' size of the array was hardcoded to 1, which means that we would only be able to access the first element of the array.
  304.                             ' To work around this, we calculate the raw memory offset pointing to the array element we need and load it separately into a
  305.                             ' LuidAndAttributes variable.
  306.                             ' The way this works is: The contents of the TokenPrivilege structure or stored in memory one after another, like this:
  307.                             '   PrivilegeCount (type: UInteger)
  308.                             '   Privileges(0) (type: LuidAndAttributes)
  309.                             '   Privileges(1) (type: LuidAndAttributes) << these and all further we normally can't access
  310.                             '   Privileges(2) (type: LuidAndAttributes)
  311.                             ' ...and so on.
  312.                             ' We are now calculating the offset into the structure for a specific array element. Let's use Privileges(2) as example:
  313.                             ' To get to it, we need to take the pointer to the beginning of the structure and add the sizes of all previous elements,
  314.                             ' which would be once the size of PrivilegeCount and then 2 times the size of a LuidAndAttributes structure.
  315.                             Dim directPointer As New IntPtr(tkpHandle.ToInt64() + Len(tkp.PrivilegeCount) + i * Marshal.SizeOf(GetType(LuidAndAttributes)))
  316.                             Dim luidAndAttributes As LuidAndAttributes = Marshal.PtrToStructure(directPointer, GetType(LuidAndAttributes))
  317.  
  318.                             ' Get the privilege name. We first call LookupPrivilegeName with a zero size to get the real size we need, then reserve space, then get the actual data
  319.                             ' NOTE: The part below isn't actually necessary as commented Mark Hurd pointed out, because you already have the right privilege's LUID in luAttr.Luid.
  320.                             ' But I'll leave it here anyway in case somebody uses this piece of code without the part which sets the privilege.
  321.                             ' Another solution in this case would also be to run LookupPrivilegeValue to get the LUID to compare to (which is what led to luAttr.Luid as well).
  322.                             Dim privNameLen As Integer = 0
  323.                             Dim sb As New System.Text.StringBuilder()
  324.                             NativeMethods.LookupPrivilegeName(Nothing, luidAndAttributes.Luid, sb, privNameLen)
  325.                             sb.EnsureCapacity(privNameLen + 1)
  326.                             If Not NativeMethods.LookupPrivilegeName(Nothing, luidAndAttributes.Luid, sb, privNameLen) Then
  327.                                 win32Err = Marshal.GetLastWin32Error
  328.                                 MessageBox.Show("LookupPrivilegeName failed.")
  329.                                 Throw New Win32Exception(win32Err)
  330.                             End If
  331.  
  332.                             ' Now that we have the name, we can check if it's the one we are looking for.
  333.                             ' NOTE: Refering to me comments above, this could be just: If luidAndAttributes.Luid = luAttr.Luid
  334.                             If sb.ToString() = privilegeName Then
  335.                                 ' Found! So we can finally get the status of the privilege!
  336.                                 found = True
  337.                                 MessageBox.Show(String.Format("{0} state is: {1}", privilegeName, luidAndAttributes.Attributes.ToString()))
  338.                                 Exit For
  339.                             End If
  340.                         Next
  341.  
  342.                         If Not found Then MessageBox.Show(String.Format("{0} not found in list of privileges!", privilegeName))
  343.                     End If
  344.                 Finally
  345.                     ' Make sure the memory block is freed again (even when an error occured)
  346.                     If tkpHandle Then Marshal.FreeHGlobal(tkpHandle)
  347.                 End Try
  348.  
  349.             End If
  350.         Catch ex As Win32Exception
  351.             MessageBox.Show(ex.NativeErrorCode & " " & ex.Message)
  352.  
  353.         Catch ex As Exception
  354.             MessageBox.Show(ex.Message)
  355.  
  356.         Finally
  357.             If (hTokenDup <> IntPtr.Zero) Then
  358.                 NativeMethods.CloseHandle(hTokenDup)
  359.             End If
  360.  
  361.             If (hToken <> IntPtr.Zero) Then
  362.                 NativeMethods.CloseHandle(hToken)
  363.             End If
  364.  
  365.         End Try
  366.     End Sub
  367. End Class
Advertisement
Add Comment
Please, Sign In to add comment