c# - Windows 7 中的 .NET 模拟(不允许请求的注册表访问)

标签 c# .net vb.net

因此,我使用一个用户来运行以下代码,该用户是 Windows 7 x64 计算机上“用户”组的成员。我正在尝试使用模拟(通过以属于管理员组的用户身份登录)来允许当前用户从注册表中读取数据。由于某种原因,登录成功,但即使 WindowsIdentity.GetCurrent() 返回属于管理员组的用户,我仍然收到一条错误消息,指出“不允许请求的注册表访问”。我做错了什么?

这是主要代码:

            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

假设我的 RunAs 类如下:

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

最佳答案

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

  1. 在应用程序的正常路径中,当需要管理员权限时,请使用 UAC 请求和命令行标志重新启动应用程序,例如 /admin
  2. 第二次运行应用程序时,检测标志 /admin,并执行应用程序的管理部分。
  3. 当第二次运行完成 (#2) 时,如果成功,则继续第一遍的应用程序逻辑。如果不成功,则显示错误/执行适当的异常处理逻辑。

在我们的应用程序中,我有一个名为 RunElevated 的帮助程序方法,它尝试使用请求的管理员权限重新启动应用程序,这将导致显示 UAC 提示(我还包含了我的 IsAdmin() 帮助程序函数):

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

使用时,我传递一个标志并运行提升。就我而言,我有一个设置注册表项的函数,并使用标志 /setregistry 来指示实例是出于 UAC 目的而启动的,以便仅设置注册表项。该代码看起来像这样:

    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

然后在启动逻辑(Form_Load,因为这是一个表单应用程序)中,我检查该标志是否存在:

    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

关于c# - Windows 7 中的 .NET 模拟(不允许请求的注册表访问),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7573192/

相关文章:

c# - 切片器连接不显示可透视的更改后数据源

c# - 在 C# 中使用鼠标拖动重新调整旋转矩形的大小

c# - 有没有办法找到控件的所有者线程?

.net - 即使浏览器站点关闭,Log4net 文件也会被锁定

regex - 去除字符串中的html标签

vb.net - 获取事件窗口的标题

c# - 如何删除C#中DataGridView的默认第一行?

.net - 如何生成 WSDL 文件?

c# - 使用viewmodel在wpf窗口中实现进度条

c# - 使用 EPPlus 获取单元格的行号