获取运行explorer.exe的用户Token时遇“无效模拟令牌无法复制”错误求助
问题:获取explorer.exe进程用户Token时遇"无法复制无效模拟令牌"错误
尝试获取运行explorer.exe的用户Token时遇到错误,错误信息如下:
New-Object : 调用".ctor"时使用"1"个参数发生异常: "无效的模拟令牌 - 无法复制。"
位于第13行:26字符
- ... essToken = (New-Object System.Security.Principal.WindowsIdentity -Arg ...
CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
使用的PowerShell代码:
# 指定目标用户名 $targetUsername = "$env:username" # 获取目标用户运行的进程 $processes = Get-WmiObject -Class Win32_Process -Filter "Name = 'explorer.exe'" | Where-Object { $_.GetOwner().User -eq $targetUsername } if ($processes.Count -eq 0) { Write-Host "未找到用户 $targetUsername 的进程" } else { foreach ($process in $processes) { # 获取进程的安全令牌 $processHandle = [System.Diagnostics.Process]::GetProcessById($process.ProcessId).Handle $processToken = (New-Object System.Security.Principal.WindowsIdentity -ArgumentList $processHandle).Token Write-Host "$targetUsername 的Token: $processToken" } }
错误原因及解决办法
原因
直接用进程句柄构造WindowsIdentity时,默认会尝试复制令牌用于模拟操作,但当前进程要么权限不足,要么原令牌不允许被复制或用于模拟。此外,GetProcessById获取的进程句柄默认没有足够权限访问进程令牌的敏感信息。
修复方案
- 必须以管理员身份运行PowerShell:没有管理员权限,无法获取操作进程令牌的必要权限。
- 调用Windows API正确复制令牌:通过
OpenProcessToken和DuplicateTokenExAPI获取可使用的令牌,替代直接用进程句柄构造WindowsIdentity的方式。
修改后的完整代码:
Add-Type @" using System; using System.Runtime.InteropServices; public class TokenHelper { [DllImport("advapi32.dll", SetLastError = true)] public static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle); [DllImport("advapi32.dll", SetLastError = true)] public static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, IntPtr lpTokenAttributes, int ImpersonationLevel, int TokenType, out IntPtr DuplicateTokenHandle); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool CloseHandle(IntPtr hObject); public const uint TOKEN_QUERY = 0x0008; public const uint TOKEN_DUPLICATE = 0x0002; public const int SecurityImpersonation = 2; public const int TokenPrimary = 1; } "@ # 指定目标用户名 $targetUsername = "$env:username" # 获取目标用户运行的explorer.exe进程 $processes = Get-WmiObject -Class Win32_Process -Filter "Name = 'explorer.exe'" | Where-Object { $_.GetOwner().User -eq $targetUsername } if (-not $processes) { Write-Host "未找到用户 $targetUsername 的explorer.exe进程" exit } foreach ($process in $processes) { try { $proc = [System.Diagnostics.Process]::GetProcessById($process.ProcessId) # 打开进程令牌,需TOKEN_QUERY和TOKEN_DUPLICATE权限 $tokenHandle = [IntPtr]::Zero if (-not [TokenHelper]::OpenProcessToken($proc.Handle, [TokenHelper]::TOKEN_QUERY -bor [TokenHelper]::TOKEN_DUPLICATE, [ref]$tokenHandle)) { Write-Host "打开进程令牌失败,错误码: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" continue } # 复制令牌为Primary类型,用于创建WindowsIdentity $duplicateToken = [IntPtr]::Zero if (-not [TokenHelper]::DuplicateTokenEx($tokenHandle, [TokenHelper]::TOKEN_QUERY, [IntPtr]::Zero, [TokenHelper]::SecurityImpersonation, [TokenHelper]::TokenPrimary, [ref]$duplicateToken)) { Write-Host "复制令牌失败,错误码: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" [TokenHelper]::CloseHandle($tokenHandle) continue } # 通过复制后的令牌创建WindowsIdentity并获取Token值 $identity = New-Object System.Security.Principal.WindowsIdentity($duplicateToken) Write-Host "$targetUsername 的Token: $($identity.Token)" # 关闭句柄释放系统资源 [TokenHelper]::CloseHandle($tokenHandle) [TokenHelper]::CloseHandle($duplicateToken) } catch { Write-Host "处理进程 $($process.ProcessId) 时出错: $_" } }
关键注意点
- 管理员权限是硬性要求,否则所有令牌操作都会因权限不足失败。
- 手动调用API复制令牌,确保获取到的令牌具备合法的使用权限,避免原代码中的模拟令牌错误。
- 操作完成后必须关闭令牌句柄,防止系统资源泄漏。
内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

