Search code examples
c++windowswinapiwin32gui

Running Process in system context


Is it possible to launch process in system context from a parent process thats running under administrator account with elevation(say a command prompt). The problem is similar to what psexec does but more of how it actually implements this.

I was thinking opening the crss.exe/winlogon.exe process duplicating the token and launching a new process using that process token. But I fail to even open the process handle (Getlasterror return 5). Can someone let me know if this is the right approach or the process should be launched differently ?

HANDLE hWinLogonProcess;
for(const auto& ps : running_processes)
{
    if(ps.id == GetCurrentProcessId() ||
        0 != ps.short_name.CompareNoCase(L"winlogon.exe"))
    {
        continue;
    }

    DWORD dwWinLogonSessionId(0);
    if(FALSE == ProcessIdToSessionId(GetCurrentProcessId(), &dwWinLogonSessionId))
    {
        std::wcerr<<"Could not get Winlogon process session id"<<std::endl;
        continue;
    }

    if(dwWinLogonSessionId != dwCurSessionId)
    {
        continue; 
    }

    hWinLogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ps.id);
    if(FALSE == hWinLogonProcess)
    {
        std::wcerr<<"Failed to get winlogon process handle"<<std::endl;
        return;
    }
    else
    {
        std::wcout<<"Able to open process "<<ps.short_name.GetString()<<" handle"<<std::endl;
        break;
    }
}

I am sure its possible as there is a working tool (psexec) but I couldnt find any reference online to do this.

Also this is similar to question, but posting separately as there was details on how it had to be achieved.


Solution

  • Yes, this is possible (without any service help).

    But I fail to even open the process handle

    Does your process have the SE_DEBUG_PRIVILEGE privilege enabled?

    With this privilege, you can open a system process with all access if it is not protected (smss.exe, csrss.exe, services.exe), and use that handle in CreateProcessAsUser(), or with UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS) if you also have SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_TCB_PRIVILEGE privileges enabled (for setting the token's SessionId to 0), which you can get in 2 ways:

    • open a thread from an unprotected system process and impersonate it, then open your own thread token and adjust privileges on it.

    • open a token from any system process (this works even for protected processes), duplicate the token, adjust privileges on it, and then impersonate with this token.

    To "launch a process in the system context", if you want to run the process:

    • with the LocalSystem token.

    • in the System terminal session (0)

    Both, as I say, are possible. And all you need is SE_DEBUG_PRIVILEGE.

    1. more simply - open some system process with PROCESS_CREATE_PROCESS access right. Use this handle with UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS). As a result, your started process inherits a token from the system process. This will be not work on XP, but there it is possible to hook NtCreateProcess/Ex() to replace HANDLE ParentProcess with your opened handle.

    2. Another way is to use CreateProcessAsUser(). Before creating the process, you will be need SE_ASSIGNPRIMARYTOKEN_PRIVILEGE and SE_TCB_PRIVILEGE privileges to set the token's TokenSessionId (if you want to run in session 0).