18

一些 Windows API 返回一个主令牌,一些返回一个模拟令牌。一些 API 需要主令牌,而其他 API 需要模拟令牌。

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

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

SetThreadToken需要一个模拟令牌,而ImpersonateLoggedOnUser这似乎做几乎相同的事情需要任何一个。

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

词汇表是这样说的:

访问令牌

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

主令牌

通常仅由 Windows 内核创建的访问令牌。它可以分配给一个进程来表示该进程的默认安全信息。

模拟令牌

为捕获客户端进程的安全信息而创建的访问令牌,允许服务器在安全操作中“模拟”客户端进程。

但这并不完全有用。似乎有人想使用像“内核”这样的大字眼,但这只会引发更多问题,例如主令牌还可以用于什么(除了分配给进程)以及除了内核之外还有谁可以创建访问权限代币?

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

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

4

1 回答 1

21

一位朋友向我推荐了 Keith Brown 的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(and LsaLogonUser) 可能会返回网络登录的模拟令牌,因为假设谁通常执行网络登录(例如,从第 83 页开始)。
  • 您可以使用未记录的 NTDLL 函数从用户模式创建令牌,该函数ZwCreateToken需要非常不寻常的权限(特别是 unique SE_CREATE_TOKEN_NAME)。你可能不应该...
于 2016-01-27T02:00:11.980 回答