Windows下如何創建低權限進程


   1.  前言

在使用 Sysinternals 出品的 Process Explorer 過程中,對 “Run as Limited User” 功能的實現方式頗感興趣,一番搜尋之下發現Mark大神在《Running as Limited User – the Easy Way》中對該功能的實現做了相關的闡述:

use the CreateRestrictedToken API to create a security context, called a token, that’s a stripped-down version of its own, removing administrative privileges and group membership. After generating a token that looks like one that Windows assigns to standard users Process Explorer calls CreateProcessAsUser to launch the target process with the new token.

使用 CreateRestrictedToken API來創建安全上下文,降低令牌(Token)的管理員權限和組成員資格,使其創建的令牌看起來像Windows賦予普通用戶時一樣,然后使用此令牌作為傳入參數調用CreateProcessAsUser來創建新的子進程。

Process Explorer queries the privileges assigned to the Users group and strips out all other privileges, including powerful ones like SeDebugPrivilege, SeLoadDriverPrivilege and SeRestorePrivilege.

查詢賦予用戶組的特權並從當前進程權限中剔除這些權限比如SeDebugPrivilege、SeLoadDriverPrivilege和SeRestorePrivilege。

 

剛好最近有個項目需要實現降低進程權限的功能,在一翻折騰下就將其實現了,下面將談談實現的歷程,如果紕漏之處,不吝指出。

   2.  知識背書

在列出代碼前需要了解一下一些實現原理,下面是一些相關的知識點,如果無耐心往下看,可以直接點擊這里跳到代碼實現處。

 

安全對象

有資格擁有安全描述符的對象如文件、管道、進程、進程間同步對象等。所有已命名的Windows對象都是安全的,那些未被命名的對象比如線程或進程對象也可以擁有安全描述符。

對於大多數的安全對象,當創建該對象時可以指定它的安全描述符。當一個安全對象被創建時,系統會對其賦予一個安全描述符,安全描述符包含由其創建者指定的安全信息,或者缺省的安全信息(如果沒有特意進行指定的話)。

  • ž   應用程序可以使特定的函數對已有的對象進行操作以來獲取和設置安全信息。
  • ž   每種類型的安全對象定義了它自身的訪問權限和自身映射的通用訪問權限。

更詳細內容見:https://msdn.microsoft.com/en-us/library/windows/desktop/aa379557(v=vs.85).aspx

 

安全描述符(security descriptor)

包含用於保護安全對象的安全信息。

安全描述符描述 對象的所有者(SIDs) 和 以下的訪問控制列表:

  • 自由訪問控制列表(DACL):指明特定用戶或組對該對象的訪問是允許或拒絕;
  • 安全訪問控制列表(SACL):控制系統審計如何訪問對象。

 

安全標識(Security Identifiers)

一定長度用來表示托管的唯一值。

安全標識主要運用於如下幾個方面:

  • 在安全描述符中定義對象的所有者和基本組;
  • 在訪問控制項中定義托管的權限是允許、拒絕或是審計;
  • 在訪問令牌中定義用戶和用戶所在的組。

 

訪問令牌

包含登錄用戶的信息。用來描述一個進程或線程的安全上下文的對象,令牌的信息包含關聯到進程或線程的賬號的標識和特權。

當一個用戶登錄時,系統對用戶的賬號和密碼進行認證,如果登錄成功,系統則創建一個訪問令牌,每個進程運行時都有一個訪問令牌代表當前的用戶,訪問令牌中的安全描述符指明當前用戶所屬的賬號和所屬的組賬號,令牌也包含一系列由用戶或用戶所在組進行維護的權限,在一個進程試圖進行訪問安全對象或執行系統管理員任務過程中需要權限時,系統通過這個令牌來確認關聯的用戶。

 

訪問控制列表及其訪問控制項

自由訪問控制列表(DACL)包含若干個訪問控制項(ACEs)。

