只要进程存在,来自 (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);
}
}
}
}