主令牌和模拟令牌之间有什么区别

con*_*nio 14 windows winapi windows-security

某些Windows API返回主令牌,有些返回模拟令牌.某些API需要主令牌,而其他API则需要模拟令牌.

例如,LogonUser通常返回主令牌,除非LOGON32_LOGON_NETWORK用作登录类型(dwLogonType)时:

在大多数情况下,返回的句柄是您可以在调用CreateProcessAsUser函数时使用的主令牌.但是,如果指定LOGON32_LOGON_NETWORK标志,则LogonUser将返回您无法在CreateProcessAsUser中使用的模拟标记,除非您调用DuplicateTokenEx将其转换为主标记.

SetThreadToken需要一个模拟令牌,而ImpersonateLoggedOnUser这似乎做同样的事情需要一个.

CreateProcessAsUser并且CreateProcessWithTokenW两者都需要一个主令牌,并注意可以通过调用从模拟令牌中获取主令牌DuplicateTokenEx,但令牌类型什么意思

词汇表说明如下:

访问令牌

访问令牌包含登录会话的安全信息.系统在用户登录时创建访问令牌,并且代表用户执行的每个进程都具有令牌的副本.令牌标识用户,用户的组和用户的权限.系统使用令牌来控制对安全对象的访问,并控制用户在本地计算机上执行各种系统相关操作的能力.有两种访问令牌,主要和模拟.

主令牌

通常仅由Windows内核创建的访问令牌.可以将其分配给进程以表示该进程的默认安全信息.

冒充令牌

已创建的访问令牌,用于捕获客户端进程的安全信息,允许服务器在安全操作中"模拟"客户端进程.

但这并不完全有用.似乎有人想要使用像"内核"这样的大男孩字样,但这只会引发更多问题,例如除了被分配到进程之外还可以使用主要令牌以及除了内核之外的其他人可以创建访问权限令牌?

(他们的意思是微软的意思,内核只是内核模式运行的一部分,还有执行等等,或者他们是否意味着用户模式代码也可以创建令牌?无论如何,即使用户 - 模式代码可以创建令牌,它必须通过系统调用来完成,就像任何对象管理器对象一样,所以无论如何,令牌实际上都是以内核模式创建的.)

无论如何,这并没有回答基本问题:令牌类型之间有什么区别?不是它们可能被用于什么或通常如何创建它们.

con*_*nio 16

一位朋友推荐我使用Keith Brown 编程的Windows安全性,他完全回答了这个问题.

主要令牌可以而且应该被称为进程令牌和模拟令牌可以而且应该被称为线程令牌.主令牌只能附加到进程并且模拟令牌只能附加到线程.就这样.它们确实可以使用自由转换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页).
  • 您可以使用未记录的NTDLL函数从用户模式创建令牌,该函数ZwCreateToken需要非常不寻常的权限(特别是唯一的SE_CREATE_TOKEN_NAME).你可能不应该......