windows源码分析14权限管理篇.docx
- 文档编号:17890862
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:89
- 大小:42.65KB
windows源码分析14权限管理篇.docx
《windows源码分析14权限管理篇.docx》由会员分享,可在线阅读,更多相关《windows源码分析14权限管理篇.docx(89页珍藏版)》请在冰点文库上搜索。
windows源码分析14权限管理篇
windows源码分析(14)-权限管理篇
Windows系统是支持多用户的。
每个文件可以设置一个访问控制表(即ACL),在ACL中规定每个用户、每个组对该文件的访问权限。
不过,只有Ntfs文件系统中的文件才支持ACL。
(Ntfs文件系统中,每个文件的ACL是作为文件的一个附加属性保存在文件中的)。
不仅ntfs文件支持ACL机制,每个内核对象也支持ACL,不过内核对象的ACL保存在对象头部的安全属性字段中,只存在于内存,对象一销毁,ACL就跟着销毁。
因此,内核对象的ACL是临时的,文件的ACL则是永久保存在磁盘上的。
文件的ACL由文件的创建者设置后保存在文件中,以后只有创建者和管理员才可以修改ACL,内核对象的ACL由对象的创建者在创建时指定。
Windows系统中为每个用户、组、机器指定了一个ID,叫SID。
每个用户登录到系统后,每当创建一个进程时,就会为进程创建一个令牌(进程的令牌叫主令牌),该令牌包含了用户、组、特权信息。
由于子进程在创建时会继承父进程的令牌,所以一个用户创建的所有进程的令牌都是一样的,包含着相同的用户、组、特权等其他信息,只是令牌ID不同而已。
换个角度看,令牌实际上相当于用户身份,进程要访问对象时,就出示它的令牌让系统检查,向系统表明自己是谁,在哪几个组中。
这样,当有了令牌和ACL后,当一个进程(准确说是线程)要访问一个对象时,系统就会检查该进程的令牌,申请的访问权限,然后与ACL比较,看看是否满足权限,不满足的话就拒绝访问。
下面我们看看相关的数据结构
typedefstruct_SID{//用户ID、组ID、机器ID
UCHARRevision;//版本号
UCHARSubAuthorityCount;//RID数组元素个数,即ID级数,最大支持8级
SID_IDENTIFIER_AUTHORITYIdentifierAuthority;//该ID的签发机关,6B长
ULONGSubAuthority[ANYSIZE_ARRAY];//RID数组,即N级ID
}SID,*PISID;
一个ID就像一个文件路径一样,由签发机关+N级ID组成。
Windows中有几种预定义的签发机关
#defineSECURITY_NULL_SID_AUTHORITY{0,0,0,0,0,0}#defineSECURITY_WORLD_SID_AUTHORITY{0,0,0,0,0,1}//世界签发机关#defineSECURITY_LOCAL_SID_AUTHORITY{0,0,0,0,0,2}//本机签发机关#defineSECURITY_CREATOR_SID_AUTHORITY{0,0,0,0,0,3}
#defineSECURITY_NON_UNIQUE_AUTHORITY{0,0,0,0,0,4}#defineSECURITY_NT_AUTHORITY{0,0,0,0,0,5}//NT域签发机关#defineSECURITY_RESOURCE_MANAGER_AUTHORITY{0,0,0,0,0,9}
typedefstruct_TOKEN
{
TOKEN_SOURCETokenSource;
LUIDTokenId;令牌ID
LUIDAuthenticationId;
LUIDParentTokenId;
LARGE_INTEGERExpirationTime;过期时间
struct_ERESOURCE*TokenLock;
SEP_AUDIT_POLICYAuditPolicy;
LUIDModifiedId;
ULONGSessionId;
ULONGUserAndGroupCount;含有的用户、组总数
ULONGRestrictedSidCount;
ULONGPrivilegeCount;含有的特权数量
ULONGVariableLength;
ULONGDynamicCharged;
ULONGDynamicAvailable;
ULONGDefaultOwnerIndex;令牌的默认拥有者在UserAndGroups数组中的位置
PSID_AND_ATTRIBUTESUserAndGroups;关键。
包含的一个用户、N个组(一个‘数组’)
PSID_AND_ATTRIBUTESRestrictedSids;
PSIDPrimaryGroup;令牌的基本组ID(即拥有者所属的基本组)
PLUID_AND_ATTRIBUTESPrivileges;关键。
包含的特权
PULONGDynamicPart;
PACLDefaultDacl;
TOKEN_TYPETokenType;令牌类型(自己的/模拟的)
SECURITY_IMPERSONATION_LEVELImpersonationLevel;模拟级别
ULONGTokenFlags;
BOOLEANTokenInUse;是否已被指派成了某个进程的令牌
PVOIDProxyData;
PVOIDAuditData;
LUIDOriginatingLogonSession;
ULONGVariablePart;
}TOKEN,*PTOKEN;
一个令牌最重要的信息便是它所包含的【特权、用户、组】
下面的函数用于创建一个SID
NTSTATUS
RtlAllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITYIdentifierAuthority,//签发机关
UCHARSubAuthorityCount,//级数
ULONGSubAuthority0,
ULONGSubAuthority1,
ULONGSubAuthority2,
ULONGSubAuthority3,
ULONGSubAuthority4,
ULONGSubAuthority5,
ULONGSubAuthority6,
ULONGSubAuthority7,
PSID*Sid)//返回
{
PISIDpSid;
if(SubAuthorityCount>8)
returnSTATUS_INVALID_SID;
pSid=RtlpAllocateMemory(RtlLengthRequiredSid(SubAuthorityCount),TAG_SID);
pSid->Revision=SID_REVISION;//固定为1
pSid->SubAuthorityCount=SubAuthorityCount;//级数
memcpy(&pSid->IdentifierAuthority,IdentifierAuthority,sizeof(SID_IDENTIFIER_AUTHORITY));
switch(SubAuthorityCount)
{
case8:
pSid->SubAuthority[7]=SubAuthority7;
case7:
pSid->SubAuthority[6]=SubAuthority6;
case6:
pSid->SubAuthority[5]=SubAuthority5;
case5:
pSid->SubAuthority[4]=SubAuthority4;
case4:
pSid->SubAuthority[3]=SubAuthority3;
case3:
pSid->SubAuthority[2]=SubAuthority2;
case2:
pSid->SubAuthority[1]=SubAuthority1;
case1:
pSid->SubAuthority[0]=SubAuthority0;
break;
}
*Sid=pSid;
returnSTATUS_SUCCESS;
}
SID本身是一个结构体,但SID还有另外一种通俗的表示法:
“S-版本号-签发机关-N级ID”。
如“S-1-5-23223-23422-286-1025”表示系统中的第24个用户,就是一个4级的SID,其中签发机关为5,表示NT域。
Windows中预定义了些常见的组ID,如
S-1-1-0表示everyone组
S-1-2-0表示Users组
S-1-3-0表示Creators组
前面说了,一个进程在创建时会继承它父进程的令牌,我们看
NTSTATUSPspInitializeProcessSecurity(INPEPROCESSProcess,INPEPROCESSParentOPTIONAL)
{
NTSTATUSStatus=STATUS_SUCCESS;
PTOKENNewToken,ParentToken;
if(Parent)
{
ParentToken=PsReferencePrimaryToken(Parent);//获得父进程的令牌
//克隆父进程的令牌(但令牌ID不同)
Status=SeSubProcessToken(ParentToken,&NewToken,TRUE,0);
ObFastDereferenceObject(&Parent->Token,ParentToken);
if(NT_SUCCESS(Status))
ObInitializeFastReference(&Process->Token,NewToken);//设置为子进程的令牌
}
else
{
ObInitializeFastReference(&Process->Token,NULL);
SeAssignPrimaryToken(Process,PspBootAccessToken);//指派令牌
}
returnStatus;
}
这样,同属于一个用户创建的所有进程的令牌都是一样的,本来就应该如此。
但是进程不是行为的主体,具体要去访问对象时,不是由进程去访问,而是由线程去访问。
所以,每个线程也得有令牌。
默认情况下,每个线程的令牌就是其所属进程的令牌。
但是,线程可以模拟使用其他进程的令牌,用来以其他线程的名义去访问对象。
为此,ETHREAD结构中有一个ImpersonationInfo字段,是一个PS_IMPERSONATION_INFORMATION结构指针,记录了该线程使用的模拟令牌信息。
下面的函数用来创建一个令牌(令牌本身也是一种内核对象)
NTSTATUS
NtCreateToken(OUTPHANDLETokenHandle,//返回句柄
INACCESS_MASKDesiredAccess,
INPOBJECT_ATTRIBUTESObjectAttributes,
INTOKEN_TYPETokenType,//主令牌/模拟令牌
INPLUIDAuthenticationId,
INPLARGE_INTEGERExpirationTime,//过期时间
INPTOKEN_USERTokenUser,//该令牌代表的用户
INPTOKEN_GROUPSTokenGroups,//该令牌含有的所有组
INPTOKEN_PRIVILEGESTokenPrivileges,//该令牌含有的所有特权
INPTOKEN_OWNERTokenOwner,//令牌的默认拥有者
INPTOKEN_PRIMARY_GROUPTokenPrimaryGroup,//令牌的基本组
INPTOKEN_DEFAULT_DACLTokenDefaultDacl,//默认的ACL
INPTOKEN_SOURCETokenSource){
HANDLEhToken;
KPROCESSOR_MODEPreviousMode;
ULONGnTokenPrivileges=0;
LARGE_INTEGERLocalExpirationTime={{0,0}};
NTSTATUSStatus;
PreviousMode=ExGetPreviousMode();
if(PreviousMode!
=KernelMode)//if来自用户模式发起的调用
{
_SEH2_TRY
{
ProbeForWriteHandle(TokenHandle);
ProbeForRead(AuthenticationId,sizeof(LUID),sizeof(ULONG));
LocalExpirationTime=ProbeForReadLargeInteger(ExpirationTime);
ProbeForRead(TokenUser,sizeof(TOKEN_USER),sizeof(ULONG));
ProbeForRead(TokenGroups,sizeof(TOKEN_GROUPS),sizeof(ULONG));
ProbeForRead(TokenPrivileges,sizeof(TOKEN_PRIVILEGES),sizeof(ULONG));
ProbeForRead(TokenOwner,sizeof(TOKEN_OWNER),sizeof(ULONG));
ProbeForRead(TokenPrimaryGroup,sizeof(TOKEN_PRIMARY_GROUP),sizeof(ULONG));
ProbeForRead(TokenDefaultDacl,sizeof(TOKEN_DEFAULT_DACL),sizeof(ULONG));
ProbeForRead(TokenSource,sizeof(TOKEN_SOURCE),sizeof(ULONG));
nTokenPrivileges=TokenPrivileges->PrivilegeCount;
}
。
。
。
}
else
{
nTokenPrivileges=TokenPrivileges->PrivilegeCount;
LocalExpirationTime=*ExpirationTime;
}
Status=SepCreateToken(&hToken,PreviousMode,DesiredAccess,ObjectAttributes,TokenType,
ObjectAttributes->SecurityQualityOfService->ImpersonationLevel,
AuthenticationId,
&LocalExpirationTime,
&TokenUser->User,
TokenGroups->GroupCount,
TokenGroups->Groups,
0,
nTokenPrivileges,
TokenPrivileges->Privileges,
TokenOwner->Owner,
TokenPrimaryGroup->PrimaryGroup,
TokenDefaultDacl->DefaultDacl,
TokenSource,
FALSE);
if(NT_SUCCESS(Status))
{
_SEH2_TRY
{
*TokenHandle=hToken;
}
。
。
。
}
returnStatus;
}
NTSTATUS
SepCreateToken(OUTPHANDLETokenHandle,
INKPROCESSOR_MODEPreviousMode,
INACCESS_MASKDesiredAccess,
INPOBJECT_ATTRIBUTESObjectAttributes,
INTOKEN_TYPETokenType,
INSECURITY_IMPERSONATION_LEVELImpersonationLevel,
INPLUIDAuthenticationId,
INPLARGE_INTEGERExpirationTime,
INPSID_AND_ATTRIBUTESUser,
INULONGGroupCount,
INPSID_AND_ATTRIBUTESGroups,
INULONGGroupLength,
INULONGPrivilegeCount,
INPLUID_AND_ATTRIBUTESPrivileges,
INPSIDOwner,//令牌的默认拥有者用户ID
INPSIDPrimaryGroup,//令牌的基本组ID
INPACLDefaultDacl,
INPTOKEN_SOURCETokenSource,
INBOOLEANSystemToken)
{
PTOKENAccessToken;
LUIDTokenId;
LUIDModifiedId;
PVOIDEndMem;
ULONGuLength;
ULONGi;
NTSTATUSStatus;
ULONGTokenFlags=0;
for(i=0;i { if(Groups[i].Attributes&SE_GROUP_MANDATORY)//默认启用所有强制类型的组 Groups[i].Attributes|=(SE_GROUP_ENABLED|SE_GROUP_ENABLED_BY_DEFAULT); if(RtlEqualSid(SeAliasAdminsSid,Groups[i].Sid)) TokenFlags|=TOKEN_HAS_ADMIN_GROUP;//标记本令牌中含有一个管理员组,提高效率用 } for(i=0;i { if(((RtlEqualLuid(&Privileges[i].Luid,&SeChangeNotifyPrivilege))&& (Privileges[i].Attributes&SE_PRIVILEGE_ENABLED))) { TokenFlags|=TOKEN_HAS_TRAVERSE_PRIVILEGE;//标记本令牌含有对象目录遍历特权 } } ZwAllocateLocallyUniqueId(&TokenId);//分配一个唯一的令牌ID ZwAllocateLocallyUniqueId(&ModifiedId);//再分配一个唯一的ModifiedId //关键。 创建一个令牌内核对象 Status=ObCreateObject(PreviousMode,SepTokenObjectType,//令牌类型 ObjectAttributes,PreviousMode,NULL,sizeof(TOKEN), 0,0,(PVOID*)&AccessToken); RtlZeroMemory(AccessToken,sizeof(TOKEN)); AccessToken->TokenLock=&SepTokenLock; RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,&TokenSource->SourceIdentifier); memcpy(AccessToken->TokenSource.SourceName,TokenSource->SourceName, sizeof(TokenSource->SourceName)); RtlCopyLuid(&AccessToken->TokenId,&TokenId);//填写令牌ID RtlCopyLuid(&AccessToken->AuthenticationId,AuthenticationId); AccessToken->ExpirationTime=*ExpirationTime; RtlCopyLuid(&AccessToken->ModifiedId,&ModifiedId); AccessToken->UserAndGroupCount=GroupCount+1;//一个用户N个组 AccessToken->PrivilegeCount=PrivilegeCount; AccessToken->TokenFlags=TokenFlags; AccessToken->TokenType=TokenType; AccessToken->ImpersonationLevel=ImpersonationLevel; uLength=sizeof(SID_AND_ATTRIBUTES)*AccessToken->UserAndGroupCount; uLength+=RtlLengthSid(User); for(i=0;i uLength+=RtlLengthSid(Groups[i].Sid); AccessToken->UserAndGroups= (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PagedPool,uLength,'uKOT'); EndMem=&AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; //填写用户SID到令牌中 Status=RtlCopySidAndAttributesArray(1,User,uLength,AccessToken->UserAndGroups, EndMem,&EndMem,&uLength); if(NT_SUCCESS(Status)) { //填写所有组SID到令牌中 Status=RtlCopySidAndAttributesArray(GroupCount,Groups,uLength, &AccessToken->UserAndGroups[1], EndMem,&EndMem,&uLength); } if(NT_SUCCESS(Status)) { //查找令牌的基本组和拥有者在UserAndGroups数组中的位置,记录在令牌中 Status=SepFindPrimaryGroupAndDefaultOwner(AccessToken,PrimaryG
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- windows 源码 分析 14 权限 管理
![提示](https://static.bingdoc.com/images/bang_tan.gif)