模拟在.NET在Windows 7(请求的注册表访问是不允许的) [英] Impersonation in .NET in Windows 7 (Requested registry access is not allowed)

查看:149
本文介绍了模拟在.NET在Windows 7(请求的注册表访问是不允许的)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我使用的是用户运行以下code即用户组的Windows 7中,64位机上的成员。我想使用模拟(通过登录的用户是管理员组的一部分),允许当前用户从注册表中读取。出于某种原因,用户登录成功后会发生,但即使WindowsIdentity.GetCurrent()的返回是管理员组我仍然得到请求的注册表访问不允许一个错误信息说的部分用户。我究竟做错了什么?

这是主要的code:

 昏暗RA由于运行方式=无
            如果UserDomain.Length> 0 AndAlso UserName.Length> 0 AndAlso UserPassword.Length> 0然后
                RA =新的运行方式
                ra.ImpersonateStart(USERDOMAIN,用户名的userPassword)
            结束如果
            如果不My.Computer.Registry.GetValue(HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows \ Windows错误报告,DontShowUI,0)是没有AndAlso _
            My.Computer.Registry.GetValue(HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows \ Windows错误报告,DontShowUI,0)= 0,那么
                    My.Computer.Registry.SetValue(HKEY_LOCAL_MACHINE \ SOFTWARE \微软\的Windows \ Windows错误报告,DontShowUI,1)
            结束如果
 

再假设我的RunAs类如下:

 公共类的RunAs
 公开声明自动功能CloseHandle的库KERNEL32.DLL(BYVAL句柄作为IntPtr的)作为布尔

    公开声明自动功能DuplicateToken库ADVAPI32.DLL(BYVAL ExistingTokenHandle作为IntPtr的,_
      BYVAL SECURITY_IMPERSONATION_LEVEL作为整数,_
      为ByRef DuplicateTokenHandle作为IntPtr的)作为布尔

    测试工具。
    如果你把这种code到DLL时,一定要要求FullTrust的。
    < PermissionSetAttribute(SecurityAction.Demand,名称:=FullTrust的)> _
    公用Sub ImpersonateStart(BYVAL域作为字符串,BYVAL用户名作为字符串,BYVAL密码作为字符串)
            tokenHandle = IntPtr.Zero
            调用LogonUser来获取句柄到一个访问令牌。
            昏暗的returnValue作为布尔= LogonUser的(用户名,域,密码,2,0,tokenHandle)

            检查是否登录成功
            如果的returnValue = false,那么
                昏暗RET作为整数= Marshal.GetLastWin32Error()
                Console.WriteLine(LogonUser的失败,错误code:{0},RET)
                抛出新System.ComponentModel.Win32Exception(RET)
                退出小组
            结束如果

            登录成功

            '使用的LogonUser返回的令牌句柄。
            昏暗NEWID作为新的WindowsIdentity(tokenHandle)
            impersonatedUser = newId.Impersonate()
    结束小组
末级
 

解决方案

我同意@Hans。通过UAC,您需要重新启动了UAC权限的应用程序,这将导致UAC提示显示。实现此目的的一个简单方法如下:

  1. 在该应用程序的正常路径,当需要管理员权限,重新启动与UAC要求和命令行标志,就像 /管理员应用程序。
  2. 在应用程序的第二次运行,检测标记 /管理员,并执行应用程序的管理部分。
  3. 当第二次运行结束(#2),如果它是成功的,然后继续应用程序逻辑从第一关。如果不成功,显示错误/执行适当的异常处理逻辑。

在我们的应用程序,我有一个名为helper方法 RunElevated ,试图重新启动应用程序与要求管理员权限,这将导致UAC提示显示(我也有包括我IsAdmin()辅助功能):

 专用功能RunElevated(命令行作为字符串,可选BYVAL超时为整数= 0)作为布尔
    昏暗的StartInfo作为新的ProcessStartInfo
    startInfo.UseShellExecute = TRUE
    startInfo.WorkingDirectory = Environment.CurrentDirectory
    昏暗URI作为新的URI(Assembly.GetEntryAssembly.GetName。codeBase类)
    startInfo.FileName = uri.LocalPath
    startInfo.Verb =运行方式
    startInfo.Arguments =命令行

    昏暗的成功作为布尔
    尝试
        昏暗的数p作为流程=的Process.Start(StartInfo的)
        等待30秒完成
        如果超时> 0然后
            如果不p.WaitForExit(30000)则
                没有完成在三秒,杀
                p.Kill()
                成功=假
            其他
                成功= TRUE
            结束如果
        其他
            p.WaitForExit()
            成功= TRUE
        结束如果
    抓住EX作为Win32Exception
        成功=假
    抓住EX为例外
        MSGBOX(试图启动应用程序以管理员身份发生了错误:&放大器; ex.Message)
        成功=假
    结束尝试
    返回成功
端功能

公共功能IsAdmin()作为布尔
    昏暗的ID作为的WindowsIdentity = WindowsIdentity.GetCurrent
    昏暗的数p作为新的WindowsPrincipal(ID)
    返回p.IsInRole(WindowsBuiltInRole.Administrator)
端功能
 

要使用,我通过一个标志和运行升高。就我而言,我有一个功能,设置注册表项,并使用标志 / setregistry 来表示该实例启动了UAC的目的只是设置的注册表项。这code看起来是这样的:

 昏暗的成功作为布尔
    如果不IsAdmin(),然后
        尝试创建注册表项以管理员身份
        成功= RunElevated(/ setregistry,30000)
        成功=成功而ValidateKeysSet()检查,如果它是成功的
        返回成功
    结束如果

    如果我们的管理员(不是IsAdmin()= FALSE),然后继续前进,在这里设置的键
 

然后,在启动逻辑(的Form_Load,因为这是一个形式应用),我检查是否该标志是present:

 如果Command.ToLower.Contains(/ setregistry),然后
        如果应用程序实例是设置注册表项,管理的唯一目的
        如果IsAdmin(),然后
            SetRegistryKeys()'设置键,因为我们都是admin
        其他
            MSGBOX(错误:应用程序必须以管理员身份运行设置注册表项。)
        结束如果
    其他
        执行正常启动过程
    结束如果
 

So I am using a user to run the following code that is a member of the "User" group on a Windows 7, x64 machine. I am trying to use impersonation (by logging in as a user that is part of the Administrator group) to allow the current user to read from the registry. For some reason the login happens successfully but even though WindowsIdentity.GetCurrent() is returning the user that is part of the Administrator group I am still getting an error message saying "Requested registry access is not allowed". What am I doing wrong?

This is the main code:

            Dim ra As RunAs = Nothing
            If UserDomain.Length > 0 AndAlso UserName.Length > 0 AndAlso UserPassword.Length > 0 Then
                ra = New RunAs
                ra.ImpersonateStart(UserDomain, UserName, UserPassword)
            End If
            If Not My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 0) Is Nothing AndAlso _
            My.Computer.Registry.GetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 0) = 0 Then
                    My.Computer.Registry.SetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting", "DontShowUI", 1)
            End If

