CreateProcessAsUser函数:Windows进程创建核心技术

吉云

今天就来聊聊我捣鼓CreateProcessAsUser这个东西的经历。这玩意儿一开始真把我搞得有点头大,但弄明白也就那么回事儿。

起因是这样的,那会儿我手头在做一个系统服务类的程序。这种程序,一般都是在后台默默运行的,用的是系统账户,比如SYSTEM什么的。问题来,有时候需要在用户登录桌面后,由这个服务启动一个程序给用户看,比如说弹个提示窗口,或者运行一个需要用户交互的工具。

一开始我想得简单,直接用CreateProcess不就行?试一下,立马傻眼。服务跑的地方跟咱们能看到的桌面,它不是一个“频道”里的,尤其在比较新的Windows系统上,搞个什么Session 0隔离。你直接在服务里CreateProcess,那程序要么起不来,要么起来也看不见,因为它压根没在当前用户能交互的那个桌面上。

CreateProcessAsUser函数:Windows进程创建核心技术

这时候就得另寻出路。 查些资料,翻些文档,CreateProcessAsUser这个函数就冒出来。看名字大概能猜到,就是“以某个用户的身份创建进程”。这不正好对上我的需求嘛

实践过程中的折腾

知道用啥,下一步就是怎么用。这CreateProcessAsUser用起来比CreateProcess要麻烦不少。

  • 第一步,得找到目标用户。 就是当前登录到桌面的那个用户。服务本身可不知道现在是谁登录,得想办法获取到这个用户的“身份凭证”,也就是所谓的“令牌”(Token)。当时我用的方法大概是通过查活动会话(Active Session)来找到用户,然后用一些API(具体哪个记不太清,好像跟WTS开头的函数有关)去拿到这个用户的令牌。
  • 第二步,令牌还不能直接用。 直接拿到的令牌(主令牌)好像有些限制,不能直接用来创建进程。需要把它复制一份,搞个“副本令牌”(模拟令牌或者主令牌副本都行,看具体需求)。当时我就卡在这儿,复制令牌有好几个参数,试好几次才搞对,需要有足够的权限才能启动进程。
  • CreateProcessAsUser函数:Windows进程创建核心技术

  • 第三步,准备启动环境。CreateProcess类似,也得准备一堆启动参数,比如要运行的程序路径、命令行参数什么的。但CreateProcessAsUser有个特别的地方,你得明确告诉它,这个新进程要在哪个“窗口站”(Window Station)和“桌面”(Desktop)上运行。默认的服务环境跟用户的交互桌面环境不一样,这里得指定成用户当前正在用的那个,通常是"WinSta0\Default"。这一步也挺关键的, 要是没弄对,程序可能在后台启动,但用户界面就是出不来。
  • 一步,调用函数。 把准备好的副本令牌、程序路径、启动参数、环境信息一股脑儿塞给CreateProcessAsUser。如果前面都没错,运气好的话,“Duang”一下,程序就以目标用户的身份,在他/她的桌面上跑起来。

我记得最清楚的一次折腾, 是程序确实启动,任务管理器里也能看到进程,但桌面上死活不见窗口。查半天,抓耳挠腮的,才定位到是那个“窗口站”和“桌面”指定得不对。改之后,窗口立马就出来。那时候真是松一口气,感觉跟打通任督二脉似的。

还有一次是权限问题,复制令牌的时候没搞对,导致启动的程序权限不足,运行一会儿就自己崩。又是一顿排查,调整复制令牌时的权限参数才解决。

总结一下

CreateProcessAsUser函数:Windows进程创建核心技术

CreateProcessAsUser这东西确实是解决“服务程序想在用户桌面启动进程”这类问题的正规军。虽然过程比直接CreateProcess要绕一些,需要处理用户令牌、会话环境这些东西,但一旦你把流程理顺,实际用起来还是挺可靠的。

对我来说,搞定这个过程,也算是填补Windows底层机制认知上的一个坑。以后再遇到类似场景,心里就有底多。分享出来,希望能给可能遇到同样问题的朋友一点小小的参考。

免责声明:由于无法甄别是否为投稿用户创作以及文章的准确性,本站尊重并保护知识产权,根据《信息网络传播权保护条例》,如我们转载的作品侵犯了您的权利,请您通知我们,请将本侵权页面网址发送邮件到qingge@88.com,深感抱歉,我们会做删除处理。

目录[+]