Windows - 使用 CreateProcessWithTokenW 在会话 0 中创建进程

Windows - Create a process in session 0 using CreateProcessWithTokenW

目的是从非 0 控制台会话中的进程在会话 0 中创建新进程。 我知道一些方法可以达到目的,但我想知道为什么下面描述的方法没有,尽管 msdn 说它应该有效。

unsigned FindProcessInSession(unsigned SessionId,const wchar_t*ProcessName)
{
    PWTS_PROCESS_INFOW pinfo;DWORD Count,Result=0;
    if(WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE,0,1,&pinfo,&Count)){
        for(unsigned i=0;i<Count;++i)if(pinfo[i].SessionId==SessionId&&_wcsicmp(pinfo[i].pProcessName,ProcessName)==0){
            Result=pinfo[i].ProcessId;break;
        }
        WTSFreeMemory(pinfo);
    }
    return Result;
}


int main()
{
    HANDLE hProcess=OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,0,FindProcessInSession(0,L"smss.exe")),ProcessToken,NewToken;
    if(hProcess&&OpenProcessToken(hProcess,TOKEN_DUPLICATE,&ProcessToken)&&DuplicateTokenEx(ProcessToken,MAXIMUM_ALLOWED,0,SecurityImpersonation,TokenImpersonation,&NewToken)){
        static STARTUPINFOW si={sizeof(STARTUPINFOW)};PROCESS_INFORMATION pi;DWORD SessionId,l;
        printf("GetTokenInformation %d\n",GetTokenInformation(NewToken,TokenSessionId,&SessionId,sizeof SessionId,&l));
        printf("SessionId %d\n",SessionId);
        printf("CreateProcessWithTokenW %d\n",CreateProcessWithTokenW(NewToken,0,L"c:\windows\system32\cmd.exe",0,0,0,0,&si,&pi));
    }
}

在我的电脑上测试期间,GetTokenInformation 成功输出 SessionId=0 并且 CreateProcessWithTokenW 在 SYSTEM 用户名中创建了一个新进程,具有来自 smss.exe 的所有权限。但是新进程仍然 运行 在调用进程所在的任何会话中。 msdn on CreateProcessWithTokenW 注释

终端服务:进程在令牌中指定的会话中 运行。默认情况下,这是调用 LogonUser 的同一会话。要更改会话,请使用 SetTokenInformation 函数。

A​​ppa运行tly 辅助登录服务CreateProcessWithTokenW 依赖不不遵循文档

CreateProcessWithTokenW 获取调用者的 SessionId 并在令牌中设置此 SessionId (作为副作用 - 令牌在 CreateProcessWithTokenW。你可以在 CreateProcessWithTokenW 之后再次调用 GetTokenInformation 并查看现在这里已经不是 0。所以 - CreateProcessWithTokenW 不能用于另一个会话中的 运行 进程. 需要使用 CreateProcessAsUserW。更多研究 here