約定的執行規則如下:

  • ž   如果對象沒有自由訪問控制列表(DACL),則任何用戶對其均有完全的訪問權限;
  • ž   如果對象擁有DACL,那么系統僅允許那些在訪問控制項(ACE)顯式指明的訪問權限;
  • ž   如果在訪問控制列表(DACL)中不存在訪問控制項(ACE),那么系統不允許任何用戶對其進行訪問;
  • ž   如果訪問控制列表中的訪問控制項對准許訪問的用戶或組數目有限,那么系統會隱式拒絕那些不在訪問控制項中的其他托管的訪問

需要注意的是訪問控制項的排序很重要。因為系統按照隊列的方式讀取訪問控制項,直到訪問被拒絕或允許。用戶的訪問拒絕ACE必須放在訪問允許ACE的前頭,否則當系統讀到對組的訪問允許ACE時,它會給當前限制的用戶賦予訪問的權限。系統在檢測到請求訪問被允許或拒絕后就不再往下檢查。

你可以通過標識允許訪問的ACE來控制對對象的訪問,你無需顯式地拒絕一個對象的訪問。

 

線程和安全對象間的交互

當一個線程想要使用一個安全對象時,系統在線程執行前會進行訪問審核,在訪問審核中,系統將線程訪問令牌中的安全信息與對象安全描述符中的安全信息進行比對。

訪問令牌中包含的安全標識(SIDs)可以指明與線程關聯的用戶,系統查看線程訪問令牌中用戶或組的SID,同時檢查對象的自由訪問控制列表(DACL),自由訪問控制列表(DACL)中包含存儲有指明對指定的用戶或組的訪問權限是允許或拒絕信息的訪問控制項(ACE),系統檢查每個訪問控制項(ACE)直至出現指明針對此線程(的用戶或組的SID)的訪問權限是允許還是拒絕的ACE,或者到最終都沒有對應的ACEs可以檢查。

 

