Windows锁屏下用户态控制键鼠的可行方案咨询(SendInput调用失败返回错误码5)
我之前开发远程控制工具时也踩过一模一样的坑,锁屏后SendInput返回错误5(拒绝访问),哪怕开了管理员权限也不好使,后来折腾出几个不用写KMDF驱动的用户态方案,分享给你:
切换到Winlogon桌面调用
SendInput
Windows锁屏后,系统的活跃输入桌面会切换到WinSta0\Winlogon(普通用户程序默认运行在WinSta0\Default桌面)。你可以按这个思路操作:- 用
OpenDesktop函数打开Winlogon桌面,要指定足够的权限,比如DESKTOP_SWITCHDESKTOP、DESKTOP_WRITEOBJECTS这些; - 调用
SetThreadDesktop把当前线程的关联桌面切换到Winlogon桌面; - 切换成功后再调用
SendInput发送键鼠事件; - 操作完成后记得切回原桌面,避免影响程序其他逻辑。
注意:这个方法需要程序主动启用SE_TCB_NAME特权,而且在Windows 10/11的部分版本中,桌面访问的权限校验更严格,可能需要结合SYSTEM权限运行——你可以用CreateProcessAsUser拿着SYSTEM令牌单独开一个线程处理输入发送。
- 用
使用Windows Input Injection API(Windows 8及以上支持)
从Windows 8开始,微软提供了InjectInput函数,这个API比SendInput更偏向系统级,支持跨会话注入输入。大致步骤是:- 用
WTSEnumerateSessions枚举会话,拿到目标用户的会话ID; - 给当前进程启用
SE_INJECTION_PRIVILEGE特权; - 调用
InjectInput时指定目标会话ID,直接向该会话注入键鼠事件。
这个API的权限逻辑更清晰,只要正确启用特权,锁屏状态下就能稳定工作,不少新的商业远程工具都在用这个方案。
- 用
依托远程桌面服务(RDS)的虚拟通道机制
这是很多老牌商业远程软件的核心玩法:把你的程序注册成RDS的虚拟通道客户端,RDS是系统原生的远程交互框架,锁屏时系统会保留RDS通道的权限豁免,允许通过通道向目标会话转发输入事件。你可以借助WTSVirtualChannelOpen、WTSVirtualChannelWrite等函数和系统RDS服务交互,绕开普通用户程序的权限限制。这种方法兼容性最好,从Windows 7到11都能稳定跑,但需要你先搞懂RDS的通道注册机制。
至于为什么管理员权限没用:管理员权限只是用户组层面的权限提升,而锁屏后的输入控制需要的是系统级特权(比如SE_TCB_NAME、SE_INJECTION_PRIVILEGE),这些特权默认不会给管理员账号启用,必须在程序运行时主动调用AdjustTokenPrivileges来开启。
内容来源于stack exchange

