【问题标题】:Running Process in system context在系统上下文中运行进程
【发布时间】:2016-08-30 22:31:33
【问题描述】:

是否可以从在管理员帐户下运行的父进程在系统上下文中启动进程并提升权限(比如命令提示符)。这个问题与 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,但单独发布,因为有关于如何实现它的详细信息。

【问题讨论】:

  • how psexec works。简而言之,psexec 以管理员用户身份登录并安装并运行一个临时服务以获得系统访问权限,然后该服务运行该命令,然后 psexec 停止并卸载该服务。 psexec 使用管道在自己和服务之间交换输入/输出,服务使用管道与运行命令交换输入/输出。
  • 感谢@RemyLebeau,我看到 psexec 创建了一个服务来实现这一点。但是我有一个 dll,不想为此引入一个新的 exe。是否有可能以编程方式实现这一目标。由于我当前的进程已经以管理员权限运行。
  • 只有服务才能获得系统权限,只有管理员才能安装服务。您不能将 DLL 作为服务直接运行(除非它是驱动程序),但您也不需要编写单独的 EXE。您可以 1) 将 DLL 设计为可从 Rundll32 调用,然后将该 EXE 用作服务,或者 2) 将您的主 EXE 安装为具有命令行参数的服务,然后添加相关的服务 API 调用当 EXE 使用该参数运行时,您的 WinMain() 函数,并让您的“服务”根据需要使用 DLL。
  • @RemyLebeau - “只有服务才能获得系统特权” - 这不是真的 - 真的是任何拥有 SE_DEBUG_PRIVILEGE 的人。如果有这个,我们可以使用 PROCESS_QUERY_LIMITED_INFORMATION 打开任何进程(甚至受保护),然后打开它的令牌,复制它并分配给我们的线程。不需要任何服务
  • @user3279954 - 是的,这是可能的,我什至有专门的工具

标签: c++ windows winapi win32gui


【解决方案1】:

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

但是我连进程句柄都打不开

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

使用此权限,您可以打开不受保护的系统进程(smss.exe、csrss.exe、services.exe),并在CreateProcessAsUser() 或@987654323 中使用该句柄@如果您还启用了SE_ASSIGNPRIMARYTOKEN_PRIVILEGESE_TCB_PRIVILEGE 权限(用于将令牌的SessionId 设置为0),您可以通过两种方式获得:

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

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

要“在系统上下文中启动进程”,如果要运行该进程:

  • 使用 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,该解决方案有效!我可以使用系统帐户创建一个子进程。我复制了进程令牌,启用了 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE , SE_TCB_PRIVILEGE,并且在模拟之后,启动该进程将子进程创建为系统进程
【解决方案2】:

感谢 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
}

【讨论】:

    猜你喜欢
    • 2011-05-13
    • 2014-06-25
    • 1970-01-01
    • 1970-01-01
    • 2014-06-10
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    相关资源
    最近更新 更多