windows Access Token 、ACL、ACE学习笔记

访问控制列表ACL学习 需要注意的是,DACL 只是访问控制的一部分,它仅涵盖了资源的自由访问控制。在 Windows 操作系统中,还有其他类型的访问控制,如系统访问控制列表(SACL)用于审核和监视访问,以及对象所有者等。总而言之,DACL 是 Windows 操作系统中用于自由访问控制的权限机制,用于确定谁可以访问资源以及他们可以执行的操作。它提供了一种灵活的方式来定义和管理资源的访问权限,以满足安全性和数据保护的需求。 阅读详情

今日看了看关于windows本身安全机制的一些文章,所以将自己掌握到的一些东西供大家探讨一下。

 

1. Access Token

  windows访问令牌记录着某用户的SID、组ID、Session、及权限等信息,要获取这些信息,可以通过GetTokenInformation API获得。以下是一些代码样例

#define GETATTRI(desc, attri, check) \
if (attri & check)\
{\
	if (desc!=_T(""))\
	{\
		desc += _T(" | ");\
	}\
	desc+=_T(#check);\
}

#define MAKESIDDESC(type) {type, _T(#type)}

struct SIDNameDesc 
{
	SID_NAME_USE type;
	TCHAR* desc;
};

SIDNameDesc gvSidUseType[]=
{
	MAKESIDDESC(SidTypeUser),
	MAKESIDDESC(SidTypeGroup),
	MAKESIDDESC(SidTypeDomain),
	MAKESIDDESC(SidTypeAlias),
	MAKESIDDESC(SidTypeWellKnownGroup),
	MAKESIDDESC(SidTypeDeletedAccount),
	MAKESIDDESC(SidTypeInvalid),
	MAKESIDDESC(SidTypeUnknown),
	MAKESIDDESC(SidTypeComputer),
	MAKESIDDESC(SidTypeLabel),
};

TCHAR* GetSidNameUseDescription(SID_NAME_USE type)
{
	TCHAR* pDesc=NULL;
	int count = sizeof(gvSidUseType) / sizeof(SIDNameDesc);
	for (int i=0;i<count;i++)
	{
		if (gvSidUseType[i].type==type)
		{
			pDesc=gvSidUseType[i].desc;
			break;
		}
	}
	return pDesc;
}

CString GetAttribute(DWORD attribute)
{
	CString strAttri;
	GETATTRI(strAttri,attribute,SE_GROUP_ENABLED);
	GETATTRI(strAttri,attribute,SE_GROUP_ENABLED_BY_DEFAULT);
	GETATTRI(strAttri,attribute,SE_GROUP_LOGON_ID);
	GETATTRI(strAttri,attribute,SE_GROUP_MANDATORY);
	GETATTRI(strAttri,attribute,SE_GROUP_OWNER);
	GETATTRI(strAttri,attribute,SE_GROUP_RESOURCE);
	GETATTRI(strAttri,attribute,SE_GROUP_USE_FOR_DENY_ONLY);

	return strAttri;
}

void dump(PSID pSid)
{
	USES_CONVERSION;

	LPTSTR strSid;
	ConvertSidToStringSid(pSid,&strSid);
	cout<<"SID : "<<T2A(strSid)<<endl;

	TCHAR name[MAX_PATH];
	TCHAR domainName[MAX_PATH];
	DWORD dwNamelen=MAX_PATH;
	DWORD dwDomainNamelen=MAX_PATH;
	SID_NAME_USE nameUse;
	if(!LookupAccountSid(NULL,pSid,name,&dwNamelen,domainName,&dwDomainNamelen,&nameUse))
	{
		cout<<"LookupAccountSid failed with "<<GetLastError()<<endl;
		return;
	}

	StrCat(domainName,_T("\\"));
	StrCat(domainName, name);
	cout<<"Account : "<<T2A(domainName)<<endl;
	cout<<"  Type  : "<<T2A(GetSidNameUseDescription(nameUse))<<endl;
}

void dump(DWORD attribute)
{
	USES_CONVERSION;
	CString strAttri = GetAttribute(attribute);
	cout<<"Attribute : "<<T2A(strAttri)<<endl;
}

void GetTokenUser(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenUser, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenUser, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_USER* pUser = (TOKEN_USER*)p;
	dump(pUser->User.Sid);
	dump(pUser->User.Attributes);
}


void GetTokenGroup(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenGroups, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenGroups, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_GROUPS* pGroup = (TOKEN_GROUPS*)p;
	
	for (int i=0;i<pGroup->GroupCount;i++)
	{
		dump(pGroup->Groups[i].Sid);
		dump(pGroup->Groups[i].Attributes);
		cout<<endl;
	}
}

void dump(LUID_AND_ATTRIBUTES privilege)
{
	USES_CONVERSION;
	TCHAR buffer[MAX_PATH];
	DWORD dwLength=MAX_PATH;
	if(!LookupPrivilegeName(NULL,&privilege.Luid,buffer,&dwLength))
	{
		cout<<"LookupPrivilegeName failed with "<<GetLastError()<<endl;
		return;
	}

	CString strAttribute;
	GETATTRI(strAttribute,privilege.Attributes,SE_PRIVILEGE_ENABLED);
	GETATTRI(strAttribute,privilege.Attributes,SE_PRIVILEGE_ENABLED_BY_DEFAULT);
	GETATTRI(strAttribute,privilege.Attributes,SE_PRIVILEGE_REMOVED);
	GETATTRI(strAttribute,privilege.Attributes,SE_PRIVILEGE_USED_FOR_ACCESS);

	CString strDump = buffer;
	strDump += _T(" : ");
	strDump += strAttribute;
	cout<<T2A(strDump)<<endl;
}

void GetPrivileges(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenPrivileges, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenPrivileges, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_PRIVILEGES* pPrivileges = (TOKEN_PRIVILEGES*)p;

	for (int i=0;i<pPrivileges->PrivilegeCount;i++)
	{
		dump(pPrivileges->Privileges[i]);
	}
}

void GetOwnerInfo(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenOwner, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenOwner, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_OWNER* pOwner = (TOKEN_OWNER*)p;

	dump(pOwner->Owner);
}


void GetPrimaryGroup(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenPrimaryGroup, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenPrimaryGroup, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_PRIMARY_GROUP* pPrimaryGroup = (TOKEN_PRIMARY_GROUP*)p;

	dump(pPrimaryGroup->PrimaryGroup);
}

void Print(LPCSTR desc, LUID luid)
{
	LARGE_INTEGER* pli = (LARGE_INTEGER*)&luid;
	cout<<desc<<" : "<<pli->QuadPart<<endl;
}

void dump(TOKEN_STATISTICS* pStatistics)
{
	Print("TokenID", pStatistics->TokenId);
	Print("AuthenticationId", pStatistics->AuthenticationId);
	if (pStatistics->TokenType == TokenPrimary)
	{
		cout<<"Primary Token"<<endl;
	}
	else
	{
		cout<<"Impersonation Token"<<endl;
	}

}

void GetTokenStatistics(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenStatistics, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenStatistics, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_STATISTICS* pTokenStatistics = (TOKEN_STATISTICS*)p;

	dump(pTokenStatistics);
}

void GetTokenSource(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	GetTokenInformation(hToken, TokenSource, NULL, NULL, &dwReturnedLen);
	if (GetLastError()!=ERROR_INSUFFICIENT_BUFFER)
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	LPVOID p=LocalAlloc(LPTR, dwReturnedLen);
	if (p==NULL)
	{
		cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	}

	if(!GetTokenInformation(hToken, TokenSource, p, dwReturnedLen, &dwReturnedLen))
	{
		if (GetLastError()!=ERROR_SUCCESS)
		{
			cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
		}
	}

	TOKEN_SOURCE* pSource = (TOKEN_SOURCE*)p;

	cout<<"Source Name : "<<pSource->SourceName<<endl;
	Print("Source ID   : ", pSource->SourceIdentifier);
}

void GetTokenSessionID(HANDLE hToken)
{
	DWORD dwReturnedLen=0;
	DWORD sessionID;
	if(!GetTokenInformation(hToken, TokenSessionId, &sessionID, sizeof(DWORD), &dwReturnedLen))
	{
		cout<<"GetTokenInformation failed with "<<GetLastError()<<endl;
	}

	cout<<"Session ID : "<<sessionID<<endl;
}


大家知道在Win7上管理员登录后会关联两个Access Token,一个是有管理员权限的Access Token,另外一个是被限制权限的Access Token,其中Restricted Access Token中Administrators组的属性为SE_GROUP_USE_FOR_DENY_ONLY,说明系统在访问检查时,只会检查给这个组应用了拒绝访问的那些ACE项,而允许访问的ACE项被忽略。而CheckTokenMembership在判断一个Token是否属于某个组时,这个组必须存在并且组属性包含SE_GROUP_ENABLED,才会认为这个Token属于这个组。所以一个权限未提升的进程的令牌是不会认为属于Administrators组的。

2. 安全描述符

安全描述符是windows安全对象管理的一种数据结构,用来描述允许什么用户使用某种权限访问它,拒绝什么用户使用某种权限访问它。(另外还有一些审计操作,不讨论了)。获取ACE信息,见一些代码

void ParseAce(PACE_HEADER pAceHdr);

#define GETATTRI(mask, check) \
if (mask & check)\
{\
	cout<<#check<<endl;\
}

#define MAKESIDDESC(type) {type, _T(#type)}

struct SIDNameDesc 
{
	SID_NAME_USE type;
	TCHAR* desc;
};

SIDNameDesc gvSidUseType[]=
{
	MAKESIDDESC(SidTypeUser),
	MAKESIDDESC(SidTypeGroup),
	MAKESIDDESC(SidTypeDomain),
	MAKESIDDESC(SidTypeAlias),
	MAKESIDDESC(SidTypeWellKnownGroup),
	MAKESIDDESC(SidTypeDeletedAccount),
	MAKESIDDESC(SidTypeInvalid),
	MAKESIDDESC(SidTypeUnknown),
	MAKESIDDESC(SidTypeComputer),
	MAKESIDDESC(SidTypeLabel),
};

TCHAR* GetSidNameUseDescription(SID_NAME_USE type)
{
	TCHAR* pDesc=NULL;
	int count = sizeof(gvSidUseType) / sizeof(SIDNameDesc);
	for (int i=0;i<count;i++)
	{
		if (gvSidUseType[i].type==type)
		{
			pDesc=gvSidUseType[i].desc;
			break;
		}
	}
	return pDesc;
}

void dump(PSID pSid)
{
	USES_CONVERSION;

	LPTSTR strSid;
	ConvertSidToStringSid(pSid,&strSid);
	cout<<"SID : "<<T2A(strSid)<<endl;

	TCHAR name[MAX_PATH];
	TCHAR domainName[MAX_PATH];
	DWORD dwNamelen=MAX_PATH;
	DWORD dwDomainNamelen=MAX_PATH;
	SID_NAME_USE nameUse;
	if(!LookupAccountSid(NULL,pSid,name,&dwNamelen,domainName,&dwDomainNamelen,&nameUse))
	{
		cout<<"LookupAccountSid failed with "<<GetLastError()<<endl;
		return;
	}

	StrCat(domainName,_T("\\"));
	StrCat(domainName, name);
	cout<<"Account : "<<T2A(domainName)<<endl;
	cout<<"  Type  : "<<T2A(GetSidNameUseDescription(nameUse))<<endl;
}

void dumpAccessMask(ACCESS_MASK mask)
{
	GETATTRI(mask, DELETE);
	GETATTRI(mask, READ_CONTROL);
	GETATTRI(mask, WRITE_DAC);
	GETATTRI(mask, WRITE_OWNER);
	GETATTRI(mask, SYNCHRONIZE);
}


#define MAKESDCDESC(sdc) {sdc, _T(#sdc)}

struct SdcDesc 
{
	DWORD sdc;
	TCHAR* desc;
};

SdcDesc gvSdcDesc[]=
{
	MAKESDCDESC(SE_DACL_AUTO_INHERIT_REQ),
	MAKESDCDESC(SE_DACL_AUTO_INHERITED),
	MAKESDCDESC(SE_DACL_DEFAULTED),
	MAKESDCDESC(SE_DACL_PRESENT),
	MAKESDCDESC(SE_DACL_PROTECTED),
	MAKESDCDESC(SE_GROUP_DEFAULTED),

	MAKESDCDESC(SE_OWNER_DEFAULTED),
	MAKESDCDESC(SE_RM_CONTROL_VALID),
	MAKESDCDESC(SE_SACL_AUTO_INHERIT_REQ),
	MAKESDCDESC(SE_SACL_AUTO_INHERITED),

	MAKESDCDESC(SE_SACL_DEFAULTED),
	MAKESDCDESC(SE_SACL_PRESENT),
	MAKESDCDESC(SE_SACL_PROTECTED),
	MAKESDCDESC(SE_SELF_RELATIVE)
};

void dumpSdc(SECURITY_DESCRIPTOR_CONTROL controlBit)
{
	USES_CONVERSION;

	CString strDesc;
	int count = sizeof(gvSdcDesc)/sizeof(SdcDesc);

	for (int i=0;i<count;i++)
	{
		if (controlBit & gvSdcDesc[i].sdc)
		{
			if (strDesc!=_T(""))
			{
				strDesc += _T(" | ");
			}
			strDesc+=gvSdcDesc[i].desc;
		}
	}

	cout<<"Security Description Control"<<endl;
	cout<<T2A(strDesc)<<endl;
}


int _tmain(int argc, _TCHAR* argv[])
{
	TCHAR* file = _T("F:\\bixy\\topdesk.ini");
	PSID pSidOwner;
	PSID pSidGroup;
	PACL pDacl;
	PSECURITY_DESCRIPTOR pSD;
	DWORD dwRet = GetNamedSecurityInfo(file,SE_FILE_OBJECT,DACL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION,
		&pSidOwner,&pSidGroup,&pDacl,NULL,&pSD);
	if (dwRet==ERROR_SUCCESS)
	{
		cout<<"-------------------Owner--------------------"<<endl;
		dump(pSidOwner);
		cout<<endl;
		cout<<"-------------------Group--------------------"<<endl;
		dump(pSidGroup);
	}
	else
	{
		cout<<"GetNamedSecurityInfo failed with "<<dwRet<<endl;
		return 0;
	}

	SECURITY_DESCRIPTOR_CONTROL controlBit;
	DWORD dwRevision;
	if(!GetSecurityDescriptorControl(pSD,&controlBit,&dwRevision))
	{
		cout<<"GetSecurityDescriptorControl failed with "<<GetLastError()<<endl;
		return 0;
	}

	dumpSdc(controlBit);

	ULONG countofExplicitEntries;
	PEXPLICIT_ACCESS pExplicitAcess;
	dwRet = GetExplicitEntriesFromAcl(pDacl,&countofExplicitEntries,&pExplicitAcess);
	if (dwRet==ERROR_SUCCESS)
	{
		for (int i=0;i<countofExplicitEntries;i++)
		{
			cout<<endl<<"----------------------------------------"<<endl;
			cout<<"Explicit Access "<<i+1<<endl;
			cout<<"Access Mask:"<<endl;
			dumpAccessMask(pExplicitAcess[i].grfAccessPermissions);
			cout<<endl;

			cout<<"Access Mode"<<endl;
			switch(pExplicitAcess[i].grfAccessMode)
			{
			case NOT_USED_ACCESS:
				cout<<"NOT_USED_ACCESS"<<endl;
				break;

			case GRANT_ACCESS:
				cout<<"GRANT_ACCESS"<<endl;
				break;

			case SET_ACCESS:
				cout<<"SET_ACCESS"<<endl;
				break;

			case DENY_ACCESS:
				cout<<"DENY_ACCESS"<<endl;
				break;

			case REVOKE_ACCESS:
				cout<<"REVOKE_ACCESS"<<endl;
				break;

			case SET_AUDIT_SUCCESS:
				cout<<"SET_AUDIT_SUCCESS"<<endl;
				break;

			case SET_AUDIT_FAILURE:
				cout<<"SET_AUDIT_FAILURE"<<endl;
				break;
			}

			if (pExplicitAcess[i].Trustee.TrusteeForm==TRUSTEE_IS_SID)
			{
				dump((PSID)pExplicitAcess[i].Trustee.ptstrName);
			}

			cout<<endl<<"--------------------------------"<<endl<<endl;
		}
	}
	else
	{
		cout<<"GetExplicitEntriesFromAcl failed with "<<GetLastError()<<endl;
	}

	TRUSTEE Trustee;
	ZeroMemory(&Trustee,sizeof(TRUSTEE));
	Trustee.pMultipleTrustee=NULL;
	Trustee.MultipleTrusteeOperation=NO_MULTIPLE_TRUSTEE;
	Trustee.TrusteeForm=TRUSTEE_IS_SID;
	Trustee.TrusteeType=TRUSTEE_IS_USER;
	Trustee.ptstrName=(LPTSTR)pSidOwner;

	ACCESS_MASK mask=0;
	dwRet = GetEffectiveRightsFromAcl(pDacl,&Trustee,&mask);
	if (dwRet==ERROR_SUCCESS)
	{
		cout<<endl;
		cout<<"Access Mask:"<<endl;
		dumpAccessMask(mask);
	}
	else
	{
		cout<<"GetEffectiveRightsFromAcl failed with "<<GetLastError()<<endl;
	}

	cout<<endl<<"--------------------------------"<<endl<<endl;
	ACL_SIZE_INFORMATION asi;
	if(!GetAclInformation(pDacl,&asi,sizeof(ACL_SIZE_INFORMATION),AclSizeInformation))
	{
		cout<<"GetAclInformation failed with "<<GetLastError()<<endl;
	}

	for (int i=0;i<asi.AceCount;i++)
	{
		LPVOID pAce;
		if (!GetAce(pDacl,i,&pAce))
		{
			cout<<"GetAce failed with "<<GetLastError()<<endl;
			break;
		}

		PACE_HEADER pAceHeader = (PACE_HEADER)pAce;
		ParseAce(pAceHeader);
	}

	//LocalFree(pDacl);
	cout<<endl;
	return 0;
}

void dumpAceFlags(BYTE flag)
{
	CString strDesc;
	GETATTRI(flag,CONTAINER_INHERIT_ACE);
	GETATTRI(flag,FAILED_ACCESS_ACE_FLAG);
	GETATTRI(flag,INHERIT_ONLY_ACE);
	GETATTRI(flag,INHERITED_ACE);
	GETATTRI(flag,NO_PROPAGATE_INHERIT_ACE);
	GETATTRI(flag,OBJECT_INHERIT_ACE);
	GETATTRI(flag,SUCCESSFUL_ACCESS_ACE_FLAG);
}

void ParseAce(PACCESS_ALLOWED_ACE pAllowedAce)
{
	dumpAccessMask(pAllowedAce->Mask);
	dump((PSID)&pAllowedAce->SidStart);
}

void ParseAce(PACCESS_DENIED_ACE pAllowedAce)
{
	dumpAccessMask(pAllowedAce->Mask);
	dump((PSID)&pAllowedAce->SidStart);
}

void ParseAce(PSYSTEM_ALARM_OBJECT_ACE pAllowedAce)
{

}

void ParseAce(PSYSTEM_ALARM_ACE pAllowedAce)
{

}


void ParseAce(PSYSTEM_ALARM_CALLBACK_ACE pAllowedAce)
{

}

void ParseAce(PSYSTEM_ALARM_CALLBACK_OBJECT_ACE pAllowedAce)
{

}

void ParseAce(PSYSTEM_AUDIT_ACE pAllowedAce)
{

}

void ParseAce(PSYSTEM_MANDATORY_LABEL_ACE pAllowedAce)
{

}


void ParseAce(PACE_HEADER pAceHdr)
{
	cout<<"-------------------------------------"<<endl;
	cout<<"-------------------------------------"<<endl;
	cout<<"-------------------------------------"<<endl;
	dumpAceFlags(pAceHdr->AceFlags);
	cout<<endl;
	if (pAceHdr->AceType == ACCESS_ALLOWED_ACE_TYPE)
	{
		cout<<"ACCESS_ALLOWED_ACE_TYPE"<<endl;
		ParseAce((PACCESS_ALLOWED_ACE)pAceHdr);
	}
	else if (pAceHdr->AceType == ACCESS_DENIED_ACE_TYPE)
	{
		cout<<"ACCESS_DENIED_ACE_TYPE"<<endl;
		ParseAce((PACCESS_DENIED_ACE)pAceHdr);
	}
	else if(pAceHdr->AceType == SYSTEM_ALARM_OBJECT_ACE_TYPE)
	{
		cout<<"SYSTEM_ALARM_OBJECT_ACE_TYPE"<<endl;
		ParseAce((PSYSTEM_ALARM_OBJECT_ACE)pAceHdr);
	}
	else if (pAceHdr->AceType == SYSTEM_ALARM_ACE_TYPE)
	{
		cout<<"SYSTEM_ALARM_ACE_TYPE"<<endl;
		ParseAce((PSYSTEM_ALARM_ACE)pAceHdr);
	}
	else if (pAceHdr->AceType == SYSTEM_ALARM_CALLBACK_ACE_TYPE)
	{
		cout<<"SYSTEM_ALARM_CALLBACK_ACE_TYPE"<<endl;
		ParseAce((PSYSTEM_ALARM_CALLBACK_ACE)pAceHdr);
	}
	else if (pAceHdr->AceType == SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE)
	{
		cout<<"SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE"<<endl;
		ParseAce((PSYSTEM_ALARM_CALLBACK_OBJECT_ACE)pAceHdr);
	}
	else if (pAceHdr->AceType == SYSTEM_AUDIT_ACE_TYPE)
	{
		cout<<"SYSTEM_AUDIT_ACE_TYPE"<<endl;
		ParseAce((PSYSTEM_ALARM_ACE)pAceHdr);
	}
	else if (pAceHdr->AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)
	{
		cout<<"SYSTEM_MANDATORY_LABEL_ACE_TYPE"<<endl;
		ParseAce((PSYSTEM_MANDATORY_LABEL_ACE)pAceHdr);
	}
	cout<<endl;
}


3. 为新建对象使用安全描述符(或更改描述符)

#define MAKESDCDESC(sdc) {sdc, _T(#sdc)}

struct SdcDesc 
{
	DWORD sdc;
	TCHAR* desc;
};

SdcDesc gvSdcDesc[]=
{
	MAKESDCDESC(SE_DACL_AUTO_INHERIT_REQ),
	MAKESDCDESC(SE_DACL_AUTO_INHERITED),
	MAKESDCDESC(SE_DACL_DEFAULTED),
	MAKESDCDESC(SE_DACL_PRESENT),
	MAKESDCDESC(SE_DACL_PROTECTED),
	MAKESDCDESC(SE_GROUP_DEFAULTED),

	MAKESDCDESC(SE_OWNER_DEFAULTED),
	MAKESDCDESC(SE_RM_CONTROL_VALID),
	MAKESDCDESC(SE_SACL_AUTO_INHERIT_REQ),
	MAKESDCDESC(SE_SACL_AUTO_INHERITED),

	MAKESDCDESC(SE_SACL_DEFAULTED),
	MAKESDCDESC(SE_SACL_PRESENT),
	MAKESDCDESC(SE_SACL_PROTECTED),
	MAKESDCDESC(SE_SELF_RELATIVE)
};

void dumpSdc(SECURITY_DESCRIPTOR_CONTROL controlBit)
{
	USES_CONVERSION;

	CString strDesc;
	int count = sizeof(gvSdcDesc)/sizeof(SdcDesc);

	for (int i=0;i<count;i++)
	{
		if (controlBit & gvSdcDesc[i].sdc)
		{
			if (strDesc!=_T(""))
			{
				strDesc += _T(" | ");
			}
			strDesc+=gvSdcDesc[i].desc;
		}
	}

	cout<<"Security Description Control"<<endl;
	cout<<T2A(strDesc)<<endl;
}

void CreateDACL()
{
	TCHAR* filename = _T("F:\\bixy\\topdesk.ini");


	SECURITY_DESCRIPTOR sd;
	PACL pAcl;
	InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);


	EXPLICIT_ACCESS explicitAccess;
	ZeroMemory(&explicitAccess,sizeof(EXPLICIT_ACCESS));
	BuildExplicitAccessWithName(&explicitAccess, _T("Everyone"), GENERIC_READ|GENERIC_WRITE, GRANT_ACCESS, NO_INHERITANCE);
	
	DWORD dwRet = SetEntriesInAcl(1, &explicitAccess, NULL, &pAcl);
	if (ERROR_SUCCESS != dwRet) 
	{
		cout<<"SetEntriesInAcl failed with "<<GetLastError()<<endl;
		return;
	}

	EXPLICIT_ACCESS explicitAccess2;
	ZeroMemory(&explicitAccess2,sizeof(EXPLICIT_ACCESS));
	BuildExplicitAccessWithName(&explicitAccess2, _T("Administrators"), GENERIC_READ|GENERIC_WRITE, DENY_ACCESS, CONTAINER_INHERIT_ACE);

	dwRet = SetEntriesInAcl(1, &explicitAccess2, pAcl, &pAcl);
	if (ERROR_SUCCESS != dwRet) 
	{
		cout<<"SetEntriesInAcl failed with "<<GetLastError()<<endl;
		return;
	}

	//PSID Sid;
	//DWORD SidSize;
	//SidSize = SECURITY_MAX_SID_SIZE;
	//// Allocate enough memory for the largest possible SID.
	//if(!(Sid = LocalAlloc(LMEM_FIXED, SidSize)))
	//{    
	//	cout<<"LocalAlloc failed with "<<GetLastError()<<endl;
	//	return;
	//}

	//if(!CreateWellKnownSid(WinBuiltinAdministratorsSid ,NULL,Sid,&SidSize))
	//{
	//	cout<<"CreateWellKnownSid failed with "<<GetLastError()<<endl;
	//	return;
	//}

	//if(!AddAccessDeniedAce(pAcl,ACL_REVISION,GENERIC_READ|GENERIC_WRITE,Sid))
	//{
	//	cout<<"AddAccessDeniedAce failed with "<<GetLastError()<<endl;
	//	return;
	//}

	SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE);


	SECURITY_DESCRIPTOR_CONTROL controlBit;
	DWORD dwRevision;
	if(!GetSecurityDescriptorControl(&sd,&controlBit,&dwRevision))
	{
		cout<<"GetSecurityDescriptorControl failed with "<<GetLastError()<<endl;
		return;
	}

	dumpSdc(controlBit);

	SECURITY_ATTRIBUTES sa;
	sa.nLength=sizeof(SECURITY_ATTRIBUTES);
	sa.bInheritHandle=FALSE;
	sa.lpSecurityDescriptor=&sd;


	HANDLE hFile = CreateFile(filename,GENERIC_READ|GENERIC_WRITE, NULL, &sa, CREATE_ALWAYS, NULL,NULL);
	CloseHandle(hFile);
}


 ps:判断当前用户是否域登录,可以先查询用户所属的组,再用LookupAccountSid查询组Sid的SID_NAME_USE

 

