Introduction to the Windows security model

Source: Internet
Author: User

Some resources in the operating system can not be accessed directly by user code, such as thread processes, files, etc., these resources must be entered into the RING0 layer by the system-level code from the RING3 layer, and return some identity for the user program to use, generally call a function into the kernel, such a function called system call, While some are not directly trapped into the kernel, commonly called system Api,linux use system calls, and Windows encapsulates a series of APIs.

Windows objects with handles to Windows objects

For security, the operating system provides a protection mechanism that prevents users from manipulating certain resources, prevents users from paying too much attention to details, or causes a system crash due to improper operation. Windows encapsulates all of these resources into objects. Objects are a series of data structures that the operating system defines to maintain these resources. Object that we can easily associate with objects in an object-oriented programming language, which is a wrapper over some data and manipulating that data, and Windows is developed using object-oriented thinking, so we could think of objects in Windows as Object-oriented objects, Instead, Windows provides action functions for each object, usually with a handle as the first argument, which is a bit like the incoming this pointer in a class function. And the function of this object is the class function.
There are a total of three objects in Windows: GUI objects, GDI objects, kernel objects.

Handles in Windows

The operation of objects in Windows is done by a series of API functions provided by the system, which have a common feature, that is, with the handle handle as the first parameter, Windows takes a handle to uniquely identify each kernel object. In Windows, the handle is defined as follows:

typedefvoid * HANDLE

As can be seen from the above definition, this handle should be a pointer to the struct of the object. Since the memory is randomly allocated every time the program starts, the handle does not use hard-coded methods, and while copying the kernel pair image, it is not simple to copy its handle, the object copy has a special function, DuplicateHandle, the function prototype is as follows:

BOOL DuplicateHandle(  //源对象所在进程句柄  //源对象句柄  //目标对象所在进程句柄  //返回目标对象的句柄  //以何种权限复制  //复制的对象句柄是否可继承  //标记一些特殊的动作);

Here is an example code:

HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);    HANDLE hMutexDup, hThread;    DWORD dwThreadId;    DuplicateHandle(GetCurrentProcess(),hMutex,GetCurrentProcess(),&hMutexDup,         0,FALSE,DUPLICATE_SAME_ACCESS);

The code above copies a handle to a mutex object in this process.

Windows security Object Model


Kernel objects in Windows are manipulated by processes and threads, and objects are like a locked room, a process that wants to access an object, and some kind of manipulation of the object process must acquire the key to the object, and the thread is like the person who owns the key, and only the key is right to be accessible. This lock can be opened by a different key, which is stored in the ACE, but only if the information in the ACE matches the key of the access string. We generally refer to this key as the access string (Token)

Access string

Access strings mainly include: User ID, group ID, priority information, and other access information.
User id: Used to uniquely identify each user, as if a unique user ID is assigned to each user
Group ID: Unique identification ID of the group to which the user belongs
Priority: The general system assigns some permissions to each user and to the group to which it belongs, and sometimes these permissions are not sufficient, and this time it is necessary to add additional permissions through this priority information
When a user logs on to the Windows system, the user is assigned an access string with that user's information, and each securable object created by the user has a copy of the access string, and when the user opens a process that attempts to access a securable object, the system looks in the object's ACL to see if the user has a permission. This permission is required to perform this operation on the object.
The child process's access string is generally inherited from the parent process, but the child process can also create its own access string to overwrite the original access string.
The API used to manipulate the access string is mainly as follows:
OpenProcessToken//Open process access token
OpenThreadToken//Open thread's access token
adjusttokengroups//Changing the user group's access token
AdjustTokenPrivileges//Changing the access privileges of a token
GetTokenInformation//Get access token information
Settokeninformation//Set access token information

Here's a look at the use of function GetTokenInformation:

