学好windows编程,理解内核对象还是至关重要的(●'◡'●)。闲话不多说,下面先来了解一下关于内核对象的知识:
内核对象(kernel object):内核对象是用于管理进程、线程和文件等诸多种类的大量资源。
内核对象的分类:进程对象,线程对象,互斥量(mutex)对象,信号量(semaphore)对象,事件对象,作业对象,文件对象,文件映射对象,管道(pipe)对象,邮件槽(mailslot)对象,I/O完成端口对象,线程池工厂(thread pool worker factory)对象,令牌(access token)对象、可等待的计时器(waitable timer)对象等。
内核对象的特性:
每个内核对象都只是一个内存块,它由操作系统分配,并只能由操作系统内核访问,这个内存块是一个数据结构,其成员维护着与对象相关的信息。少数成员(安全描述符和使用计数等)是所有对象都有的,但其他大多数成员都是不同类型的对象特有的。例如,进程对象有一个ID,一个基本的优先级和一个退出代码;而文件对象有一个字节偏移量(byte offset)、一个共享模式和一个打开模式。
由于内核对象的数据结构只能被操作系统访问,故应用程序不能在内存中定位这些数据结构并更改其内容;
当调用一个可以创建内核对象的函数后,该函数会返回一个用于标识该对象的句柄。如果将该句柄值传递给另一个进程中的一个线程,那么这另一个进程使用你的进程的句柄值所作的调用就会失败。如果想在多个进程*享内核对象,要通过一定的机制(如对象句柄的继承性,命名对象,复制对象句柄)。
下图所示是一个可以查看一个包含所有内核对象类型的列表的软件(WinObj)界面。有兴趣的可以下载学习一下,加深一下对内核对象的认识。
内核对象的安全性:内核对象可以用一个安全描述符(security descriptor,SD)来保护。用于创建内核对象的所有函数几乎都指向一个SECURITY_ATTRIBUTES结构的指针作为参数:如下面的
CreateFileMapping(
HHANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSiizelow,
PCTSTR pszName
);
大多数应用程序只是为这个参数传入NULL,这样创建的内核对象具有默认的安全性----具体包括哪些默认的安全性,要取决于当前进程的安全令牌(security token)。但是也可以分配一个SECURITY_ATTRIBUTES结构,并对它进行初始化,再将它的地址传给这个参数。SECURITY_ATTRIBUTES结构体如下所示:
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES;
虽然这个结构称为SECURITY_ATTRIBUTES,但它实际上只包含一个和安全性有关的成员,即lpSecurityDescriptor。如果相对创建的内核对象加以访问限制,就必须创建一个安全描述符,然后按下面所示初始化其结构:
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecrityDeccriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFileMApping = CreateFileMapping(INVALID_HANDLE_VALUE,
&sa,
P0AGE_READWRITE,
0,
1024,
TEXT(“MyFileMapping”));
若想访问一个现有的文件映射对象,以便从中读取数据,可以如下下述方式调用:
HANDLE hFileMapping = OpenFileMapping(
FILE_MAP_READ,FALSE,
FALSE,
TEXT(“MyFileMapping”));
若想判断一个对象是不是内核对象,最简单的方式是查看创建这个对象的函数。几乎所有创建内核对象的函数都有一个指定安全属性信息的参数,就像上述的CreateFileMapping函数一样。相反,用于创建用户对象或GDI对象的函数都没有PSECURITY_ATTRIBUTES参数。如下所示的CreateIcon函数
HICON CreateIcon(
HINSTANCE hinst,
int nWidth,
int nHight,
BYTE cPlanes,
BYTE cBitsPixel,
CONST BYTE *pbANDbits,
CONST BYTE *pbXORbits);
ps:像菜单、窗口、鼠标光标、画刷和字体这样的对象属于用户对象或GDI(Graphical Device Interface)对象。
部分创建内核对象的函数:
HANDLE CraeateThread (
PSECURITY_ATTRIBUTES psa,
size_t dwStackSize,
LPTHREAD_START_ROUTINE pfnstartAddress,
PVOID pvParam,
DWORD dwCreatinFlags,
PDWORD pdwThread );
HANDLE CraeateFile (
PCTSTR pszFileName
DWORD dwDesiredAccess,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD daCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile );
HANDLE CreateSemaphore (
PSECURITY_ATTRIBUTES psa,
LONG lInitialCount,
LONG lMaxiumumCount,
PCTSTR pszName);
……
结束内核对象,需调用:BOOL CloseHandle(HANDLE hobject);