Windows下让普通用户操作内核驱动:SDDL权限修改全解析 Windows安全模型以访问令牌和安全描述符为核心,服务和内核驱动统一由服务控制管理器(SCM)管理。默认情况下,服务DACL仅向管理员授予启动和停止权限,导致普通用户在驱动调试、自动化测试或内网运维中频频遭遇“拒绝访问”。SDDL(安全描述符定义语言)提供了一种精确控制服务权限的途径,通过sc.exe sdset可为普通用户追加SERVICE_START和SERVICE_STOP权限,无需分发管理员密码,有效降低提权风险。该方法适用于驱动开发、终端管控、测试环境自动化等场景,既能满足业务需求,又能保留安全 阅读详情

相关推荐

AI赋能Windows权限诊断:智能解决“无法枚举容器对象”难题

在Windows系统管理与运维中,访问控制列表(ACL)和权限模型是保障系统安全的核心机制。其原理基于用户身份验证和资源授权,通过权限继承、令牌机制等实现细粒度的访问控制。这一技术价值在于平衡安全性与可用性,确保最小权限原则。典型的应用场景包括文件系统操作、注册表访问以及Active Directory对象管理。当进程因权限不足而无法列出容器内对象时,便会触发“无法枚举容器对象”错误。本文聚焦于如何利用AI编程助手(如Cursor、GitHub Copilot)构建智能化诊断链,通过感知上下文、分析根因、生

