Core summary of Windows core programming (chapter III kernel objects) (2018.6.2)

Source: Internet
Author: User

Learning Goals

The third chapter of the concept of kernel objects is more abstract, it is difficult to understand, I constantly surf the internet to find information and see the video, just basic understanding of the concept and characteristics of the kernel objects, in fact, the whole book to my feeling is that the complete code is too few, there is not much practice of code on the content of the implementation, and the book There is too much knowledge that we don't know, and this knowledge is superfluous for the main content of this chapter, so it is very difficult for us to understand. In order to learn this chapter better, I added some auxiliary content. The learning objectives of this chapter:
1.Windows session and security mechanisms
2. What is a kernel object?
3. Using the count and security descriptors
4. Kernel Object Handle Table
5. Creating Kernel objects
6. Close the Kernel object
7. Sharing kernel objects across process boundaries-using object handle inheritance
8. Sharing kernel objects across process boundaries-naming objects
9. Prevent multiple instances of an application from running
10. Terminal Services namespaces and proprietary namespaces
11. Combining proprietary namespaces to prevent multiple instances of an application from running
12. Sharing kernel objects across process boundaries-copy object handles

Windows session and security mechanisms

At the beginning of the Vista system, Windows established the session concept. After the Windows system starts, it establishes Session0 (session 0) and loads the public service into Session0 (session 0), for example: some modules that are closely related to hardware (such as interrupt handlers, etc.), drivers for various common devices (sound card drivers, printer drivers, Graphics drivers) and high-frequency modules (such as clock management, process scheduling, and some basic operations common to many modules), are placed in memory, called the operating system kernel. After the system starts, the first user logs on to the system and builds up the Session1 (Session 1), so when you run all the Apps, Warcraft, Rook, Jedi, these applications are running under Session1 (Session 1). Running multiple programs under a session involves multitasking, such as multiple processes executing concurrently, and multitasking through process management isolation. When another user logs on remotely, the Session2 (Session 2) is established, and Session2 (Session 2) has a unique application---process. If a user logs on to the system sequentially, a new session is established sequentially, followed by a unique application---process. With this design, the core components of the system can be better isolated from malicious software that is inadvertently initiated by the user. The process of different users is isolated through the session, this is the process of multiuser, multi-users rely on the session to isolate the user to achieve mutual independence, non-impact. This leads to the concept of session sessions, and it is necessary to consider security mechanism issues. If Zhang San landed the system, set up a session 1, and then the system will give a 31 session token, the token contains its user information, as well as the user access permissions, what groups and other information. In Session 1, Zhang San run a program, the system will assign a token to the program, the program token is inherited from the session established by the session token, and then the program wants to open a file (Kernel object), this file (kernel object) will have a security descriptor (SD), Depending on the program token and the security descriptor of the file, the security descriptor contains the user who was created, which users or groups allowed access to the object, and which users or groups denied access to the object. After the match finds that the user is in the Access denied list of the security descriptor, the program cannot open the file, otherwise it can open the file.

What is a kernel object?

In the system and in the applications we write, kernel objects are used to manage a wide variety of resources, such as processes, threads, and files. As a Windows developer, we often create, open, and process kernel objects. When we start an application in a session, when the application loads into memory, a process is generated (this is a keynote process). Each process corresponds to a virtual address space, which is then converted by the memory manager to the virtual address space and the physical address space. The virtual memory space of the process is divided into the kernel layer and the application layer, each kernel object is actually a block of memory, this memory block is located in the kernel address space of the operating system (kernel layer), and the user's application runs on the application layer, note: Here is the description in the virtual address space, and then map to the real physical address space Kernel objects are assigned by the operating system kernel and can only be accessed by the operating system kernel. Therefore, the application cannot manipulate the kernel object directly, and it needs to operate with a function given by the Windows system. Each kernel object has a specific creation function and an operation function. So, when a kernel object function is called in a keynote session, the kernel object (memory block) is actually mapped to the operating system kernel area of the physical memory in the kernel layer of the virtual memory space of the process. Kernel Object This block of memory is a data structure whose members maintain information related to the object.

Using count and security descriptors