(圖片出處:https://msdn.microsoft.com/en-us/library/windows/desktop/aa378890(v=vs.85).aspx

 

系統按照序列檢查每個ACE,查詢ACE中的托管與定義在線程中的托管(根據托管的SID)一致的ACE,直到如下的情況出現:

  • ž   表明訪問拒絕的ACE顯式拒絕在線程的訪問令牌中的一個托管的任何訪問權限;
  • ž   一個或多個表明訪問允許的ACEs顯式地為線程訪問令牌中的托管提供所有訪問權限;
  • ž   所有ACEs已經比對審核完但至少有一個請求訪問權限沒有顯式允許,這種情況下該訪問權限則被隱式拒絕。

一個訪問控制列表(ACL)可以有多個的訪問控制項(ACE)針對令牌的(同一個)SIDs,這種情況下每個ACE授予的訪問權限是可以進行累積疊加,比如,如果一個ACE對一個組允許讀的訪問權限,而另一個ACE對該組內的一個用戶允許寫的訪問權限,那么該用戶對於當前對象就擁有了讀和寫的訪問權限。

 

(圖片出處:https://msdn.microsoft.com/en-us/library/windows/desktop/aa446597(v=vs.85).aspx

如上圖所示,對於線程A,盡管在ACE@3中允許寫權限,但因為在ACE@1中已經顯式拒絕“Andrew”用戶的訪問權限,所以該安全對象對於線程A是不可訪問的;對於線程B,在ACE@2中顯式指明A組用戶可以有寫的權限,並且在ACE@3中允許任何用戶讀和執行的權限,所以線程B對這個安全對象擁有讀、寫以及執行的權限。

 

完整性級別

Windows完整性機制是對Windows安全架構的擴展,該完整性機制通過添加完整性等級到安全訪問令牌和添加強制性標記訪問控制項到安全描述符中的系統訪問控制列表(SACL)

進程在安全訪問令牌中定義完整性等級,IE在保護模式下的完整性等級為低,從開始菜單運行的應用程序的等級為中等,需要管理員權限並以管理員權限運行的應用程序的等級為高。

保護模式能夠有效地減少IE進程附帶的攻擊行為如篡改和摧毀數據、安裝惡意程序;相比其他程序,連接網絡的程序更容易遭受網絡的攻擊因為它們更可能從未知源地址下載未受信任的內容,通過降低完整性等級或限制對其的允許權限,可以減少篡改系統或污染用戶數據文件的風險。

在系統訪問控制列表(SACL)中有一個稱為強制標識的訪問控制項(ACE),該控制項的安全描述符定義完整性等級或允許訪問當前對象需要達到的等級,安全對象如果沒有該控制項則默認擁有中等的完整性等級;

即使用戶在自由訪問控制列表(DACL)中已經明確授予相應的寫權限,低等級的進程也不能獲取比其高等級的安全對象的寫權限,完整性等級檢驗在用戶訪問權限審查之前完成。

 

所有的文件和注冊表鍵在缺省下的完整性等級為中,而由低等完整性進程創建的安全對象,系統會自動地賦予其低等完整性強制標志,同樣,由低等完整性進程創建的子進程也是在低完整性等級下運行。

 

完整性訪問等級(IL)

系統權限

安全標識

 

System

System

S-1-16-16384

 

High

Administrative

 

S-1-16-12288

可安裝文件到Program Files文件夾、往敏感的注冊表中如HKEY_LOCAL_MACHINE寫數據

Medium

User

S-1-16-8192

創建和修改用戶文檔中的文件、往特定用戶的注冊表如HKEY_CURRENT_USER中寫數據

Low

Untrusted

S-1-16-4096

僅能往低等級位置寫數據如臨時網絡文件夾和注冊表

HKEY_CURRENT_USER\Software\LowRegistry

 

低完整性進程可以往用戶存檔文件下寫文件,通常為%USER PROFILE%\AppData\LocalLow,可以通過調用SHGetKnownFolderPath 函數並傳入FOLDERID_LocalAppDataLow參數來獲取完整的路徑名稱

SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, NULL, szPath, ARRAYSIZE(szPath));

同樣低完整性進程可以往指定的注冊表下創建和修改子鍵,該注冊表路徑通常為HKEY_CURRENT_USER\Software\AppDataLow

   3.  代碼實現

實現思路

  1. 創建新的普通用戶組和系統管理員的安全描述符標識;
  2. 獲取當前進程的令牌,並根據令牌句柄獲取當前進程所擁有的特權;
  3. 通過已創建的普通用戶組的安全描述符標識獲取普通用戶組所擁有的特權;
  4. 給當前進程令牌中的管理員安全描述符添加Deny-only屬性,以此達到避免新創建的進程以管理員作為其所有者;
  5. 從當前進程擁有的特權中剔除普通用戶組所沒有的特權;
  6. 從新的受限令牌中復制為模擬令牌;
  7. 將模擬令牌的完整性特權設為低級,以限制新創建的進程對普通文檔、可執行程序的寫、執行等訪問權限;

代碼實現

  1 void CreateRestrictedProcess() 
  2 {
  3     SECURITY_ATTRIBUTES sa;
  4     sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  5     sa.bInheritHandle = TRUE;
  6     sa.lpSecurityDescriptor = NULL;
  7 
  8     TCHAR szCmdLine[CMDLINE_SIZE] = {0};
  9     HANDLE hToken = NULL;
 10     HANDLE hNewToken = NULL;
 11     HANDLE hNewExToken = NULL;
 12 
 13     CHAR szIntegritySid[20] = "S-1-16-4096";
 14     PSID pIntegritySid = NULL;
 15     PSID pUserGroupSID = NULL;
 16     PSID pAdminSID = NULL;
 17 
 18     TOKEN_MANDATORY_LABEL tml = {0};
 19 
 20     PROCESS_INFORMATION pi;
 21     STARTUPINFO si;
 22 
 23     BOOL bSuc = FALSE;
 24     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
 25 
 26     ZeroMemory(&si, sizeof(STARTUPINFO));
 27     si.cb = sizeof(STARTUPINFO);
 28     GetStartupInfo(&si);
 29     DWORD fdwCreate = 0;
 30 
 31     __try
 32     {
 33 
 34         if (!OpenProcessToken(GetCurrentProcess(),
 35             //MAXIMUM_ALLOWED,
 36             TOKEN_DUPLICATE |
 37             TOKEN_ADJUST_DEFAULT |
 38             TOKEN_QUERY |
 39             TOKEN_ASSIGN_PRIMARY,
 40             &hToken))
 41         {
 42             char szMsg[DEFAULT_MSG_SIZE] = {0};
 43             Dbg("OpenProcessToken failed, GLE = %u.", GetLastError());
 44             __leave;
 45         }
 46 
 47         Dbg("Using RestrictedTokens way !!!");
 48         DWORD dwSize = 0;
 49         DWORD dwTokenInfoLength = 0;
 50         SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
 51         SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
 52         if(!AllocateAndInitializeSid(
 53             &SIDAuthNT, 
 54             0x2, 
 55             SECURITY_BUILTIN_DOMAIN_RID/*0×20*/, 
 56             DOMAIN_ALIAS_RID_USERS, 
 57             0, 0, 0, 0, 0, 0,
 58             &pUserGroupSID))
 59         {
 60             Dbg("AllocateAndInitializeSid for UserGroup Error %u", GetLastError());
 61             __leave;
 62         }
 63 
 64         // Create a SID for the BUILTIN\Administrators group.
 65         if(! AllocateAndInitializeSid( &SIDAuth, 2,
 66             SECURITY_BUILTIN_DOMAIN_RID,
 67             DOMAIN_ALIAS_RID_ADMINS,
 68             0, 0, 0, 0, 0, 0,
 69             &pAdminSID) ) 
 70         {
 71             Dbg("AllocateAndInitializeSid for AdminGroup Error %u", GetLastError());
 72             __leave;
 73         }
 74 
 75         SID_AND_ATTRIBUTES SidToDisable[1] = {0};
 76         SidToDisable[0].Sid = pAdminSID;
 77         SidToDisable[0].Attributes = 0;
 78 
 79         PTOKEN_PRIVILEGES pTokenPrivileges = NULL;
 80         PTOKEN_PRIVILEGES pTokenPrivilegesToDel = NULL;
 81         if(!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize))
 82         {
 83             if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
 84             {
 85                 pTokenPrivileges = (PTOKEN_PRIVILEGES)LocalAlloc(0, dwSize);
 86                 pTokenPrivilegesToDel = (PTOKEN_PRIVILEGES)LocalAlloc(0, dwSize);
 87                 if(pTokenPrivileges != NULL && pTokenPrivilegesToDel != NULL)
 88                 {
 89                     if(!GetTokenInformation(hToken, TokenPrivileges, pTokenPrivileges, dwSize, &dwSize))
 90                     {
 91                         Dbg("GetTokenInformation about TokenPrivileges failed GTE = %u.", GetLastError());
 92                         __leave;
 93                     }
 94                 }
 95                 else
 96                 {
 97                     char szMsg[DEFAULT_MSG_SIZE] = {0};
 98                     Dbg("LocalAlloc for pTokenPrivileges failed GTE = %u.", GetLastError());
 99                     __leave;
100                 }
101             }
102         }
103 
104         LUID_AND_ATTRIBUTES *pTokenLUID = pTokenPrivileges->Privileges;
105         Dbg("CurrentToken's TokenPrivileges Count: %u", pTokenPrivileges->PrivilegeCount);
106         DWORD dwLuidCount = 0;
107         PLUID pPrivilegeLuid = NULL;
108         if(!CTWProcHelper::GetPrivilegeLUIDWithSID(pUserGroupSID, &pPrivilegeLuid, &dwLuidCount))
109         {
110             Dbg("GetPrivilegeLUIDWithSID failed GTE = %u.", GetLastError());
111             if(pPrivilegeLuid)
112             {
113                 //HeapFree(GetProcessHeap(), 0, pPrivilegeLuid);
114                 LocalFree(pPrivilegeLuid);
115                 pPrivilegeLuid = NULL;
116             }
117             __leave;
118         }
119         Dbg("UserGroup's TokenPrivileges Count: %u", dwLuidCount);
120 
121         DWORD dwDelPrivilegeCount = 0;
122         for(DWORD dwIdx=0; dwIdx<(pTokenPrivileges->PrivilegeCount); dwIdx++)
123         {
124             BOOL bFound = FALSE;
125             DWORD dwJdx = 0;
126             for(; dwJdx<dwLuidCount; dwJdx++)
127             {
128                 //if(memcmp(&(pTokenLUID[dwIdx].Luid), &(pPrivilegeLuid[dwJdx]), sizeof(LUID)) == 0)
129                 if((pTokenLUID[dwIdx].Luid.HighPart == pPrivilegeLuid[dwJdx].HighPart)
130                     &&
131                     (pTokenLUID[dwIdx].Luid.LowPart == pPrivilegeLuid[dwJdx].LowPart))
132                 {
133                     bFound = TRUE;
134                     break;
135                 }
136             }
137             if(!bFound)
138             {
139                 char szPrivilegeName[MAX_PATH] = {0};
140                 DWORD dwNameSize = MAX_PATH;
141                 if(!LookupPrivilegeName(NULL, &(pTokenLUID[dwIdx].Luid), szPrivilegeName, &dwNameSize))
142                 {
143                     Dbg("LookupPrivilegeName failed GTE = %u.", GetLastError());
144                     //Dbg("NoFound[%u]: i=%u, j=%u", dwDelPrivilegeCount, dwIdx, dwJdx);
145                 }
146                 //else
147                 //{
148                 //    Dbg("NoFound[%u]: i=%u, j=%u -> %s", dwDelPrivilegeCount, dwIdx, dwJdx, szPrivilegeName);
149                 //}
150                 pTokenPrivilegesToDel->Privileges[dwDelPrivilegeCount++].Luid = pTokenLUID[dwIdx].Luid;
151             }
152         }
153         pTokenPrivilegesToDel->PrivilegeCount = dwDelPrivilegeCount;
154         Dbg("TokenPrivileges to delete Count: %u", dwDelPrivilegeCount);
155         if(pPrivilegeLuid)
156         {
157             //HeapFree(GetProcessHeap(), 0, pPrivilegeLuid);
158             LocalFree(pPrivilegeLuid);
159             pPrivilegeLuid = NULL;
160         }
161 
162         if(!CreateRestrictedToken(hToken,
163             0,
164             1, SidToDisable,
165             //0, NULL,
166             dwDelPrivilegeCount, pTokenPrivilegesToDel->Privileges,
167             0, NULL,
168             &hNewToken
169             ))
170         {
171             char szMsg[DEFAULT_MSG_SIZE] = {0};
172             Dbg("CreateRestrictedToken failed GTE = %u.", GetLastError());
173             __leave;
174         }
175 
176         // Duplicate the primary token of the current process.
177         if (!DuplicateTokenEx(hNewToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, 
178             TokenPrimary, &hNewExToken))
179         {
180             Dbg("DuplicateTokenEx failed GTE = %u.", GetLastError());
181             hNewExToken = NULL;
182             //__leave;
183         }
184         else
185         {
186             if (ConvertStringSidToSid(szIntegritySid, &pIntegritySid))
187             {
188                 tml.Label.Attributes = SE_GROUP_INTEGRITY;
189                 tml.Label.Sid = pIntegritySid;
190 
191                 // Set the process integrity level
192                 if (!SetTokenInformation(hNewExToken, TokenIntegrityLevel, &tml,
193                     sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid)))
194                 {
195                     Dbg("SetTokenInformation failed GTE = %u.", GetLastError());
196                     //__leave;
197                 }
198                 else
199                 {
200                     CloseHandle(hNewToken);
201                     hNewToken = hNewExToken;
202                     hNewExToken = NULL;
203                     Dbg("Assign Low Mandatory Level to New Token which used to CreateProcessAsUser.");
204                 }
205             }
206 
207         }
208 
209         if(!(bSuc = CreateProcessAsUser(hNewToken, NULL,
210             szCmdLine,     // command line 
211             NULL,          // TODO: process security attributes 
212             NULL,          // TODO: primary thread security attributes 
213             TRUE,         // handles are inherited ?? 
214             fdwCreate,     // creation flags
215             NULL,          // use parent's environment 
216             NULL,          // use parent's current directory 
217             &si,           // STARTUPINFO pointer 
218             &pi)))         // receives PROCESS_INFORMATION 
219         {
220             Dbg("CreateProcessAsUser failed GTE = %u.", GetLastError());
221             __leave;
222         }
223 
224         if(pTokenPrivileges)
225         {
226             LocalFree(pTokenPrivileges);
227         }
228         if(pTokenPrivilegesToDel)
229         {
230             LocalFree(pTokenPrivilegesToDel);
231         }
232     }
233     __finally
234     {
235         if(pIntegritySid)
236         {
237             LocalFree(pIntegritySid);
238         }
239         if(pUserGroupSID)
240         {
241             LocalFree(pUserGroupSID);
242         }
243         if(pAdminSID)
244         {
245             LocalFree(pAdminSID);
246         }
247         // 
248         // Close the access token.
249         // 
250         if (hToken)
251         {
252             CloseHandle(hToken);
253         }
254         if(hNewToken)
255         {
256             CloseHandle(hNewToken);
257         }
258         if(hNewExToken)
259         {
260             CloseHandle(hNewExToken);
261         }
262         if(!bSuc)
263         {
264             Dbg("Retry to Create process in normal way.");
265             //Create process.
266             bSuc = CreateProcess(NULL, 
267                 szCmdLine,     // command line 
268                 NULL,          // TODO: process security attributes 
269                 NULL,          // TODO: primary thread security attributes 
270                 TRUE,          // handles are inherited ?? 
271                 fdwCreate,     // creation flags
272                 NULL,          // use parent's environment 
273                 NULL,          // use parent's current directory 
274                 &si,           // STARTUPINFO pointer 
275                 &pi);          // receives PROCESS_INFORMATION 
276         }
277     }
278 }


