1 什么是内核对象
内核对象是内核分配的一段空间,如文件对象和进程对象等。可以用Windows提供的函数来创建相应的内核对象。创建成功后返回一个对象句柄,并且对象句柄值是进程相关的。程序不能直接操作内核对象,只能通过Windows提供的函数来控制。
1.1内核对象的使用计数
内核对象可以被多个进程同时使用,句柄值通常会不一样,但是引用的内容是同一块。内核对象的所有者是操作系统,而非进程,因此内核对象的存在时间通常会比进程的存在时间长。内核对象中有一个值用来保存当前使用该内核对象的进程数,这就是使用计数。这样可以确保在没有进程引用该对象时系统中不保留任何内核对象。内核对象由内核控制何时释放,而不是由调用它的进程,每一个内核对象的数据中都有一个进程引用计数,当某进行创建了一个内核对象时,该内核对象中的引用计数被置为1,之后要是有其它进程访问该内核对象时,引用计数加1,当所有访问内核对象的进程都释放,引用计数为0时,该内核对象由内核释放)。
1.2安全性
内核对象提供了安全描述符来限制操作权限,如文件映射内核对象的函数
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
参 数psa就是来控制访问权限的。当访问一个现有的文件映射内核对象时需要设定要对对象执行什么操作,如: HANDLE hFileMapping = OpenFileMapping(FILE_MAP_READ, FALSE, "MyFileMapping"),其中FILE_MAP_READ说明是对内核对象执行读操作,"MyFileMapping"是内核对象的名字。
注:我们可以通过对象的创建函数中是否有安全描述符来区分是内核对象还是一般的用户对象。
2 进程的内核对象句柄表
2.1创建内核对象
当 进程创建时,它会创建一个句柄表,用于存储内核对象的信息。当生成一个内核对象时,系统会将内核对象的地址以及其他信息存入句柄表,并返回一个句柄。这个 句柄是和内存相关的,即不同的进程访问同一个内核对象时,返回的句柄值是不同的。当访问内核对象时,可以通过句柄到句柄表中查找对应的内核地址。
注:当查看创建内核对象的函数返回值时,必须格外小心。特别要注意的是,当调用CreateFile函数失败时,返回值为INVALID_HANDLE_VALUE(值为-1)。其他的内核函数返回值为NULL。
2.2关闭内核对象
关 闭内核对象可以调用函数BOOL CloseHandle(HANDLE hobj)。系统会先判断句柄是否有效,如果有效,再判断计数是否为0,如果是的话,就将从内存中撤销该内核对象。不管成功与否,都将从句柄表中删除该对 象信息,该进程将不能再访问。如果忘记调用CloseHandle函数,进程运行时将有可能引起资源泄漏。但是进程终止时,系统浏览句柄表,并释放所有资 源。
#include <windows.h>
#include <stdio.h>
int main(void)
{
SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
sa.nLength =sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; //使得创建的句柄可继承
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
HANDLE h = CreateMutex(&sa, FALSE, "fuck");
if(GetLastError()== ERROR_ALREADY_EXISTS)
{
printf("run error\n");
system("pause");
return 0;
}
else{
//使得创建的新进程 RunAsDate.EXE 继承父进程中可以继承的内核句柄,如前面创建的互斥句柄 h
CreateProcess(NULL,"RunAsDate", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
printf("run\n");
system("pause");
return 0;
}
}
ps:运行上面的程序之后,会创建一个RunAsDate进程,把父进程关闭,再运行父进程会提示run error,表明我们的互斥对象已经被RunAsDate子进程继承,并且关闭父进程,对于互斥对象没有影响.