weixin_33805992的博客 447

关于:Windows 中的 ACL,DACL,SACL 和 ACE

关于:Windows 中的 ACL,DACL,SACL 和 ACE

老陈醋的博客 2964

Win11磁盘根目录新建文件夹权限问题深度解析

Windows 11中的磁盘根目录(如D:\)新建文件夹受限,本质是系统级资源访问控制机制升级所致,而非传统用户权限不足。其底层依托UAC深度集成、内核级路径保护策略与高完整性级别(High IL)路径标记,触发SeCreateFilePrivilege强制校验。该机制提升了代码完整性(KMCI)和应用控制(WDAC)防护能力,但也带来GUI操作卡顿与权限误判。典型应用场景包括开发环境初始化、企业终端部署及备份目录管理。本文聚焦Win11特有的NTFS安全描述符配置、PowerShell直写优化与fsuti

weixin_34037173的博客 269

ACL&ACE的三条原则!

第一:NTFS Permission are Cumulative 即多个组被赋予的不同的权限是可以累加的。第二:File Override Folder Permission 即文件的权限占先于目录的权限。文件的权限先起作用,文件夹的权限后起作用。即底层的权限优先。第三:Deny Override Other Permission 即拒绝访问权限优先。

技术点滴 5109

为什么你的ESXI无法识别移动硬盘?一步步教你解决USB存储挂载问题

