【问题标题】:Difference between access token taken from process than from user/pass从进程获取的访问令牌与从用户/通行证获取的访问令牌之间的差异
【发布时间】:2016-11-25 13:55:07
【问题描述】:

我试图了解 2 个可能相同的访问令牌之间的区别。

  1. 获取访问令牌的一种方法是使用 OpenProcessToken()。该函数返回一个访问令牌,可用于创建其他进程或模拟。
  2. 另一种方法(还有更多,但让我们关注这两个)是使用 LogonUser() 函数,该函数还返回可用于创建其他进程或模拟的访问令牌。

区别是(1)中的访问令牌只要进程存在就有效,而(2)中的访问令牌不附加到任何进程。

那么,(1) 我从 OpenProcessToken() 中究竟得到了什么?不是访问令牌? (2) 我可以将 OpenProcessToken() 中的访问令牌“更改”为与进程“分离”吗? (即在进程终止后仍然有效)

【问题讨论】:

  • (1) - 不正确。令牌没有“附加”到处理。进程具有对令牌的引用,但令牌(作为任何内核对象)只有在引用计数达到 0 时才会被销毁。因此,在您打开进程令牌后 - 您不关闭它的最小值将变为有效
  • 请准确说明您观察到的使您认为令牌在进程退出后变得无效的情况。最好发布演示代码。

标签: winapi visual-c++ window


【解决方案1】:

只要进程存在,来自 (1) 的访问令牌就有效

这不是真的。令牌没有“附加”到任何进程。当然这没有记录,但是您可以解析 pdb 符号并观察到 ​​struct _TOKEN 没有任何指向 _EPROCESS 对象的链接。

与任何内核对象一样,令牌具有引用计数,当引用计数达到零时它将被销毁 - 但在那之前,它仍然有效。每个_EPROCESS 都有一个对令牌的引用,但反之则不然。打开进程令牌后,只要您保持打开状态,它就会一直有效,即使您从中获取它的进程终止。

这很容易测试:从某个进程(具有必要的权限)打开一个令牌,然后关闭/终止该进程。您会发现您仍然可以使用带有CreateProcessAsUserW 的令牌来启动新进程。

所以不,这两个令牌之间没有区别;在这两种情况下,您都有内核对象的句柄。


这里是演示代码,显示来自OpenProcessToken 的令牌即使在进程退出后仍然有效。我们创建一个记事本实例,打开它的令牌,等待进程存在,然后尝试(成功!)使用令牌来启动一个新的记事本实例。

void demo()
{
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    // create new process in suspended state
    // path to notepad hardcoded for for simplicity
    if (CreateProcessW(L"c:\\windows\\notepad.exe", 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0,&si, &pi))
    {
        // open process token with TOKEN_QUERY only
        HANDLE hToken;
        NTSTATUS status = NtOpenProcessToken(pi.hProcess, TOKEN_QUERY, &hToken);

        // resume process
        ResumeThread(pi.hThread);
        NtClose(pi.hThread);

        // close notepad
        WaitForInputIdle(pi.hProcess, INFINITE);
        PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0);

        // wait notepad exit
        ZwWaitForSingleObject(pi.hProcess, FALSE, 0);

        NtClose(pi.hProcess);

        // try use "invalid" token from died process
        if (0 <= status)
        {
            // we need TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY access for CreateProcessAsUserW
            // we can at begin (in NtOpenProcessToken open it with the necessary access, this is only for demo

            if (0 <= ZwDuplicateObject(NtCurrentProcess(),
                hToken, NtCurrentProcess(), &hToken, 
                TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY, 0, DUPLICATE_CLOSE_SOURCE))
            {
                if (CreateProcessAsUserW(hToken, L"c:\\windows\\notepad.exe", 0, 0, 0, 0, 0, 0, 0, &si, &pi))
                {
                    NtClose(pi.hThread);
                    NtClose(pi.hProcess);
                }
                else
                {
                    GetLastError();
                }

                NtClose(hToken);
            }
        }
    }
}

【讨论】:

  • 如果我只使用“TOKEN_QUERY”,一旦进程被销毁,它就会失效。是不是没有 TOKEN_DUPLICATE 引用计数不会增加?
  • @TCS - “它变得无效”是什么意思?
  • @TCS - “引用计数没有增加” - 当然没有。甚至奇怪听这个
  • 如果您尝试“创建流程”而不先复制它会怎样。只需使用令牌。为什么要先“复制”它?
  • ZwDuplicateObject 不会复制令牌,它只是打开它的新句柄。如果您更改代码以使用适当的权限打开原始句柄,您可能会忽略它。
猜你喜欢
  • 2016-07-18
  • 2018-06-06
  • 2018-02-17
  • 1970-01-01
  • 2012-04-28
  • 2014-12-09
  • 2017-03-22
  • 2014-07-09
相关资源
最近更新 更多