/Visual Studio 2008/VBUACSelfElevation/ReadMe.txt
Plain Text | 401 lines | 332 code | 69 blank | 0 comment | 0 complexity | 8a2d1e13be70a21f7a5e9200f5fc3ced MD5 | raw file
- =============================================================================
- APPLICATION : VBUACSelfElevation Project Overview
- =============================================================================
-
- /////////////////////////////////////////////////////////////////////////////
- Summary:
-
- User Account Control (UAC) is a new security component in Windows Vista and
- newer operating systems. With UAC fully enabled, interactive administrators
- normally run with least user privileges. This example demonstrates how to
- check the privilege level of the current process, and how to self-elevate
- the process by giving explicit consent with the Consent UI.
-
-
- /////////////////////////////////////////////////////////////////////////////
- Prerequisite:
-
- You must run this sample on Windows Vista or newer operating systems.
-
-
- /////////////////////////////////////////////////////////////////////////////
- Demo:
-
- The following steps walk through a demonstration of the UAC sample.
-
- Step1. After you successfully build the sample project in Visual Studio 2008,
- you will get an application: VBUACSelfElevation.exe.
-
- Step2. Run the application as a protected administrator on a Windows Vista or
- Windows 7 system with UAC fully enabled. The application should display the
- following content on the main dialog.
-
- IsUserInAdminGroup: True
- IsRunAsAdmin: False
- IsProcessElevated: False
- Integrity Level: Medium
-
- There is a UAC shield icon on the Self-elevate button.
-
- Step3. Click on the Self-elevate button. You will see a Consent UI.
-
- User Account Control
- ----------------------------------
- Do you want to allow the following program from an unknown publisher to
- make changes to this computer?
-
- Step4. Click Yes to approve the elevation. The original application will then
- be started and display the following content on the main dialog.
-
- IsUserInAdminGroup: True
- IsRunAsAdmin: True
- IsProcessElevated: True
- Integrity Level: High
-
- The Self-elevate button on the dialog does not have the UAC shield icon this
- time. That is, the application is running as elevated administrator. The
- elevation succeeds. If you click on the Self-elevate button again, the
- application will tell you that it is running as administrator.
-
- Step5. Close the application.
-
-
- /////////////////////////////////////////////////////////////////////////////
- Creation:
-
- Step1. Create a new Visual Basic Windows Forms project named
- VBUACSelfElevation.
-
- Step2. Add controls to the main form
-
- Type: Button
- ID: btnElevate
- Caption: "Self-elevate"
-
- Type: Label
- ID: lbInAdminGroup
- Use: Display whether the primary access token of the process belongs to
- user account that is a member of the local Administrators group, even if it
- currently is not elevated.
-
- Type: Label
- ID: lbIsRunAsAdmin
- Use: Display whether the application is run as administrator.
-
- Type: Label
- ID: lbIsElevated
- Use: Display whether the process is elevated or not. Token elevation is
- only available on Windows Vista and newer operating systems. The label
- shows N/A on systems prior to Windows Vista.
-
- Type: Label
- ID: lbIntegrityLevel
- Use: Display the integrity level of the current process. Integrity level is
- only available on Windows Vista and newer operating systems. The label
- shows N/A on systems prior to Windows Vista.
-
- Step3. Check and display the current process's "run as administrator" status,
- elevation information and integrity level when the application initializes
- the main dialog.
-
- Create the following four helper functions:
-
- ''' <summary>
- ''' The function checks whether the primary access token of the process belongs
- ''' to user account that is a member of the local Administrators group, even if
- ''' it currently is not elevated.
- ''' </summary>
- ''' <returns>
- ''' Returns True if the primary access token of the process belongs to user
- ''' account that is a member of the local Administrators group. Returns False
- ''' if the token does not.
- ''' </returns>
- ''' <exception cref="System.ComponentModel.Win32Exception">
- ''' When any native Windows API call fails, the function throws a Win32Exception
- ''' with the last error code.
- ''' </exception>
- Friend Function IsUserInAdminGroup() As Boolean
-
- ''' <summary>
- ''' The function checks whether the current process is run as administrator.
- ''' In other words, it dictates whether the primary access token of the
- ''' process belongs to user account that is a member of the local
- ''' Administrators group and it is elevated.
- ''' </summary>
- ''' <returns>
- ''' Returns True if the primary access token of the process belongs to user
- ''' account that is a member of the local Administrators group and it is
- ''' elevated. Returns False if the token does not.
- ''' </returns>
- Friend Function IsRunAsAdmin() As Boolean
-
- ''' <summary>
- ''' The function gets the elevation information of the current process. It
- ''' dictates whether the process is elevated or not. Token elevation is only
- ''' available on Windows Vista and newer operating systems, thus
- ''' IsProcessElevated throws a C++ exception if it is called on systems prior
- ''' to Windows Vista. It is not appropriate to use this function to determine
- ''' whether a process is run as administartor.
- ''' </summary>
- ''' <returns>
- ''' Returns True if the process is elevated. Returns False if it is not.
- ''' </returns>
- ''' <exception cref="System.ComponentModel.Win32Exception">
- ''' When any native Windows API call fails, the function throws a Win32Exception
- ''' with the last error code.
- ''' </exception>
- ''' <remarks>
- ''' TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation
- ''' type (TokenElevationTypeDefault / TokenElevationTypeLimited /
- ''' TokenElevationTypeFull) of the process. It is different from TokenElevation
- ''' in that, when UAC is turned off, elevation type always returns
- ''' TokenElevationTypeDefault even though the process is elevated (Integrity
- ''' Level == High). In other words, it is not safe to say if the process is
- ''' elevated based on elevation type. Instead, we should use TokenElevation.
- ''' </remarks>
- Friend Function IsProcessElevated() As Boolean
-
- ''' <summary>
- ''' The function gets the integrity level of the current process. Integrity
- ''' level is only available on Windows Vista and newer operating systems, thus
- ''' GetProcessIntegrityLevel throws a C++ exception if it is called on systems
- ''' prior to Windows Vista.
- ''' </summary>
- ''' <returns>
- ''' Returns the integrity level of the current process. It is usually one of
- ''' these values:
- '''
- ''' SECURITY_MANDATORY_UNTRUSTED_RID - means untrusted level. It is used by
- ''' processes started by the Anonymous group. Blocks most write access.
- ''' (SID: S-1-16-0x0)
- '''
- ''' SECURITY_MANDATORY_LOW_RID - means low integrity level. It is used by
- ''' Protected Mode Internet Explorer. Blocks write acess to most objects
- ''' (such as files and registry keys) on the system. (SID: S-1-16-0x1000)
- '''
- ''' SECURITY_MANDATORY_MEDIUM_RID - means medium integrity level. It is used
- ''' by normal applications being launched while UAC is enabled.
- ''' (SID: S-1-16-0x2000)
- '''
- ''' SECURITY_MANDATORY_HIGH_RID - means high integrity level. It is used by
- ''' administrative applications launched through elevation when UAC is
- ''' enabled, or normal applications if UAC is disabled and the user is an
- ''' administrator. (SID: S-1-16-0x3000)
- '''
- ''' SECURITY_MANDATORY_SYSTEM_RID - means system integrity level. It is used
- ''' by services and other system-level applications (such as Wininit,
- ''' Winlogon, Smss, etc.) (SID: S-1-16-0x4000)
- '''
- ''' </returns>
- ''' <exception cref="System.ComponentModel.Win32Exception">
- ''' When any native Windows API call fails, the function throws a Win32Exception
- ''' with the last error code.
- ''' </exception>
- Friend Function GetProcessIntegrityLevel() As Integer
-
- Some of the methods need to P/Invoke some native Windows APIs. The P/Invoke
- signatures are defined in NativeMethod.vb.
-
- In the Load event of the main form, check and display the "run as
- administrator" status, the elevation information, and the integrity level of
- the current process.
-
- ' Get and display whether the primary access token of the process belongs
- ' to user account that is a member of the local Administrators group even
- ' if it currently is not elevated (IsUserInAdminGroup).
- Try
- Dim fInAdminGroup As Boolean = Me.IsUserInAdminGroup
- Me.lbInAdminGroup.Text = fInAdminGroup.ToString
- Catch ex As Exception
- Me.lbInAdminGroup.Text = "N/A"
- MessageBox.Show(ex.Message, "An error occurred in IsUserInAdminGroup", _
- MessageBoxButtons.OK, MessageBoxIcon.Error)
- End Try
-
- ' Get and display whether the process is run as administrator or not
- ' (IsRunAsAdmin).
- Try
- Dim fIsRunAsAdmin As Boolean = Me.IsRunAsAdmin
- Me.lbIsRunAsAdmin.Text = fIsRunAsAdmin.ToString
- Catch ex As Exception
- Me.lbIsRunAsAdmin.Text = "N/A"
- MessageBox.Show(ex.Message, "An error occurred in IsRunAsAdmin", _
- MessageBoxButtons.OK, MessageBoxIcon.Error)
- End Try
-
- ' Get and display the process elevation information (IsProcessElevated)
- ' and integrity level (GetProcessIntegrityLevel). The information is not
- ' available on operating systems prior to Windows Vista.
- If (Environment.OSVersion.Version.Major >= 6) Then
- ' Running Windows Vista or later (major version >= 6).
-
- Try
- ' Get and display the process elevation information.
- Dim fIsElevated As Boolean = Me.IsProcessElevated
- Me.lbIsElevated.Text = fIsElevated.ToString
-
- ' Update the Self-elevate button to show the UAC shield icon on
- ' the UI if the process is not elevated.
- Me.btnElevate.FlatStyle = FlatStyle.System
- NativeMethod.SendMessage(Me.btnElevate.Handle, NativeMethod.BCM_SETSHIELD, _
- 0, IIf(fIsElevated, IntPtr.Zero, New IntPtr(1)))
- Catch ex As Exception
- Me.lbIsElevated.Text = "N/A"
- MessageBox.Show(ex.Message, "An error occurred in IsProcessElevated", _
- MessageBoxButtons.OK, MessageBoxIcon.Error)
- End Try
-
- Try
- ' Get and display the process integrity level.
- Dim IL As Integer = Me.GetProcessIntegrityLevel
- Select Case IL
- Case NativeMethod.SECURITY_MANDATORY_UNTRUSTED_RID
- Me.lbIntegrityLevel.Text = "Untrusted"
- Case NativeMethod.SECURITY_MANDATORY_LOW_RID
- Me.lbIntegrityLevel.Text = "Low"
- Case NativeMethod.SECURITY_MANDATORY_MEDIUM_RID
- Me.lbIntegrityLevel.Text = "Medium"
- Case NativeMethod.SECURITY_MANDATORY_HIGH_RID
- Me.lbIntegrityLevel.Text = "High"
- Case NativeMethod.SECURITY_MANDATORY_SYSTEM_RID
- Me.lbIntegrityLevel.Text = "System"
- Case Else
- Me.lbIntegrityLevel.Text = "Unknown"
- End Select
- Catch ex As Exception
- Me.lbIntegrityLevel.Text = "N/A"
- MessageBox.Show(ex.Message, "An error occurred in GetProcessIntegrityLevel!", _
- MessageBoxButtons.OK, MessageBoxIcon.Hand)
- End Try
-
- Else
- Me.lbIsElevated.Text = "N/A"
- Me.lbIntegrityLevel.Text = "N/A"
- End If
-
- Step4. Handle the click event of the Self-elevate button. When user clicks
- the button, elevate the process by restarting itself with
- ProcessStartInfo.UseShellExecute = true and ProcessStartInfo.Verb = "runas"
- if the process is not run as administrator
-
- Private Sub btnElevate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
- Handles btnElevate.Click
- ' Elevate the process if it is not run as administrator.
- If (Not Me.IsRunAsAdmin) Then
- ' Launch itself as administrator
- Dim proc As New ProcessStartInfo
- proc.UseShellExecute = True
- proc.WorkingDirectory = Environment.CurrentDirectory
- proc.FileName = Application.ExecutablePath
- proc.Verb = "runas"
-
- Try
- Process.Start(proc)
- Catch
- ' The user refused the elevation.
- ' Do nothing and return directly ...
- Return
- End Try
-
- Application.Exit() ' Quit itself
- Else
- MessageBox.Show("The process is running as administrator", "UAC")
- End If
- End Sub
-
- Step5. Automatically elevate the process when it's started up.
-
- If your application always requires administrative privileges, such as during
- an installation step, the operating system can automatically prompt the user
- for privileges elevation each time your application is invoked.
-
- If a specific kind of resource (RT_MANIFEST) is found embedded within the
- application executable, the system looks for the <trustInfo> section and
- parses its contents. Here is an example of this section in the manifest file:
-
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel
- level="requireAdministrator"
- />
- </requestedPrivileges>
- </security>
- </trustInfo>
-
- Three different values are possible for the level attribute
-
- a) requireAdministrator
- The application must be started with Administrator privileges; it won't run
- otherwise.
-
- b) highestAvailable
- The application is started with the highest possible privileges.
- If the user is logged on with an Administrator account, an elevation prompt
- appears. If the user is a Standard User, the application is started
- (without any elevation prompt) with these standard privileges.
-
- c) asInvoker
- The application is started with the same privileges as the calling
- application.
-
- To configure the elevation level in this Visual Basic Windows Forms project,
- open the project's properties, turn to the Application tab, and click the
- "View UAC Settings" button. This creates an app.manifest file and configures
- the project to embed the manifest. You can find the "app.manifest" file in
- the "My Project" folder of the VB.NET project. The file has the following
- content by default.
-
- <?xml version="1.0" encoding="utf-8"?>
- <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"
- xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
- <security>
- <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
- <!-- UAC Manifest Options
- If you want to change the Windows User Account Control level replace the
- requestedExecutionLevel node with one of the following.
-
- <requestedExecutionLevel level="asInvoker" uiAccess="false" />
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
- <requestedExecutionLevel level="highestAvailable" uiAccess="false" />
-
- If you want to utilize File and Registry Virtualization for backward
- compatibility then delete the requestedExecutionLevel node.
- -->
- <requestedExecutionLevel level="asInvoker" uiAccess="false" />
- </requestedPrivileges>
- <applicationRequestMinimum>
- <PermissionSet class="System.Security.PermissionSet" version="1"
- Unrestricted="true" ID="Custom" SameSite="site" />
- <defaultAssemblyRequest permissionSetReference="Custom" />
- </applicationRequestMinimum>
- </security>
- </trustInfo>
- </asmv1:assembly>
-
- Here we are focusing on the line:
-
- <requestedExecutionLevel level="asInvoker" uiAccess="false" />
-
- You can change it to be
-
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
-
- to require the application always be started with Administrator privileges.
-
-
- /////////////////////////////////////////////////////////////////////////////
- References:
-
- MSDN: User Account Control
- http://msdn.microsoft.com/en-us/library/aa511445.aspx
-
- MSDN: Windows Vista Application Development Requirements for User Account
- Control Compatibility
- http://msdn.microsoft.com/en-us/library/bb530410.aspx
-
-
- /////////////////////////////////////////////////////////////////////////////