本文深入解析了ESXi无法识别移动硬盘的根本原因,并提供了从诊断到解决的完整方案。核心在于理解ESXi的USB Arbitrator服务机制,通过检查服务状态、内核设备识别及分区表,逐步定位问题。文章详细指导了如何禁用USB仲裁服务以在主机挂载USB存储,或将其直通给虚拟机,并针对大容量硬盘、USB 3.0兼容性等进阶问题给出了实用建议。

qq_27496129的博客 331

企业微信API实战:解密external_userid的跨应用一致性管理

本文深入探讨企业微信API中external_userid的跨应用一致性管理问题,解析其本质及在不同应用场景下的ID不一致挑战。通过ID转换与统一管理方案,结合unionid实现跨应用客户数据整合,提供实战代码示例和架构设计,助力企业构建高效的客户管理系统。

weixin_29258297的博客 636

Windows安全描述符SECURITY_DESCRIPTOR

安全对象Securable Object是拥有SD的Windows的对象。所有的被命名的Windows的对象都是安全对象。一些没有命名的对象是安全对象,如:进程和线程,也有安全描述符SD。安全对象Securable Object是拥有SD的Windows的对象。在 Windows系统中,其是用一个安全描述符(Security Descriptors)的结构来保存其权限的设置信息,简称为SD,其在W

