You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell调用LogonUserA实现用户模拟失败问题求助

问题:LogonUser与ImpersonateLoggedOnUser模拟远程用户失败

我编写了一段结合LogonUserA和ImpersonateLoggedOnUser Windows API函数的PowerShell代码,尝试模拟远程机器的管理员用户,但运行后发现并未切换身份,仍然是当前用户。

我的代码:

$userName = "administrator"
$domain = "target-win"
$password = Read-Host -Prompt 'Enter password:' -AsSecureString

function GetCurrentPrincipal
{
    return [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
}

$logonUserSignature =
@'
[DllImport( "advapi32.dll" )]
public static extern bool LogonUser( String lpszUserName,
                                 String lpszDomain,
                                 String lpszPassword,
                                 int dwLogonType,
                                 int dwLogonProvider,
                                 ref IntPtr phToken );
'@

$AdvApi32 = Add-Type -MemberDefinition $logonUserSignature -Name "AdvApi32" -Namespace "PsInvoke.NativeMethods" -PassThru

$closeHandleSignature =
@'
[DllImport( "kernel32.dll", CharSet = CharSet.Auto )]
public static extern bool CloseHandle( IntPtr handle );
'@

$Kernel32 = Add-Type -MemberDefinition $closeHandleSignature -Name "Kernel32" -Namespace "PsInvoke.NativeMethods" -PassThru


try
{
    $Logon32Provider = 3  #LOGON32_PROVIDER_WINNT50
    $Logon32Type = 9      #LOGON32_LOGON_NEW_CREDENTIALS
    $tokenHandle = [IntPtr]::Zero

    $success = $AdvApi32::LogonUser($userName, $domain, ([Net.NetworkCredential]::new('', $password).Password), $Logon32Type, $Logon32Provider, [Ref] $tokenHandle)
    if (!$success )
    {
        $retVal = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
        Write-Host "LogonUser was unsuccessful. Error code: $retVal"
        return
    }

    Write-Host "LogonUser was successful."
    Write-Host "Value of Windows NT token: $tokenHandle"

    $identityName = GetCurrentPrincipal
    Write-Host "Current Identity: $identityName"

    $newIdentity = New-Object System.Security.Principal.WindowsIdentity( $tokenHandle )
    $context = $newIdentity.Impersonate()

    $identityName = GetCurrentPrincipal
    Write-Host "Impersonating: $identityName"

}
catch [System.Exception]
{
    Write-Host $_.Exception.ToString()
}
finally
{
    if ( $context -ne $null )
    {
        $context.Undo()
    }
    if ( $tokenHandle -ne [System.IntPtr]::Zero )
    {
    $Kernel32::CloseHandle( $tokenHandle )
    }
}

运行输出:

LogonUser was successful.
Value of Windows NT token: 4364
Current Identity: COMPONENTS\Administrator
Impersonating: COMPONENTS\Administrator
True 

我认为代码逻辑正确,但无法定位问题,求解决建议。


解决建议
  • 修改登录类型(LogonType):你当前使用的LOGON32_LOGON_NEW_CREDENTIALS(值为9)仅用于后续网络请求时替换凭证,不会改变本地线程的执行身份。要真正切换本地上下文用户,建议使用:

    • LOGON32_LOGON_INTERACTIVE(值为2):交互式登录,提供完整的用户上下文
    • LOGON32_LOGON_NETWORK_CLEARTEXT(值为8):明文网络登录,适合明确的身份切换场景
  • 验证登录提供者匹配:对应修改后的登录类型,可保留LOGON32_PROVIDER_WINNT50(值为3),或改用LOGON32_PROVIDER_DEFAULT(值为0),确保两者兼容。

  • 检查密码转换正确性:临时添加输出,验证([Net.NetworkCredential]::new('', $password).Password)是否正确将安全字符串转为明文密码,避免凭证传递错误。

  • 确认权限配置:当前运行PowerShell的用户必须拥有SeImpersonatePrivilege或SeAssignPrimaryTokenPrivilege权限,否则模拟操作会静默失败。可执行以下命令检查权限:

    whoami /priv
    
  • 直接调用Win32模拟API:替换.NET的$newIdentity.Impersonate(),改用原生ImpersonateLoggedOnUser API更可靠。添加以下签名到$logonUserSignature中:

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
    

    然后在代码中调用$AdvApi32::ImpersonateLoggedOnUser($tokenHandle),并检查返回值是否成功。


内容的提问来源于stack exchange,提问作者sbagnato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 08:13:10