BOOL WINAPI GetTokenInformation(  __in          //访问字串的句柄  __in          //需要返回访问字串哪方面的信息  __out_opt     //用于接收返回信息的缓冲  __in          //缓冲的长度  __out         //实际所需的缓冲的长度);

This function returns information about the various aspects of the access token, which information is returned, which needs to be specified by the second parameter, which is an enumeration type that represents the information that needs to be obtained, and the information for each aspect defines the corresponding struct, which can be found in MSDN. In addition, this function supports two invocations, first passing in a null pointer and 0 length, so that the last parameter can be used to obtain the desired buffer size.

Sid

The user and user groups in the access string are uniquely identified (security Indentifer SID) with a secure identifier, and the SID in the system is unique. It is primarily used to identify these things:
1. Owners and user groups in the security descriptor
2. Visitors recognized by Ace
3. Accessing strings for users and groups
The length of the SID is mutable and should not be used when the SID data type is used, because at this time it is not known what the length is, and the pointer to it should be created and returned by the system, so a pointer to the SID is used when it is used. Here are some APIs for manipulating SIDs
ALLOCATEANDINITIALIZESID//Initialize a SID
Freesid//Releasing a SID
Copysid//Copy a SID
EQUALSID//Determine if two SIDs are equal
GETLENGTHSID//Gets the length of the SID
Isvalidsid//is a valid SID
Convertsidtostringsid//How to convert a SID to a string
Here is an example of using these APIs to get the SID of the System user group and the SID of the currently logged on user:

BOOL Getloginsid (HANDLE htoken, PSID *ppsid);The size of the//SID itself is unknowable, so you should pass in a 2-level pointer when you pass in the parameter, determined by the function itself .voidFreesid (PSID *ppsid);int_tmain (intARGC, tchar* argv[]) {setlocale (Lc_all,"CHS");    HANDLE hprocess = GetCurrentProcess ();    HANDLE htoken = NULL;    OpenProcessToken (hprocess, token_all_access, &htoken);    PSID PSID = NULL;    Getloginsid (Htoken, &psid);    LPTSTR pstringsid = NULL;    Convertsidtostringsid (PSid, &pstringsid); _tprintf (_t ("Current logged on user SID =%s\n"), PSTRINGSID); Freesid (&AMP;PSID);return 0;}    BOOL Getloginsid (HANDLE htoken, PSID *ppsid) {token_groups *PTG = NULL;    BOOL bsuccess = FALSE; DWORD dwlength =0;if(! GetTokenInformation (Htoken, tokengroups, PTG,0, &dwlength)) {if(Error_insufficient_buffer! = GetLastError ()) {Goto__CLEAN_UP; } PTG = (token_groups*) HeapAlloc (GetProcessHeap (), heap_zero_memory, dwlength);if(! GetTokenInformation (Htoken, TokenGroups, PTG, Dwlength, &dwlength)) {Goto__CLEAN_UP; }} _tprintf (_t ("%d sets of sid\n found"), Ptg->groupcount); LPTSTR pstringsid = NULL; for(inti =0; I < ptg->groupcount; i++) {Convertsidtostringsid (ptg->groups[i].        Sid, &pstringsid); _tprintf (_t ("\ t id =%d SID =%s"), I, PSTRINGSID);if((ptg->groups[i). Attributes & se_group_logon_id) = = se_group_logon_id) {_tprintf (_t ("This user is the currently logged on user"));             *ppsid = (PSID) HeapAlloc (GetProcessHeap (), heap_zero_memory, dwlength); Copysid (Dwlength, *ppsid, Ptg->groups[i].        SID); } _tprintf (_t ("\ n")); }__CLEAN_UP:if(PTG! = NULL) {HeapFree (GetProcessHeap (),0, PTG); }returnbsuccess;}voidFreesid (PSID *ppsid) {HeapFree (GetProcessHeap (),0, *ppsid); *ppsid = NULL;}

This example is an example of MSDN that first gets the access token for the process and then obtains the access token information through the function gettokeninformation. Gets the access string for the user group that the current user is in by passing in the tokengroups value. and save the information to the structure Token_groups finally passed (Ptg->groups[i]. Attributes & se_group_logon_id) = = se_group_logon_id An expression that determines whether the current SID is a logged-on user.

Priority

Precedence is a locally unique identifier (LUID) identified by a string
Priority is assigned by the system administrator to the corresponding user, generally cannot be programmed to elevate the user's priority, but sometimes even if the user has a certain priority, but it starts the program does not have the relevant priority. This can be done programmatically to elevate user process privileges.
The system has 3 values that represent a priority:
String name, the whole system is meaningful, called the global name, the string is not a readable string, the information displayed is not necessarily able to understand.
A readable name that is displayed to the user, such as: Changing the system time (can be viewed in Group Policy)
Each computer has a different local value;
Here are a few common priorities:

#define SE_DEBUG_NAME  TEXT("SeDebugPrivilege") //调试进程#define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") //装载驱动#define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") //锁定内存页面#define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") //关机

Here are a few priority functions
Lookupprivilegevalue//value of query priority
Lookupprivilegedisplayname//Query Priority output name
Lookupprivilegename//Name of the query priority
PrivilegeCheck//Priority information check
Here is a code to get user privileged information:

int_tmain (intARGC, TCHAR *argv[]) {setlocale (Lc_all,"CHS");    HANDLE htoken = NULL;    HANDLE hprocess = GetCurrentProcess (); OpenProcessToken (hprocess, Token_adjust_privileges |    Token_query, &htoken);    token_privileges* PTG = NULL; DWORD dwtgsize =0; TCHAR szname[255] = _t (""); TCHAR szdisplay[255] = _t (""); DWORD LanguageID = Getuserdefaultlangid ();if(! GetTokenInformation (Htoken, Tokenprivileges, PTG,0, &dwtgsize)) {if(Error_insufficient_buffer! = GetLastError ()) {_tprintf (_t ("Get token failed \ n"));return 0; } PTG = (token_privileges*) HeapAlloc (GetProcessHeap (), heap_zero_memory, dwtgsize);if(! GetTokenInformation (Htoken, Tokenprivileges, PTG, Dwtgsize, &dwtgsize)) {_tprintf (_t ("Failed to read token information \ n"));return 0; }} _tprintf (_t ("Privileged information for users: \ n")); for(inti =0; I < ptg->privilegecount; i++) {DWORD Dwname =sizeof(szName)/sizeof(TCHAR); DWORD Dwdisplay =sizeof(Szdisplay)/sizeof(TCHAR); Lookupprivilegename (NULL, &ptg->privileges[i].        Luid, SzName, &dwname);        Lookupprivilegedisplayname (NULL, SzName, Szdisplay, &dwdisplay, &languageid); _tprintf (_t ("\ t privilege name%s%s"), SzName, Szdisplay);if(Ptg->privileges[i]. Attributes & (se_privilege_enabled | Se_privilege_enabled_by_default)) {_tprintf (_t ("Privilege open \ n")); }Else{_tprintf (_t ("Privileged shutdown \ n")); }} heapfree (GetProcessHeap (),0, PTG);return 0;}

The following is the code for the process to extract power:

int_tmain (intARGC, TCHAR *argv[]) {HANDLE htoken = NULL;    HANDLE hprocess = GetCurrentProcess (); Setprivileges (Htoken, Se_tcb_name, TRUE);return 0;} BOOL Setprivileges (HANDLE htoken, LPTSTR lpprivilegesname, BOOL benableprivilege) {//Get token's privileged informationLUID uid = {0};    Lookupprivilegevalue (NULL, Lpprivilegesname, &uid); Token_privileges TP = {0}; Tp. Privilegecount =1; Tp. privileges[0]. Luid = UID;if(Benableprivilege) {TP. privileges[0].    Attributes = se_privilege_enabled; }Else{TP. privileges[0]. Attributes =0; } adjusttokenprivileges (Htoken, FALSE, &AMP;TP,sizeof(token_privileges), NULL, NULL);if(GetLastError () = = error_not_all_assigned) {_tprintf (_t ("Assignment of the specified privilege (%s) failed. \ n "), lpprivilegesname);returnFALSE; }returnTRUE;}
Security descriptor

The security descriptor typically contains information: Owner, primary group, optional access Control List (DACL), System access Control List (SACL)
Security descriptors are other information that begins with the securite_descriptor structure, followed by successive security descriptors

Access Control List

The Access Control List (ACL) is comprised primarily of multiple access control portals (access Controls Entries Aces). Aces are used to identify a user, group, or local group and each of the allowed access rights;

Creation of security descriptors

In a function that creates a secure access object, it is generally necessary to fill in a pointer to a security_attributes struct, either given a null value that has a default security attribute, or creates a security descriptor on its own and passes his pointer in.
There are several main steps to creating a security descriptor:
1. Use the function AllocateAndInitializeSid to create the user's SID. The function is defined as follows:

BOOL WINAPI AllocateAndInitializeSid(  __in          //用于表示该SID标识的颁发机构  __in          BYTE nSubAuthorityCount,  //SID有多少个子部分  __in          //第0个子部分  __in          DWORD dwSubAuthority1,  __in          DWORD dwSubAuthority2,  __in          DWORD dwSubAuthority3,  __in          DWORD dwSubAuthority4,  __in          DWORD dwSubAuthority5,  __in          DWORD dwSubAuthority6,  __in          DWORD dwSubAuthority7,  __out         //返回一个PSID的指针);

The SID consists primarily of one authority and one or more 32-bit unique rids that make up these rids by parameter dwSubAuthority0 to DwSubAuthority7 generation. The corresponding user SID has a fixed combination. I haven't found the exact user and SID definition.
2. Assigning access control permissions to the user SID is achieved primarily by populating the struct explicit_access members, which is defined as follows:

typedefstruct _EXPLICIT_ACCESS {      //制定用户权限    //用于表示允许、拒绝、审查特定用户的权限    //当前的权限是否可以继承    //这是一个访问托管} EXPLICIT_ACCESS,  *PEXPLICIT_ACCESS;

3. Use API SetEntriesInAcl to put the above structure into the ACL
4. Assign and initialize the Security_descriptor struct, the API used to initialize the struct is InitializeSecurityDescriptor
5. Add the SECURITY_DESCRIPTOR structure to the security descriptor, the structure of the security descriptor is: security_attributes
The following is a concrete example (this example is from MSDN):

Sid_identifier_authority Sidauthoritynt = security_world_sid_authority;    Sid_identifier_authority Sidauthorityword = security_nt_authority;    PSID peveryonesid = NULL;    PSID padminsid = NULL; Explicit_access ea[2] = {0}; PACL PACL = NULL;//Create SID for everyone userAllocateAndInitializeSid (&sidauthorityword,1, Security_world_rid,0,0,0,0,0,0,0, &peveryonesid); Psecurity_descriptor PSD = NULL;//define access control information for everyoneea[0].grfaccessmode = set_access;//used to indicate permission to allow, deny, and review specific usersea[0].grfaccesspermissions = Key_read;//Develop user rightsea[0].grfinheritance = FALSE; ea[0].    Trustee.trusteetype = Trustee_is_well_known_group; ea[0].    Trustee.trusteeform = Trustee_is_sid; ea[0]. Trustee.ptstrname = (LPTSTR) peveryonesid;//Create SID for Administor user groupAllocateAndInitializeSid (&sidauthoritynt,2, Security_builtin_domain_rid,domain_alias_rid_admins,0,0,0,0,0,0, &padminsid); ea[1].grfaccessmode = set_access; ea[1].grfaccesspermissions = key_all_access; ea[1].grfinheritance = FALSE; ea[1].    Trustee.trusteeform = Trustee_is_sid; ea[1].    Trustee.trusteetype = Trustee_is_group; ea[1]. Trustee.ptstrname = (LPTSTR) padminsid;//Add the above two SIDs to the ACLSetEntriesInAcl (2, EA, NULL, &pacl); PSD = (psecurity_descriptor) HeapAlloc (GetProcessHeap (),0, security_descriptor_min_length);//Initialize a SECURITY_DESCRIPTOR structureInitializeSecurityDescriptor (&AMP;PSD, security_descriptor_revision);//Add the SECURITY_DESCRIPTOR structure to the security descriptorSecurity_attributes sa = {0};    Sa.binherithandle = FALSE;    Sa.lpsecuritydescriptor = PSD; Sa.nlength =sizeof(security_attributes);    HKEY hksub = NULL; DWORD dwdisposition =0; RegCreateKeyEx (HKEY_CURRENT_USER, _t ("MyKey"),0, _t (""),0, Key_read | Key_write, &sa, &hksub, &dwdisposition);if(PEVERYONESID)    {Freesid (PEVERYONESID); }if(PADMINSID)    {Freesid (PADMINSID); }if(PACL)    {LocalFree (PACL); } heapfree (GetProcessHeap (),0, PSD);if(hksub)    {RegCloseKey (hksub); }

Introduction to the Windows security model

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.