luckylion的专栏 3414

STM32CubeMx配置串口使用printf函数打印数据(HAL库开发)

HAL库开发串口,打印printf

m0_58832575的博客 6287

Windows 中的 ACL,DACL,SACL 和 ACE

DACL(Discretionary Access Control List,自由决定的访问控制列表),主要用于设置。- SACL(System Access Control List,SACL,系统访问控制列表),用于。- SD 有助于控制对对象的访问,它包含所有者的信息、要审核的内容以及以何种方式授予访问权限。(Access Control Entries)构成。- 它包含了真正的用于设置安全权限的 ACL。配置对安全对象的访问的审计(生成日志)。- 每个 ACL 由多个。

顺其自然~专栏 2462

ANSYS Twin Builder实战:5步搞定数字孪生模型部署(附ROM配置技巧)

本文详细解析了ANSYS Twin Builder在数字孪生模型部署中的实战应用,重点介绍了ROM(降阶模型)配置技巧。通过5个关键步骤,从环境搭建到工业部署,帮助工程师高效实现高精度三维仿真到轻量化数字孪生的转化,提升预测性维护和系统仿真效率。

weixin_27330481的博客 658

总结-NuerIPS2023-Direct Preference Optimization:Your Language Model is Secretly a Reward Model

对比PPO,DPO的泛化能力更强。

