某些Windows API返回主令牌,有些返回模拟令牌。某些API需要主令牌,而其他API则需要模拟令牌。
例如,LogonUser
通常会返回主令牌,除非使用LOGON32_LOGON_NETWORK
作为登录类型(dwLogonType
):
在大多数情况下,返回的句柄是您可以在调用CreateProcessAsUser函数时使用的主令牌。但是,如果指定LOGON32_LOGON_NETWORK标志,则LogonUser将返回您无法在CreateProcessAsUser中使用的模拟标记,除非您调用DuplicateTokenEx将其转换为主标记。
SetThreadToken
需要一个假冒令牌而ImpersonateLoggedOnUser
这似乎做同样的事情需要一个。
CreateProcessAsUser
和CreateProcessWithTokenW
都需要主令牌,并注意可以通过调用DuplicateTokenEx
从模拟令牌中获取主令牌,但令牌类型是什么意思
词汇表说明如下:
访问令牌包含登录会话的安全信息。系统在用户登录时创建访问令牌,并且代表用户执行的每个进程都具有令牌的副本。令牌标识用户,用户的组和用户的权限。系统使用令牌来控制对安全对象的访问,并控制用户在本地计算机上执行各种系统相关操作的能力。有两种访问令牌,主要和模拟。
通常仅由Windows内核创建的访问令牌。可以将其分配给流程以表示该流程的默认安全信息。
为了捕获客户端进程的安全信息而创建的访问令牌,允许服务器在安全操作中“模拟”客户端进程。
但这并不完全有用。似乎有人想要使用像“内核”这样的大男孩话,但这只会引发更多问题,例如除了被分配到进程之外还可以使用主要令牌以及除了内核之外还有谁可以创建访问权限令牌?
(他们是否意味着微软意味着内核只是内核模式运行的一部分,而且还有Executive等等,或者他们是否意味着用户模式代码也可以创建令牌?无论如何,即使用户模式代码可以创建令牌,它必须通过系统调用来完成,就像任何对象管理器对象一样,因此令牌实际上将以内核模式创建。)
无论如何,这并没有回答基本问题:令牌类型之间有什么区别? 不 可能的用途或通常创建的方式。
答案 0 :(得分:16)
一位朋友将我推荐给基斯·布朗的Programming Windows Security,他完全回答了这个问题。
主要令牌可以而且应该被称为进程令牌和模拟令牌可以而且应该被称为线程令牌。主令牌只能附加到进程并且模拟令牌只能附加到线程。这就是全部。它们确实可以使用DuplicateTokenEx
自由转换(假设您拥有对要转换的句柄的必要访问权限,显然)。
从书中的第115页开始:
BOOL DuplicateTokenEx( HANDLE ExistingToken, // in DWORD DesiredAccess, // in LPSECURITY_ATTRIBUTES Attributes, // in, optional SECURITY_IMPERSONATION_LEVEL ImpLevel, // in TOKEN_TYPE Type, // in PHANDLE NewToken); // out
...
Type
参数是历史工件。如果您查看TOKEN_TYPE
枚举的定义,您会发现令牌已被分类为两类:假冒与主要令牌。不要挂在这个命名法上;意思实际上比听起来简单得多。模拟令牌只能附加到线程,主令牌只能附加到进程。这就意味着什么。之前通过OpenProcessToken获得的进程令牌因此是主要令牌。在Windows NT(3.x)的早期版本中,对令牌的处理方式有更严格的限制,具体取决于您最初获取令牌的位置,因此引入了令牌类型以跟踪令牌令牌的预期用途。由于本文假设您使用的是Windows NT 4.0或更高版本,因此只需将模拟令牌视为"线程令牌",将主令牌视为"进程令牌",并在必要时使用
DuplicateTokenEx
在两者之间进行转换。 Windows NT 4.0通过引入DuplicateTokenEx
来破坏两者之间的界限;此函数的Windows NT 3.x版本DuplicateToken
被硬编码为仅生成模拟令牌。事实上,现在您应该能够看到导致第一次调用SetThreadToken
失败的愚蠢错误:代码试图将主令牌(从进程获得的令牌)附加到线程(这需要冒充令牌)。这是禁忌。要解决逻辑问题和愚蠢的历史问题,请修改以下代码:
其他不严格回答问题的东西,但在问题中提到:
ImpersonateLoggedOnUser
更加努力,将主要令牌转换为假冒令牌,而SetThreadToken
则不会感到烦恼。为什么?谁知道?可能出于同样的原因,某些API在呼叫期间启用了特权,而其他API则要求呼叫者自己启用特权。LogonUser
(和LsaLogonUser
)可能会返回用于网络登录的模拟令牌,因为假设谁经常执行网络登录(例如,第83页)。ZwCreateToken
从用户模式创建令牌,该函数需要非常不寻常的权限(特别是唯一的SE_CREATE_TOKEN_NAME
)。你可能不应该......