And suppose my RunAs class is the following:

Public Class RunAs
 Public Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean

    Public Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, _
      ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
      ByRef DuplicateTokenHandle As IntPtr) As Boolean

    ' Test harness.
    ' If you incorporate this code into a DLL, be sure to demand FullTrust.
    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
    Public Sub ImpersonateStart(ByVal Domain As String, ByVal userName As String, ByVal Password As String)
            tokenHandle = IntPtr.Zero
            ' Call LogonUser to obtain a handle to an access token.
            Dim returnValue As Boolean = LogonUser(userName, Domain, Password, 2, 0, tokenHandle)

            'check if logon successful
            If returnValue = False Then
                Dim ret As Integer = Marshal.GetLastWin32Error()
                Console.WriteLine("LogonUser failed with error code : {0}", ret)
                Throw New System.ComponentModel.Win32Exception(ret)
                Exit Sub
            End If

            'Logon succeeded

            ' Use the token handle returned by LogonUser.
            Dim newId As New WindowsIdentity(tokenHandle)
            impersonatedUser = newId.Impersonate()
    End Sub
End Class

解决方案

I agree with @Hans. With UAC, you need to restart the application with UAC privileges, which will cause the UAC prompt to display. A simple way to accomplish this is as follows:

  1. In normal path of the application, when admin privileges are needed, restart the application with UAC request and a command-line flag, like /admin.
  2. On second run of the application, detect the flag /admin, and do the administrative part of the application.
  3. When the second run finishes (#2), if it was successful, then continue application logic from the first pass. If not successful, display error/perform appropriate exception handling logic.

In our application, I have a helper method called RunElevated that attempts to restart the application with requested administrator privileges, which will cause the UAC prompt to display (I have also included my IsAdmin() helper function):

Private Function RunElevated(commandLine As String, Optional ByVal timeout As Integer = 0) As Boolean
    Dim startInfo As New ProcessStartInfo
    startInfo.UseShellExecute = True
    startInfo.WorkingDirectory = Environment.CurrentDirectory
    Dim uri As New Uri(Assembly.GetEntryAssembly.GetName.CodeBase)
    startInfo.FileName = uri.LocalPath
    startInfo.Verb = "runas"
    startInfo.Arguments = commandLine

    Dim success As Boolean
    Try
        Dim p As Process = Process.Start(startInfo)
        ' wait thirty seconds for completion
        If timeout > 0 Then
            If Not p.WaitForExit(30000) Then
                ' did not complete in thirty seconds, so kill
                p.Kill()
                success = False
            Else
                success = True
            End If
        Else
            p.WaitForExit()
            success = True
        End If
    Catch ex As Win32Exception
        success = False
    Catch ex As Exception
        MsgBox("Error occurred while trying to start application as administrator: " & ex.Message)
        success = False
    End Try
    Return success
End Function

Public Function IsAdmin() As Boolean
    Dim id As WindowsIdentity = WindowsIdentity.GetCurrent
    Dim p As New WindowsPrincipal(id)
    Return p.IsInRole(WindowsBuiltInRole.Administrator)
End Function

To use, I pass a flag and run elevated. In my case, I have a function that sets registry keys, and uses the flag /setregistry to indicate that the instance is started for UAC purposes to just set the registry keys. That code looks something like this:

    Dim success As Boolean
    If Not IsAdmin() Then
        ' try to create the registry keys as administrator
        success = RunElevated("/setregistry", 30000)
        success = success And ValidateKeysSet() ' check if it was successful
        Return success
    End If

    ' If we are Admin (Not IsAdmin() = False), then go ahead and set the keys here

Then in the startup logic (Form_Load, since this is a forms application), I check if that flag is present:

    If Command.ToLower.Contains("/setregistry") Then
        ' if application instance is for sole purpose of setting registry keys as admin
        If IsAdmin() Then
            SetRegistryKeys() ' set the keys, since we are admin
        Else
            MsgBox("ERROR: Application must be run as administrator to set registry keys.")
        End If
    Else
        ' Perform normal startup process
    End If

这篇关于模拟在.NET在Windows 7(请求的注册表访问是不允许的)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