PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/Visual Studio 2008/VBUACSelfElevation/ReadMe.txt

#
Plain Text | 401 lines | 332 code | 69 blank | 0 comment | 0 complexity | 8a2d1e13be70a21f7a5e9200f5fc3ced MD5 | raw file
  1. =============================================================================
  2. APPLICATION : VBUACSelfElevation Project Overview
  3. =============================================================================
  4. /////////////////////////////////////////////////////////////////////////////
  5. Summary:
  6. User Account Control (UAC) is a new security component in Windows Vista and
  7. newer operating systems. With UAC fully enabled, interactive administrators
  8. normally run with least user privileges. This example demonstrates how to
  9. check the privilege level of the current process, and how to self-elevate
  10. the process by giving explicit consent with the Consent UI.
  11. /////////////////////////////////////////////////////////////////////////////
  12. Prerequisite:
  13. You must run this sample on Windows Vista or newer operating systems.
  14. /////////////////////////////////////////////////////////////////////////////
  15. Demo:
  16. The following steps walk through a demonstration of the UAC sample.
  17. Step1. After you successfully build the sample project in Visual Studio 2008,
  18. you will get an application: VBUACSelfElevation.exe.
  19. Step2. Run the application as a protected administrator on a Windows Vista or
  20. Windows 7 system with UAC fully enabled. The application should display the
  21. following content on the main dialog.
  22. IsUserInAdminGroup: True
  23. IsRunAsAdmin: False
  24. IsProcessElevated: False
  25. Integrity Level: Medium
  26. There is a UAC shield icon on the Self-elevate button.
  27. Step3. Click on the Self-elevate button. You will see a Consent UI.
  28. User Account Control
  29. ----------------------------------
  30. Do you want to allow the following program from an unknown publisher to
  31. make changes to this computer?
  32. Step4. Click Yes to approve the elevation. The original application will then
  33. be started and display the following content on the main dialog.
  34. IsUserInAdminGroup: True
  35. IsRunAsAdmin: True
  36. IsProcessElevated: True
  37. Integrity Level: High
  38. The Self-elevate button on the dialog does not have the UAC shield icon this
  39. time. That is, the application is running as elevated administrator. The
  40. elevation succeeds. If you click on the Self-elevate button again, the
  41. application will tell you that it is running as administrator.
  42. Step5. Close the application.
  43. /////////////////////////////////////////////////////////////////////////////
  44. Creation:
  45. Step1. Create a new Visual Basic Windows Forms project named
  46. VBUACSelfElevation.
  47. Step2. Add controls to the main form
  48. Type: Button
  49. ID: btnElevate
  50. Caption: "Self-elevate"
  51. Type: Label
  52. ID: lbInAdminGroup
  53. Use: Display whether the primary access token of the process belongs to
  54. user account that is a member of the local Administrators group, even if it
  55. currently is not elevated.
  56. Type: Label
  57. ID: lbIsRunAsAdmin
  58. Use: Display whether the application is run as administrator.
  59. Type: Label
  60. ID: lbIsElevated
  61. Use: Display whether the process is elevated or not. Token elevation is
  62. only available on Windows Vista and newer operating systems. The label
  63. shows N/A on systems prior to Windows Vista.
  64. Type: Label
  65. ID: lbIntegrityLevel
  66. Use: Display the integrity level of the current process. Integrity level is
  67. only available on Windows Vista and newer operating systems. The label
  68. shows N/A on systems prior to Windows Vista.
  69. Step3. Check and display the current process's "run as administrator" status,
  70. elevation information and integrity level when the application initializes
  71. the main dialog.
  72. Create the following four helper functions:
  73. ''' <summary>
  74. ''' The function checks whether the primary access token of the process belongs
  75. ''' to user account that is a member of the local Administrators group, even if
  76. ''' it currently is not elevated.
  77. ''' </summary>
  78. ''' <returns>
  79. ''' Returns True if the primary access token of the process belongs to user
  80. ''' account that is a member of the local Administrators group. Returns False
  81. ''' if the token does not.
  82. ''' </returns>
  83. ''' <exception cref="System.ComponentModel.Win32Exception">
  84. ''' When any native Windows API call fails, the function throws a Win32Exception
  85. ''' with the last error code.
  86. ''' </exception>
  87. Friend Function IsUserInAdminGroup() As Boolean
  88. ''' <summary>
  89. ''' The function checks whether the current process is run as administrator.
  90. ''' In other words, it dictates whether the primary access token of the
  91. ''' process belongs to user account that is a member of the local
  92. ''' Administrators group and it is elevated.
  93. ''' </summary>
  94. ''' <returns>
  95. ''' Returns True if the primary access token of the process belongs to user
  96. ''' account that is a member of the local Administrators group and it is
  97. ''' elevated. Returns False if the token does not.
  98. ''' </returns>
  99. Friend Function IsRunAsAdmin() As Boolean
  100. ''' <summary>
  101. ''' The function gets the elevation information of the current process. It
  102. ''' dictates whether the process is elevated or not. Token elevation is only
  103. ''' available on Windows Vista and newer operating systems, thus
  104. ''' IsProcessElevated throws a C++ exception if it is called on systems prior
  105. ''' to Windows Vista. It is not appropriate to use this function to determine
  106. ''' whether a process is run as administartor.
  107. ''' </summary>
  108. ''' <returns>
  109. ''' Returns True if the process is elevated. Returns False if it is not.
  110. ''' </returns>
  111. ''' <exception cref="System.ComponentModel.Win32Exception">
  112. ''' When any native Windows API call fails, the function throws a Win32Exception
  113. ''' with the last error code.
  114. ''' </exception>
  115. ''' <remarks>
  116. ''' TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation
  117. ''' type (TokenElevationTypeDefault / TokenElevationTypeLimited /
  118. ''' TokenElevationTypeFull) of the process. It is different from TokenElevation
  119. ''' in that, when UAC is turned off, elevation type always returns
  120. ''' TokenElevationTypeDefault even though the process is elevated (Integrity
  121. ''' Level == High). In other words, it is not safe to say if the process is
  122. ''' elevated based on elevation type. Instead, we should use TokenElevation.
  123. ''' </remarks>
  124. Friend Function IsProcessElevated() As Boolean
  125. ''' <summary>
  126. ''' The function gets the integrity level of the current process. Integrity
  127. ''' level is only available on Windows Vista and newer operating systems, thus
  128. ''' GetProcessIntegrityLevel throws a C++ exception if it is called on systems
  129. ''' prior to Windows Vista.
  130. ''' </summary>
  131. ''' <returns>
  132. ''' Returns the integrity level of the current process. It is usually one of
  133. ''' these values:
  134. '''
  135. ''' SECURITY_MANDATORY_UNTRUSTED_RID - means untrusted level. It is used by
  136. ''' processes started by the Anonymous group. Blocks most write access.
  137. ''' (SID: S-1-16-0x0)
  138. '''
  139. ''' SECURITY_MANDATORY_LOW_RID - means low integrity level. It is used by
  140. ''' Protected Mode Internet Explorer. Blocks write acess to most objects
  141. ''' (such as files and registry keys) on the system. (SID: S-1-16-0x1000)
  142. '''
  143. ''' SECURITY_MANDATORY_MEDIUM_RID - means medium integrity level. It is used
  144. ''' by normal applications being launched while UAC is enabled.
  145. ''' (SID: S-1-16-0x2000)
  146. '''
  147. ''' SECURITY_MANDATORY_HIGH_RID - means high integrity level. It is used by
  148. ''' administrative applications launched through elevation when UAC is
  149. ''' enabled, or normal applications if UAC is disabled and the user is an
  150. ''' administrator. (SID: S-1-16-0x3000)
  151. '''
  152. ''' SECURITY_MANDATORY_SYSTEM_RID - means system integrity level. It is used
  153. ''' by services and other system-level applications (such as Wininit,
  154. ''' Winlogon, Smss, etc.) (SID: S-1-16-0x4000)
  155. '''
  156. ''' </returns>
  157. ''' <exception cref="System.ComponentModel.Win32Exception">
  158. ''' When any native Windows API call fails, the function throws a Win32Exception
  159. ''' with the last error code.
  160. ''' </exception>
  161. Friend Function GetProcessIntegrityLevel() As Integer
  162. Some of the methods need to P/Invoke some native Windows APIs. The P/Invoke
  163. signatures are defined in NativeMethod.vb.
  164. In the Load event of the main form, check and display the "run as
  165. administrator" status, the elevation information, and the integrity level of
  166. the current process.
  167. ' Get and display whether the primary access token of the process belongs
  168. ' to user account that is a member of the local Administrators group even
  169. ' if it currently is not elevated (IsUserInAdminGroup).
  170. Try
  171. Dim fInAdminGroup As Boolean = Me.IsUserInAdminGroup
  172. Me.lbInAdminGroup.Text = fInAdminGroup.ToString
  173. Catch ex As Exception
  174. Me.lbInAdminGroup.Text = "N/A"
  175. MessageBox.Show(ex.Message, "An error occurred in IsUserInAdminGroup", _
  176. MessageBoxButtons.OK, MessageBoxIcon.Error)
  177. End Try
  178. ' Get and display whether the process is run as administrator or not
  179. ' (IsRunAsAdmin).
  180. Try
  181. Dim fIsRunAsAdmin As Boolean = Me.IsRunAsAdmin
  182. Me.lbIsRunAsAdmin.Text = fIsRunAsAdmin.ToString
  183. Catch ex As Exception
  184. Me.lbIsRunAsAdmin.Text = "N/A"
  185. MessageBox.Show(ex.Message, "An error occurred in IsRunAsAdmin", _
  186. MessageBoxButtons.OK, MessageBoxIcon.Error)
  187. End Try
  188. ' Get and display the process elevation information (IsProcessElevated)
  189. ' and integrity level (GetProcessIntegrityLevel). The information is not
  190. ' available on operating systems prior to Windows Vista.
  191. If (Environment.OSVersion.Version.Major >= 6) Then
  192. ' Running Windows Vista or later (major version >= 6).
  193. Try
  194. ' Get and display the process elevation information.
  195. Dim fIsElevated As Boolean = Me.IsProcessElevated
  196. Me.lbIsElevated.Text = fIsElevated.ToString
  197. ' Update the Self-elevate button to show the UAC shield icon on
  198. ' the UI if the process is not elevated.
  199. Me.btnElevate.FlatStyle = FlatStyle.System
  200. NativeMethod.SendMessage(Me.btnElevate.Handle, NativeMethod.BCM_SETSHIELD, _
  201. 0, IIf(fIsElevated, IntPtr.Zero, New IntPtr(1)))
  202. Catch ex As Exception
  203. Me.lbIsElevated.Text = "N/A"
  204. MessageBox.Show(ex.Message, "An error occurred in IsProcessElevated", _
  205. MessageBoxButtons.OK, MessageBoxIcon.Error)
  206. End Try
  207. Try
  208. ' Get and display the process integrity level.
  209. Dim IL As Integer = Me.GetProcessIntegrityLevel
  210. Select Case IL
  211. Case NativeMethod.SECURITY_MANDATORY_UNTRUSTED_RID
  212. Me.lbIntegrityLevel.Text = "Untrusted"
  213. Case NativeMethod.SECURITY_MANDATORY_LOW_RID
  214. Me.lbIntegrityLevel.Text = "Low"
  215. Case NativeMethod.SECURITY_MANDATORY_MEDIUM_RID
  216. Me.lbIntegrityLevel.Text = "Medium"
  217. Case NativeMethod.SECURITY_MANDATORY_HIGH_RID
  218. Me.lbIntegrityLevel.Text = "High"
  219. Case NativeMethod.SECURITY_MANDATORY_SYSTEM_RID
  220. Me.lbIntegrityLevel.Text = "System"
  221. Case Else
  222. Me.lbIntegrityLevel.Text = "Unknown"
  223. End Select
  224. Catch ex As Exception
  225. Me.lbIntegrityLevel.Text = "N/A"
  226. MessageBox.Show(ex.Message, "An error occurred in GetProcessIntegrityLevel!", _
  227. MessageBoxButtons.OK, MessageBoxIcon.Hand)
  228. End Try
  229. Else
  230. Me.lbIsElevated.Text = "N/A"
  231. Me.lbIntegrityLevel.Text = "N/A"
  232. End If
  233. Step4. Handle the click event of the Self-elevate button. When user clicks
  234. the button, elevate the process by restarting itself with
  235. ProcessStartInfo.UseShellExecute = true and ProcessStartInfo.Verb = "runas"
  236. if the process is not run as administrator
  237. Private Sub btnElevate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
  238. Handles btnElevate.Click
  239. ' Elevate the process if it is not run as administrator.
  240. If (Not Me.IsRunAsAdmin) Then
  241. ' Launch itself as administrator
  242. Dim proc As New ProcessStartInfo
  243. proc.UseShellExecute = True
  244. proc.WorkingDirectory = Environment.CurrentDirectory
  245. proc.FileName = Application.ExecutablePath
  246. proc.Verb = "runas"
  247. Try
  248. Process.Start(proc)
  249. Catch
  250. ' The user refused the elevation.
  251. ' Do nothing and return directly ...
  252. Return
  253. End Try
  254. Application.Exit() ' Quit itself
  255. Else
  256. MessageBox.Show("The process is running as administrator", "UAC")
  257. End If
  258. End Sub
  259. Step5. Automatically elevate the process when it's started up.
  260. If your application always requires administrative privileges, such as during
  261. an installation step, the operating system can automatically prompt the user
  262. for privileges elevation each time your application is invoked.
  263. If a specific kind of resource (RT_MANIFEST) is found embedded within the
  264. application executable, the system looks for the <trustInfo> section and
  265. parses its contents. Here is an example of this section in the manifest file:
  266. <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
  267. <security>
  268. <requestedPrivileges>
  269. <requestedExecutionLevel
  270. level="requireAdministrator"
  271. />
  272. </requestedPrivileges>
  273. </security>
  274. </trustInfo>
  275. Three different values are possible for the level attribute
  276. a) requireAdministrator
  277. The application must be started with Administrator privileges; it won't run
  278. otherwise.
  279. b) highestAvailable
  280. The application is started with the highest possible privileges.
  281. If the user is logged on with an Administrator account, an elevation prompt
  282. appears. If the user is a Standard User, the application is started
  283. (without any elevation prompt) with these standard privileges.
  284. c) asInvoker
  285. The application is started with the same privileges as the calling
  286. application.
  287. To configure the elevation level in this Visual Basic Windows Forms project,
  288. open the project's properties, turn to the Application tab, and click the
  289. "View UAC Settings" button. This creates an app.manifest file and configures
  290. the project to embed the manifest. You can find the "app.manifest" file in
  291. the "My Project" folder of the VB.NET project. The file has the following
  292. content by default.
  293. <?xml version="1.0" encoding="utf-8"?>
  294. <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"
  295. xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
  296. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  297. <assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
  298. <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
  299. <security>
  300. <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
  301. <!-- UAC Manifest Options
  302. If you want to change the Windows User Account Control level replace the
  303. requestedExecutionLevel node with one of the following.
  304. <requestedExecutionLevel level="asInvoker" uiAccess="false" />
  305. <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
  306. <requestedExecutionLevel level="highestAvailable" uiAccess="false" />
  307. If you want to utilize File and Registry Virtualization for backward
  308. compatibility then delete the requestedExecutionLevel node.
  309. -->
  310. <requestedExecutionLevel level="asInvoker" uiAccess="false" />
  311. </requestedPrivileges>
  312. <applicationRequestMinimum>
  313. <PermissionSet class="System.Security.PermissionSet" version="1"
  314. Unrestricted="true" ID="Custom" SameSite="site" />
  315. <defaultAssemblyRequest permissionSetReference="Custom" />
  316. </applicationRequestMinimum>
  317. </security>
  318. </trustInfo>
  319. </asmv1:assembly>
  320. Here we are focusing on the line:
  321. <requestedExecutionLevel level="asInvoker" uiAccess="false" />
  322. You can change it to be
  323. <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
  324. to require the application always be started with Administrator privileges.
  325. /////////////////////////////////////////////////////////////////////////////
  326. References:
  327. MSDN: User Account Control
  328. http://msdn.microsoft.com/en-us/library/aa511445.aspx
  329. MSDN: Windows Vista Application Development Requirements for User Account
  330. Control Compatibility
  331. http://msdn.microsoft.com/en-us/library/bb530410.aspx
  332. /////////////////////////////////////////////////////////////////////////////