运行 系统上下文中的进程

Running Process in system context

是否可以从 运行 具有提升权限的管理员帐户下的父进程在系统上下文中启动进程(比如命令提示符)。这个问题类似于 psexec 所做的,但更多的是它如何实际实现这个。

我正在考虑打开 crss.exe/winlogon.exe 进程复制令牌并使用该进程令牌启动新进程。但我什至无法打开进程句柄 (Getlasterror return 5)。有人可以告诉我这是正确的方法还是应该以不同的方式启动流程?

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;
    }
}

我确信这是可行的,因为有一个可用的工具 (psexec),但我无法在网上找到任何参考来执行此操作。

这也类似于 question,但单独发布,因为有关于如何实现它的详细信息。

是的,这是可能的(无需任何服务帮助)。

But I fail to even open the process handle

您的进程是否启用了 SE_DEBUG_PRIVILEGE 权限?

有了这个权限,你可以打开一个系统进程,如果它没有被保护(smss.exe,csrss.exe,services.exe),你可以使用所有访问权限,并在CreateProcessAsUser(),或者使用 UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS) 如果您还启用了 SE_ASSIGNPRIMARYTOKEN_PRIVILEGESE_TCB_PRIVILEGE 权限(用于将令牌的 SessionId 设置为 0),您可以在 2方式:

  • 从未受保护的系统进程中打开一个线程并模拟它,然后打开您自己的线程令牌并调整其权限。

  • 从任何系统进程打开一个令牌(这甚至适用于受保护的进程),复制该令牌,调整其权限,然后使用该令牌进行模拟。

到"launch a process in the system context",如果要运行过程:

  • 使用 LocalSystem 令牌。

  • 在系统终端会话中(0)

正如我所说,两者都是可能的。你只需要 SE_DEBUG_PRIVILEGE.

  1. 更简单 - 打开一些具有 PROCESS_CREATE_PROCESS 访问权限的系统进程。将此句柄与 UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS) 一起使用。结果,您启动的进程从系统进程继承了一个令牌。这在 XP 上不起作用,但是可以挂钩 NtCreateProcess/Ex() 以用您打开的句柄替换 HANDLE ParentProcess

  2. 另一种方法是使用CreateProcessAsUser()。在创建流程之前,您将需要 SE_ASSIGNPRIMARYTOKEN_PRIVILEGESE_TCB_PRIVILEGE 权限来设置令牌的 TokenSessionId(如果您想在会话 0 中 运行)。

感谢 RbMm 的回答,我找到了完成这项任务的方法。

对于任何没有成功的人,我在下面留下一些可能有帮助的东西:

//First we need to add debug privilege to this process
HANDLE hToken;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
    &hToken))
{
    std::cout << "OpenProcessToken failed: " << GetLastError();
    return 0;
}

TOKEN_PRIVILEGES tk;
tk.PrivilegeCount = 1;
tk.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tk.Privileges[0].Luid))
{
    std::cout << "LookupPrivilegeValue failed: " << GetLastError();
    return 0;
}

AdjustTokenPrivileges(hToken, FALSE, &tk, 0, NULL, 0);
if((DWORD res = GetLastError()) != ERROR_SUCCESS)
{
    std::cout << "AdjustTokenPrivileges failed: " << res;
}

CloseHandle(hToken);

//Now we need a handle to a process that already runs as SYSTEM.
//You can choose any process that is not protected (if OpenProcess fails try with other process)

//pid of chosen process (you can get this by opening task manager and go to
//Details tab or by enumerating all processes and extract that one you need)
DWORD pid;
HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
if (!hProcess)
{
    std::cout << "OpenProcess with pid " << pid << "failed: " << GetLastError();
    return 0
}

//We need to initialize a list that contains PROC_THREAD_ATTRIBUTE_PARENT_PROCESS 
//to specify that parent process of the process we are going to start is the 
//process we opened earlier (this will make the child process inherit the system context).
//This list will be specified in a STARTUPINFOEX object that CreateProcess will get
STARTUPINFOEX siex = { sizeof(STARTUPINFOEX) };
siex.StartupInfo.cb = sizeof(STARTUPINFOEXW);

//We need to initialize our list. To do this we call InitializeProcThreadAttributeList 
//with a NULL list to get how big our list needs to be to store all attributes 
//we want to specify, then we allocate our list with the size we got from first call 
//and we call again the function to initialize the list.
SIZE_T cbAttributeListSize = 0;
if(!InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize))
{
    std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
    return 0
}

siex.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize));
if(!InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &cbAttributeListSize))
{
    std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
    return 0
}

if(!UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), NULL, NULL))
{
    std::cout << "UpdateProcThreadAttribute failed: " << GetLastError();
    return 0
}

//path to program we want to run in system context
LPWSTR szCmdline = _wcsdup(TEXT("C:\Windows\System32\notepad.exe"));
PROCESS_INFORMATION pi = { 0 };

if(!CreateProcess(NULL, szCmdline, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOW>(&siex), &pi))
{
    std::cout << "CreateProcess failed: " << GetLastError();
    return 0
}