m0_60361484的博客 1606

初探 Windows Access Token

Access Token是一个与进程或者线程相关的对象。它包括有用户(持有该进程的用户)的安全标识符(security identifier)和特权(privileges)等等信息。当进程或者线程需要访问某个具有安全属性的对象时(通常是内核对象),OS会根据这个Token在该

805

glm-4v-9b环境配置全攻略:从CUDA版本冲突到bitsandbytes异常排查(RTX A4000实测)

本文详细介绍了在RTX A4000显卡上配置GLM-4V-9B多模态大模型的完整流程,重点解决CUDA版本冲突和bitsandbytes异常问题。通过4-bit量化技术显著降低显存占用,提供从环境预检到量化部署的实战指南,帮助开发者在有限显存环境下高效运行大模型。

weixin_30369041的博客 405

【windows】windows安全基础

windows安全基础 安全主体 security principal 是可以进行身份验证的实体。 哪个安全主体在要求访问?这个维度可以是用户,计算机和进程。一旦确认以后,系统就会发放SID。 例子:你正在运行服务,该进程需要访问计算机上的文件。操作系统需要知道谁要求访问这些文件。这个时候需要有适用于它的安全主体。 您将在windows中找到任何对象或实体都有一个安全主体(secur...

361

ROS2 - 乐动激光雷达 LD06

STL-06P 主要由激光测距核心,无线传电单元,无线通讯单元,角度测量单元、电机驱动单元和机械外壳组成。STL-06P 测距核心采用 DTOF 技术,可进行每秒 5000 次的测距。每次测距时,雷达发射出红外激光,激光遇到目标物体后被反射到单光子接收单元。

机器人控制与仿真应用 3484

半车(前后、左右)、整车悬架详细推导建模和simulink仿真分析

用达朗贝尔定理依据悬架数学模型,得到悬架模型微分方程,分别用simulink建立前后半车、左右半车悬架;结合转向2自由度模型与半车侧倾模型,对模型考虑相干性、延时性的C级随机路面下,仿真分析给定角阶跃输入下的侧倾稳定性。

Mr.邹的博客 1万+

Windows九项高危特权解析:ACL、令牌与权限加固实战

Windows权限管理并非“管理员/非管理员”二值开关,而是由SID、ACL、访问令牌、特权与完整性级别共同构成的访问控制体系。进程打开文件或注册表对象时,内核会拿令牌中的SID比对目标DACL,遵循拒绝优先于允许;而SeDebugPrivilege、SeImpersonatePrivilege等高危特权属于系统级能力,一旦错误分配或被滥用,可能带来提权与持久化风险。理解权限、特权、完整性级别的边界,对服务器交付、IIS/容器运行、备份审计和安全评估都有实际价值,也能减少“拒绝访问”类故障的误判。围绕九项高

weixin_34379433的博客 330

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

[Windows内核源码分析3] 引导过程(安全管理器初始化在Phase0部分的分析)

本文章记录分析安全管理器在windows系统引导的阶段0中的初始化工作。主要是SeInitSystem函数。进入后内部调用的实际上是。

輚至消亡 866

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Nt/2000/xp平台下的存储控制模型(Access Control Model)

Nt/2000/xp平台下的存储控制模型(Access Control Model) Byleezy_2000 2003-7-16 15:59 &lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt; (-) 鉴于在nt类操作系统下开发程序时有可能涉及操作注册表,读写文件和操控服务等...

webcenterol 105

LyricFever卡拉OK模式实战:打造常驻屏幕的悬浮歌词窗自定义指南

**LyricFever** 是一款为 macOS 打造的 Spotify 与 Apple Music 歌词工具(LyricsX 的精神续作)。它的**卡拉OK模式(Karaoke Mode)**能让**悬浮歌词窗**常驻在所有桌面之上,无论你切换到哪个应用,歌词都始终跟随音乐跳动。本文将带你完整掌握 LyricFever 悬浮歌词窗的开关方法,以及字体、背景色、透明度等全部自定义选项。 ##

gitblog_00054的博客 212

设计哲学的分野:为什么Windows在系统工程层面领先Linux,却输在代码质量

回到最初的问题:Windows和Linux谁更先进?在底层内核架构和系统核心机制上,Windows NT的设计更先进、更精密、更工程化;但在上层API和代码质量上,Linux更简洁、更干净、包袱更少。这不是谁对谁错的问题,而是不同目标下的不同选择。微软选择了向后兼容和企业级特性,代价是技术债务;Linux社区选择了快速迭代和开放,代价是架构一致性。有意思的是,两个系统正在向中间靠拢:Windows在不断开放,推出了WSL、WinGet、PowerShell,吸收了很多Linux的优点;

vortex5的博客 419

Codex Harness 安全沙箱机制原理

很多人第一次接触沙箱,会把它理解成“一个隔离目录”或者“一个受限容器”。这种理解不能说错,但不够本质。沙箱环境更准确的定义是:让一个执行体可以运行,但只能在被限制的能力边界内运行。这个“边界”不是抽象概念,而是具体的资源访问边界。最常见的通常有三类:文件系统边界:它能读哪些目录,能写哪些目录。网络边界:它能不能联网,能访问哪些目标地址。系统能力边界:它能不能启动子进程,能不能访问桌面、设备、注册表、系统接口。

qq_31142237的博客 900

windows 安全模型简介

操作系统中有些资源是不能由用户代码直接访问的,比如线程进程,文件等等,这些资源必须由系统级代码由RING3层进入到RING0层操作,并且返回一些标识供用户程序使用,一般调用某个函数陷入到内核,这样的函数叫做系统调用,而有些不直接陷入到内核,一般叫做系统API,linux中使用系统调用,而windows中封装了一系列的API。 windows对象与句柄 windows对象 操作系统为了安全

Masimaro的专栏 9510

Windows Server权限与路径问题深度解析:从原理到实战的完整解决方案

在Windows Server运维与开发中,访问控制列表(ACL)和PATH环境变量是保障系统安全与程序正常运行的核心机制。ACL通过用户、组和安全标识符(SID)构成的权限模型,精确控制对文件、目录等资源的访问,遵循最小权限原则是安全架构的基石。PATH环境变量则决定了系统在何处查找可执行命令,其配置与管理直接影响脚本和应用的执行。理解这些基础原理的技术价值在于,能够系统性地解决生产环境中高频出现的“拒绝访问”和“命令找不到”等棘手问题,而非依赖危险的全权限授予。典型的应用场景包括IIS/ASP.NET应

weixin_33898876的博客 362

delphi 以系统权限运行程序的代码

program sysrun; uses Windows, SysUtils, tlhelp32, AccCtrl, AclAPI; function findprocess(TheProcName: string): DWORD; var isOK: Boolean; ProcessHandle: Thandle; ProcessStruct: TProces...

dkopg24406的专栏 556
上一篇: 服务器中以system权限启动UI进程
下一篇: 证书相关
xbgprogrammer
博客等级 码龄20年 36粉丝 106原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值