As we said in the last section, the kernel object is actually a data structure, and the structure of the kernel object is divided into two parts: the common part (Security descriptor (DESCRIPTOR,SD), usage count), and the specific part. The specific part, for example: The process kernel object has a process ID, a basic priority, and an exit code. Use count is a data member of each kernel object, when a kernel object is created, the usage count is set to 1, when another process obtains access to the existing kernel object, the usage count is incremented, and after the process terminates running, The operating system kernel will automatically decrement the usage count of all kernel objects that are still open by this process, and if the kernel object's usage count is 0, the kernel object will be destroyed by the operating system kernel. The security descriptor describes who owns the kernel object, which groups and users are allowed to access or use this object, and which groups and users are denied access or use of this object. Almost all functions used to create a kernel object have a pointer to the SECURITY_ATTRIBUTES structure as a parameter. The signature of this structure is given below:

        typedef struct _SECURITY_ATTRIBUTES {            DWORD  nLength;//结构的大小            LPVOID lpSecurityDescriptor;//安全描述符             BOOL   bInheritHandle;//表示所创建的内核对象是否可被继承,一般是具有父子关系的进程才可以继承            } SECURITY_ATTRIBUTES;

If you want to restrict access to the kernel objects that we create, you must create a security descriptor. In Windows core programming there is the concept of this kernel object, while Windows programming also has GDI objects such as brushes, windows, brushes, bitmaps. Concept, we can know only kernel objects at the kernel layer, and user objects (for example: GDI objects) at the application layer. So how do we tell if an object is a kernel object or a non-kernel object? We have just learned the security descriptor, and each kernel object's creation function basically has a security_attributes attribute as a parameter, so it's obvious. We can look at the function that creates the object, if the function that created the object has a security descriptor parameter, then the object created by this function is the kernel object.

Kernel Object Handle Table

When a process is initialized, the system assigns a kernel object handle table to the process. Shows a handle table for a process. You can see that the kernel object handle table is an array of data structures, each containing an index, a pointer to a memory block of a kernel object, an access mask, and some flags (for example, whether a flag that can be inherited is specified when the kernel object is created).

Creating Kernel objects

When a process is initialized for the first time, its kernel object handle table is empty. Then, when a thread in the process invokes a function that creates a kernel object, such as CreateFileMapping, the operating system kernel allocates a block of memory for the object and initializes it. At this point, the operating system kernel scans the handle table of the process to find an empty entry. The operating system kernel finds the structure on the index 1 location and initializes it. The pointer member is set to the memory address of the kernel object's data structure, the access mask is set to full access, and the individual flags are set. I enumerate the following parts to create a function signature for a kernel object:

HANDLE CreateThread(   PSECURITY_ATTRIBUTES psa,   size_t dwStackSize,   LPTHREAD_START_ROUTINE pfnStartAddress,   PVOID pvParam,   DWORD dwCreationFlags,   PDWORD pdwThreadId);HANDLE CreateFile(   PCTSTR pszFileName,   DWORD dwDesiredAccess,   DWORD dwShareMode,   PSECURITY_ATTRIBUTES psa,   DWORD dwCreationDisposition,   DWORD dwFlagsAndAttributes,   HANDLE hTemplateFile);HANDLE CreateFileMapping(   HANDLE hFile,   PSECURITY_ATTRIBUTES psa,   DWORD flProtect,   DWORD dwMaximumSizeHigh,   DWORD dwMaximumSizeLow,   PCTSTR pszName);HANDLE CreateSemaphore(   PSECURITY_ATTRIBUTES psa,   LONG lInitialCount,   LONG lMaximumCount,   PCTSTR pszName);

We can see these function signatures that create kernel objects, parameters have a security_attributes structure parameter, and then return a kernel object handle, which is actually used as the index of the kernel object handle table, so these handles are related to the current process, cannot be used by other processes, if we are really using it in other processes, then the actual reference is only to the kernel object in the same index in the handle table of that process----only the index value is the same. To get the actual index value of the handle table, the kernel object handle value should be divided by 4 to get the index value.

Close the Kernel object

Regardless of how the kernel object is created, it is indicated to the system that the operation of the object will be terminated by calling the CloseHandle function, and the signature of the function is given below:

HRESULT CloseHandle(    HANDLE hHandle  );

Call this function, inside the function will first check the handle table of the keynote process, to see if the keynote process has access to the kernel object handle. If the kernel object handle is valid, the system obtains the address of the kernel object's data structure and decrements the usage count member in the structure. If the use count becomes 0, the kernel object is destroyed and the corresponding record entry in the corresponding kernel object handle table is cleared, and if the use count is decremented to 0, indicating that the kernel object is still being used by other processes, then only the corresponding record entry in the corresponding kernel object handle table is cleared and the kernel object is not destroyed. With so much to say, is there a way to see how many kernel objects the process has? Of course, Microsoft provides a gadget: Process Explorer, and the diagram below shows my own application, which creates a mutex kernel object called "YDM", and I will close the kernel object. This line of mutant type below is the mutex kernel object that I created internally.

Sharing kernel objects across process boundaries-using object handles for inheritance

There is a kernel handle table in each process, which means that the same kernel object may not have the same kernel object handle value in a different process. However, the role of kernel objects is largely due to the ability to share kernel objects across process boundaries through common access between processes. So how do we implement sharing the same kernel object between different processes? Windows core Programming This book provides us with three ways to implement this feature. This section first uses object handle inheritance to implement shared kernel objects across process boundaries.
Object handles can be inherited only if there is a parent-child relationship between the processes. In order for the child process to inherit the kernel object handle table of the parent process, the following steps must be performed:
1. When a parent process creates a kernel object, the parent process must indicate to the system that it expects the handle of the object to be inheritable. Note that the inheritance referred to here refers to inheriting kernel object handles, not kernel objects. In order to create a handle to a kernel object that can be inherited, the parent process must allocate and initialize a security_attributes structure and pass the address of the structure to the specific create* to create the kernel object function. Here's a stark example:

SECURITY_ATTRIBUTES sa;//安全属性结构sa.nLength=sizeof(sa);//结构大小sa.lpSecurityDescriptor=NULL;//安全描述符sa.bInheritHandle=TRUE;//指定内核对象是否可被继承HANDLE hMutex=CreateMutex(&sa,FALSE,NULL);//创建一个互斥量内核对象

We all know that each record entry in the Kernel object handle table contains an index, an address that points to the memory block of the kernel object, an access mask, and a flag, where the flag refers to whether it can be inherited. If you pass NULL as the Psecurity_attributes parameter when you create the kernel object, the returned handle will be non-inheritable, the flag will be set to 0, and if the bInheritHandle member is set to true, the flag will be set to 1.
2. The parent process generates a child process, which is done by calling the CreateProcess function within the keynote process. The following is a function signature for CreateProcess:

  BOOL WINAPI CreateProcess (_in_opt_ lpctstr lpapplicationname, _inout_opt_ LPTSTR lpCommandLine, _in_opt_ lpsecurity_attributes lpprocessattributes, _in_opt_ lpsecurity_attributes lpThreadAtt     Ributes, _in_ BOOL binherithandles, _in_ DWORD dwcreationflags, _in_opt_          LPVOID lpenvironment, _in_opt_ lpctstr lpcurrentdirectory, _in_ lpstartupinfo Lpstartupinfo, _out_ lpprocess_information lpprocessinformation);  

Note that if set to true, the child process inherits the value of the "inheritable kernel object handle" of the parent process, note that if it is a "non-inheritable kernel object handle" of the parent process, the child process will not inherit the binherithandles. I said each process has a kernel object handle table, and the child process is no exception. The system allocates a new, blank kernel object handle table after the child process is created. The overall execution process is as follows: The system will first traverse the parent process's kernel object handle table, check every record entry, and any item containing a valid "inheritable kernel object handle" will be completely copied to the child process's kernel object handle table, in the child process's kernel object handle table, The location of the copied item is exactly the same as it would be in the parent process handle table, which means that the kernel object handle values that are identified for each kernel object are identical in both the parent and child processes. In addition to copying the record entries for the kernel handle table, the system also increments the usage count of the kernel objects, since two processes are now using this kernel object. Remember one important point: the inheritance of kernel object handles only occurs when the child process is generated, and if the parent process later creates a new kernel object and also sets their handle as an inheritable handle, the running child process does not inherit the new handle. The first is to create an inheritable kernel object for the parent process, the parent process calls the CreateProcess function to create a child process, and then the system automatically copies the kernel object handle that the parent process can inherit to the child process's kernel object handle table, and then creates the second child process, which still remains the case. But I want to inherit this kernel object from the parent process when I create a second child process. Simply put, we want to control which child processes inherit the kernel object handle, and you can call the Sethandleinformation function to change the inheritance flag of the kernel object handle that has already been created. Then we can accomplish this by calling the Sethandleinformation function to close the inheritance flag of the kernel object before calling the CreateProcess function to generate the second child process. This function is signed as follows:

BOOL SetHandleInformation(   HANDLE hObject,//标识了一个有效的内核对象句柄,为什么有效?因为还是需要主调进程有访问权限。   DWORD dwMask,//告诉函数我们想更改哪个或者哪些标志   DWORD dwFlags);//指出把标志设为什么

Two values for parameter 2,dwmask are given below:

HANDLE_FLAG_INHERIT 0x00000001  If this flag is set, a child process created with the bInheritHandles parameter of CreateProcess set to TRUE will inherit the object handle. HANDLE_FLAG_PROTECT_FROM_CLOSE  0x00000002  

1. If you want to open an inheritance flag for a kernel object handle, you can write:

SetHandleInformation(hObj,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);

2. To turn off this flag, you can write:

SetHandleInformation(hObj,HANDLE_FLAG_INHERIT,0);

The 3.HANDLE_FLAG_PROTECT_FROM_CLOSE flag is to tell the system not to allow the kernel object handle to be closed:

SetHandleInformation(hObj,HANDLE_FLAG_PROTECT_FROM_CLOSE,HANDLE_FLAG_PROTECT_FROM_CLOSE);//如果在这个函数之后调用CloseHandle关闭这个句柄就会报错

4. If you need to tell the system to allow the kernel object handle to be closed, we can write:

SetHandleInformation(hObj,HANDLE_FLAG_PROTECT_FROM_CLOSE,0);//这时候在这个函数调用之后调用CloseHandle函数关闭内核对象句柄不会报错,成功关闭

5. We can get the current flag for the specified kernel object handle through the Gethandleinformation function. If you want to check whether a kernel object handle can be inherited, we can write:

DWORD dwFlags;GetHandleInformation(hObj,&dwFlags);BOOL fHandleIsInheritable=(0!=(dwFlags & HANDLE_FLAG_INHERIT));

Later content later added ...

Core summary of Windows core programming (chapter III kernel objects) (2018.6.2)

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.