参考URL:
https://blog.csdn.net/u011801161/article/details/45567289
http://blog.nsfocus.net/analysis-windows-access-authority-inspection-mechanism/
https://blog.csdn.net/eggfly178/article/details/41773601
一 Windows访问控制概述:
Windows访问控制中最主要的部分:访问令牌(Access Token)和安全描述符(Security Descriptor),window通过查看访问者AT与被访问对象SD中的内容来确定访问者是否能访问对象。
Windows访问控制概念介绍:
① SID:Secure Identifier(安全标识符),每个用户和账户组都有一个唯一的SID(通常情况下唯一)。它是标识用户、用户组和计算机账户唯一的号码,由计算机名、当前时间、当前用户态线程的CPU耗费时间三个参数来确定。
② Access Token:与特定的windows账户关联,账户环境下启动的所有进程都会获得该令牌的副本,进程中的线程默认获得这个令牌。由关联账户的SID、当前登录账户所属组的SID列表、受限制的SID列表、当前登录账户与所属组的Privilege列表组成。
③ Security Descriptor:安全描述符,与被访问对象关联。由对象所有者的SID、属组SID、DACL、SACL组成。DACL(随机访问控制列表)是SD最重要的一部分,描述允许或拒绝特定用户或组的某些访问权限,它包含零个或多个访问控制实体(ACE,Access Control Entry)。
④ ACE:访问控制实体,用于指定特定用户/组的访问权限,由SID、SIZE、Type、Access Mask、Inheritance/Audit Flags组成。
Windows访问控制流程图:
当一个线程尝试去访问一个对象时,系统会检查线程持有的令牌以及被访问对象的安全描述符中的DACL。
如果安全描述符中不存在DACL,则系统会允许线程进行访问。如果存在DACL,系统会顺序遍历DACL中的每个ACE,检查ACE中的SID在线程的令牌中是否存在。以访问者中的User SID或Group SID作为关键字查询被访问对象中的DACL。顺序:先查询类型为DENY的ACE,若命中且权限符合则访问拒绝;未命中再在ALLOWED类型的ACE中查询,若命中且类型符合则可以访问;以上两步后还没命中那么访问拒绝。
此外, SACL是系统访问控制列表,是用来做审计用的,一般不用关心。
二 一个修改特定对象DACL
以下代码实现了以默认权限创建一个event内核对象(默认权限下Administrators组没有修改权限), 然后给该对象的Administrators组添加修改权限的功能. 注意: 以下代码必须在system权限下运行(就是服务进程里边), 只展示了核心代码部分, DACL的修改貌似只能以整个安全描述符为单位进行修改, 不知道是不是我孤陋寡闻的原因
1 #include <windows.h> 2 #include <aclapi.h> 3 #include <sddl.h> 4 bool MyCreateEvent() 5 { 6 HANDLE g_HEStop =NULL; 7 bool result = false; 8 DWORD ret = 0; 9 PACL pDACL11 = NULL; 10 PSECURITY_DESCRIPTOR pSE = NULL; 11 PSID pAdminSID = NULL; 12 wchar_t *domainName = NULL; 13 do 14 { 15 //get sid 16 LogToFile(L"find administrators sid"); 17 DWORD domainSize = 0; 18 DWORD sidSize = 0; 19 SID_NAME_USE sidType = SidTypeGroup; 20 ret = LookupAccountNameW(NULL, L"Administrators", NULL, &sidSize, NULL, &domainSize, &sidType); 21 if (!(ret == 0 && GetLastError() ==ERROR_INSUFFICIENT_BUFFER)) 22 { 23 24 LogErr(L"LookupAccountName err1", GetLastError()); 25 break; 26 } 27 std::wstring str = std::to_wstring(sidSize); 28 str += L" "; 29 str += std::to_wstring(domainSize); 30 LogToFile(str.c_str()); 31 32 pAdminSID = new char[sidSize]; 33 domainName = new wchar_t[domainSize]; 34 if (!pAdminSID || !domainName) 35 { 36 LogToFile(L"alloc buffer err"); 37 break; 38 } 39 40 ret = LookupAccountNameW(NULL, L"Administrators", pAdminSID, &sidSize, domainName, &domainSize, &sidType); 41 if (ret == 0) 42 { 43 LogErr(L"LookupAccountName err2", GetLastError()); 44 break; 45 } 46 else 47 { 48 LogErr(L"sidType", sidType); 49 LPWSTR str = NULL; 50 if (ConvertSidToStringSidW(pAdminSID, &str)) 51 { 52 LogToFile(str); 53 LocalFree(str); 54 str = NULL; 55 } 56 } 57 58 // create event 59 LogToFile(L"create event"); 60 g_HEStop = CreateEventW(NULL, TRUE, FALSE, STOP_EVENT_NAME); 61 if (!g_HEStop) 62 { 63 LogToFile(L"create event err"); 64 break; 65 } 66 67 // modify dacl 68 LogToFile(L"modify dacl"); 69 ret = GetSecurityInfo(g_HEStop, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &pDACL11, NULL, &pSE); 70 if (ret != ERROR_SUCCESS) 71 { 72 LogErr(L"get Dacl err",ret); 73 break; 74 } 75 76 ACL_SIZE_INFORMATION aclSInfo; 77 ret = GetAclInformation(pDACL11, &aclSInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation); 78 if (ret == 0) 79 { 80 LogErr(L"get acl info err", GetLastError()); 81 break; 82 } 83 84 LogToFile(L"enum ace"); 85 86 PACE_HEADER aceHeader = NULL; 87 bool find = false; 88 PSID pSidInAce = NULL; 89 LPWSTR StringSid = NULL; 90 for (DWORD index = 0; index < aclSInfo.AceCount; ++index) 91 { 92 ret = GetAce(pDACL11, index, (LPVOID*)&aceHeader); 93 if (ret) 94 { 95 // 目前来说各中ace的结构是一样的, 可以这么写, 将来可能会变 96 pSidInAce = (PSID)((DWORD)aceHeader + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK)); 97 if (ConvertSidToStringSidW(pSidInAce, &StringSid)) 98 { 99 LogToFile(StringSid); 100 LocalFree(StringSid); 101 StringSid = NULL; 102 } 103 else 104 LogErr(L"ConvertSidToStringSidW err: ", GetLastError()); 105 106 if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) 107 { 108 PACCESS_ALLOWED_ACE aceAl = (PACCESS_ALLOWED_ACE)aceHeader; 109 if (EqualSid(pSidInAce, pAdminSID)) 110 { 111 aceAl->Mask |= GENERIC_WRITE; 112 find = true; 113 break; 114 } 115 } 116 } 117 } 118 if (find) 119 { 120 ret = SetSecurityInfo(g_HEStop, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pDACL11, NULL); 121 if (ret == ERROR_SUCCESS) 122 result = true; 123 else 124 LogErr(L"SetSecurityInfo err: ", ret); 125 } 126 else 127 LogToFile(L"not find allow ace"); 128 } while (false); 129 if (pAdminSID) 130 delete[] pAdminSID; 131 if (domainName) 132 delete[] domainName; 133 if (pSE) 134 LocalFree(pSE); 135 136 if (!result && IsStopEventValid()) 137 CloseHandle(g_HEStop); 138 return result; 139 }