access token 访问令牌的概念
Windows操作系统安全性的一个概念。一个访问令牌包含了此登陆会话的安全信息。当用
用户权利指派
户登陆时,系统创建一个访问令牌
,然后以该用户身份运行的的所以进程都拥有该令牌的一个拷贝。该令牌唯一表示该用户、用户的组和用户的特权。系统使用令牌控制用户可以访问哪些安全对象,并控制用户执行相关系统操作的能力。有两种令牌:主令牌和模拟的令牌。主令牌是与进程相关的;模拟的令牌是与模拟令牌的线程相关的。 进程拥有某种令牌就表示它拥有某种特权。什么是特权呢?特权是指用户进程进行各种系统操作的权利。如:关机,加载设备驱动程序,改变系统时间也是一种特权。可以对用户或用户所在的组授予特权。见图。
WinNT定义的特权
在WinNT.h头文件中定义了这些特权的名称: #define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") #define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") #define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") #define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") #define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") #define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") #define SE_TCB_NAME TEXT("SeTcbPrivilege") #define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") #define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") #define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") #define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") #define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") #define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") #define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") #define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") #define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") #define SE_BACKUP_NAME TEXT("SeBackupPrivilege") #define SE_RESTORE_NAME TEXT("SeRestorePrivilege") #define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") #define SE_DEBUG_NAME TEXT("SeDebugPrivilege") #define SE_AUDIT_NAME TEXT("SeAuditPrivilege") #define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") #define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") #define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") #define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") #define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") #define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") #define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") #define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") #define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") #define SE_TRUSTED_CREDMAN_ACCESS_NAME TEXT("SeTrustedCredManAccessPrivilege") #define SE_RELABEL_NAME TEXT("SeRelabelPrivilege") #define SE_INC_WORKING_SET_NAME TEXT("SeIncreaseWorkingSetPrivilege") #define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege") #define SE_CREATE_SYMBOLIC_LINK_NAME TEXT("SeCreateSymbolicLinkPrivilege")
如何取得一个进程的访问令牌 通过API函数OpenProcessToken 取得进程令牌。其定义如下: BOOL WINAPI
OpenProcessToken( __in HANDLE
ProcessHandle, //进程句柄。通过GetCurrentProcess函数取得当前进程句柄 __in DWORD
DesiredAccess, //要对令牌进行何种操作。如TOKEN_ADJUST_PRIVILEGES用于调整权限 __out PHANDLE
TokenHandle //进程令牌句柄 ); 如下代码取得进程的令牌,并告诉系统我们想调整令牌的权限 HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { ...... }
对令牌可以进行的操作
Value |
Meaning |
TOKEN_ADJUST_DEFAULT |
改变令牌所有者、主组或访问控制列表DACL |
TOKEN_ADJUST_GROUPS |
改变令牌的组属性 |
TOKEN_ADJUST_PRIVILEGES |
enable or disable 令牌的特权 |
TOKEN_ADJUST_SESSIONID |
调整令牌的Session ID。进程需要 SE_TCB_NAME 特权. |
TOKEN_ASSIGN_PRIMARY |
为进程分配主令牌。需要 SE_ASSIGNPRIMARYTOKEN_NAME 特权 |
TOKEN_DUPLICATE |
复制令牌 |
TOKEN_EXECUTE |
合并 STANDARD_RIGHTS_EXECUTE 和 TOKEN_IMPERSONATE. |
TOKEN_IMPERSONATE |
附加一个模拟令牌到进程 |
TOKEN_QUERY |
查询令牌 |
TOKEN_QUERY_SOURCE |
查询令牌源 |
TOKEN_READ |
合并 STANDARD_RIGHTS_READ 和TOKEN_QUERY. |
TOKEN_WRITE |
合并 STANDARD_RIGHTS_WRITE, TOKEN_ADJUST_PRIVILEGES, TOKEN_ADJUST_GROUPS, 和 TOKEN_ADJUST_DEFAULT. |
TOKEN_ALL_ACCESS |
合并所以可能的操作 |
与访问令牌关联的特权 TOKEN_PRIVILEGES令牌特权结构体,该结构体定义了访问令牌所拥有的一系列特权。其原型定义如下: typedef struct
_TOKEN_PRIVILEGES { DWORD
PrivilegeCount; //特权数量(数组的长度) LUID_AND_ATTRIBUTES
Privileges[ANYSIZE_ARRAY]; //特权数组 }
TOKEN_PRIVILEGES, *
PTOKEN_PRIVILEGES; 其中,Privileges数组类型为
LUID_AND_ATTRIBUTES结构体,其原型定义如下: typedef struct _LUID_AND_ATTRIBUTES { LUID Luid; //局部唯一标识符,代表某种特权的Value DWORD Attributes; //Luid的属性,代表特权的属性(Enabled or Disabled) }
LUID_AND_ATTRIBUTES, *
PLUID_AND_ATTRIBUTES; 其特权属性Attributes可以是如下常量:
值 |
含义 |
SE_PRIVILEGE_ENABLED |
使特权有效 |
SE_PRIVILEGE_ENABLED_BY_DEFAULT |
使特权默认有效 |
SE_PRIVILEGE_REMOVED |
移除该特权 |
SE_PRIVILEGE_USED_FOR_ACCESS |
取得对象或服务的访问权 |
如何调整访问令牌的特权
取得特权的LUID值
首先通过LookupPrivilegeValue函数取得某种特权的LUID,通过特权的名称查找特权的LUID。 BOOL WINAPI
LookupPrivilegeValue( __in_opt LPCTSTR lpSystemName, //特权所在的系统名称,NULL表示本地系统 __in LPCTSTR lpName, //特权名称,在WInNT.h 中定义的特权名称 __out PLUID lpLuid //取得的特权的LUID ); 如下代码取得SE_DEBUG_NAME特权的LUID,并将特权属性设为SE_PRIVILEGE_ENABLED TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
调整令牌特权
AdjustTokenPrivileges函数可以调整令牌的特权。函数定义如下: BOOL WINAPI AdjustTokenPrivileges( __in HANDLE TokenHandle, //令牌句柄 __in BOOL DisableAllPrivileges, //是否禁用所有特权,如为TRUE,则忽略NewState参数 __in_opt PTOKEN_PRIVILEGES NewState,//调整为NewState结构定义的特权 __in DWORD BufferLength, //
PreviousState 参数的字节大小 __out_opt PTOKEN_PRIVILEGES PreviousState, 可选,调整之前的TOKEN_PRIVILEGES结构体指针 __out_opt PDWORD ReturnLength //可选,返回的结构体的长度 ); //调用 AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);