其中 GetPrivilegeLUIDWithSID 函數的實現如下:

 1 BOOL GetPrivilegeLUIDWithSID(PSID pSID, PLUID *pLUID, PDWORD pDwCount)
 2 {
 3     LSA_OBJECT_ATTRIBUTES ObjectAttributes;
 4     NTSTATUS ntsResult;
 5     LSA_HANDLE lsahPolicyHandle;
 6 
 7     // Object attributes are reserved, so initialize to zeros.
 8     ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
 9 
10     // Get a handle to the Policy object.
11     ntsResult = LsaOpenPolicy(
12         NULL,    //Name of the target system.
13         &ObjectAttributes, //Object attributes.
14         POLICY_ALL_ACCESS, //Desired access permissions.
15         &lsahPolicyHandle  //Receives the policy handle.
16         );
17 
18     if (ntsResult != STATUS_SUCCESS)
19     {
20         printf("OpenPolicy failed returned %lu", LsaNtStatusToWinError(ntsResult));
21         return FALSE;
22     } 
23 
24     PLSA_UNICODE_STRING UserRights = NULL;
25     ULONG uRightCount;
26     ntsResult = LsaEnumerateAccountRights(lsahPolicyHandle, pSID, &UserRights, &uRightCount);
27     if (ntsResult != STATUS_SUCCESS)
28     {
29         printf("LsaEnumerateAccountRights failed returned %lu", LsaNtStatusToWinError(ntsResult));
30         LsaClose(lsahPolicyHandle);
31         return FALSE;
32     }
33     
34     printf("LsaEnumerateAccountRights returned Right count: %lu", uRightCount);
35 
36     (*pDwCount) = 0;
37     //pLUID = (PLUID)HeapAlloc(GetProcessHeap(), 0, uRightCount*sizeof(LUID));
38     (*pLUID) = (PLUID)LocalAlloc(LPTR, uRightCount*sizeof(LUID));
39     if((*pLUID) == NULL)
40     {
41         printf("HeapAlloc for PLUID failed returned %u", GetLastError());
42         LsaClose(lsahPolicyHandle);
43         return FALSE;
44     }
45 
46     for(ULONG uIdx=0; UserRights != NULL && uIdx<uRightCount; uIdx++)
47     {
48         int nLenOfMultiChars = WideCharToMultiByte(CP_ACP, 0, UserRights[uIdx].Buffer, UserRights[uIdx].Length,
49             NULL, 0, NULL, NULL);
50         PTSTR pMultiCharStr = (PTSTR)HeapAlloc(GetProcessHeap(), 0, nLenOfMultiChars*sizeof(char));
51         if(pMultiCharStr != NULL)
52         {
53             WideCharToMultiByte(CP_ACP, 0, UserRights[uIdx].Buffer, UserRights[uIdx].Length,
54                 pMultiCharStr, nLenOfMultiChars, NULL, NULL);
55             LUID luid;
56             if(!LookupPrivilegeValue(NULL, pMultiCharStr, &luid))
57             {
58                 printf("LookupPrivilegeValue about %s failed, GLE=%u.", pMultiCharStr, GetLastError());
59                 HeapFree(GetProcessHeap(), 0, pMultiCharStr);
60                 continue;
61             }
62             (*pLUID)[(*pDwCount)++] = luid;
63             HeapFree(GetProcessHeap(), 0, pMultiCharStr);
64         }
65     }
66     if((ntsResult = LsaFreeMemory(UserRights)) != STATUS_SUCCESS)
67     {
68         printf("LsaFreeMemory failed returned %lu", LsaNtStatusToWinError(ntsResult));
69     }
70     LsaClose(lsahPolicyHandle);
71     return TRUE;
72 }

 

 下圖是普通創建子進程效果(使用 Process Explorer 獲取的進程信息,下同),可以看到:

  • 該進程的所有者為 Administrators;
  • 強制性標識等級為:高
  • 部分特權為 Enabled

 

 通過執行上方的代碼對新進程的創建令牌進行一系列的限制后,可以看到:

  • 進程的所有者:添加了Deny屬性;
  • 強制性標識等級:低;
  • 部分特權被刪除。

 

 

  4.  擴展延伸

托管

一個托管可以是用戶賬號、組賬號或者登陸會話。是由訪問控制項(ACE)賦予的,每個訪問控制項(ACE)中都有一個安全標識(SID)用來表明特定的托管。

 

特權(Privilege)

特權用於對一個對象或服務的訪問控制,比自由訪問控制更為嚴格,一個系統管理員通過使用特權控制那些用戶可以操縱系統資源,一個應用程序在修改系統層級的資源需要使用到特權,比如修改系統時間和關閉系統。

 

更多內容請查看如下鏈接:

Windows Integrity Mechanism Design

Designing Applications to Run at a Low Integrity Level

Understanding and Working in Protected Mode Internet Explorer

Browsing the Web and Reading E-mail Safely as an Administrator(DropMyRight.exe的實現)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM