zoukankan      html  css  js  c++  java
  • Windows核心编程 第3章 内核对象

    3.1 什么是内核对象

    内核对象就是内核中的一块内存,是一个结构,并且只能由内核对象访问,应用程序只能通过调用Windows提供的函数来操作内核对象。每个内核对象都有相同的部分比如安全属性和使用计数器。

    3.1.1 内核对象的使用计数

    内核对象中的使用计数和进程无关,当进程第一次创建某个内核对象时候使用计数变为1,当另一个进程也调用此内核对象时计数变为2。当进程释放时或者关闭内核对象时(CloseHandle),内核的使用计数减去1,如果使用计数不为0的话,内核不会释放此内核对象。

    3.2.2 安全性

    内核对象能够得到安全描述符的保护,安全描述符定义了谁能够创建,访问和使用该对象,一般在服务器代码中使用,客户端可以忽略。

    所有创建内核对象的函数的参数都有一个指向SECURITY_ATTRIBUTES结构的指针。

    typedef struct _SECURITY_ATTRIBUTES {
        DWORD nLength;
        LPVOID lpSecurityDescriptor;
        BOOL bInheritHandle;
    } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

    只有

    lpSecurityDescriptor

    成员和安全属性有关。一般此参数传递NULL,表示默认的安全描述。如果需要:

    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = FALSE;
    HANDLE h = CreateMutex(&sa, FALSE, "XI");
    其余进程可用用OpenMutex函数打开,如果权限可以就返回句柄,如果失败返回NULL,GetLastError被设置为ERROR_ACCESS_DENIED。
    Windows除了内核对象之外还有GDI和用户对象,区分它们的简单办法就是,创建函数中带有安全描述符参数的就是内核对象。
     
    3.2 进程的内核对象句柄表

    索引                         内核对象内存块得指针                             访问屏蔽(标志位的DWORD)                      标志(标志位的DWORD)


    1                               0x????????                                                0x????????                                                        0x????????
    2                               0x????????                                                0x????????                                                        0x????????
    …                               …                                                               …                                                                       …

    3.2.1 创建内核对象

    调用Create&函数族来创建相应的内核对象,返回的是内核对象的句柄(也有个说法就是句柄表的索引),如果创建失败一般会返回0(NULL),也有的会返回INVALID_HANDLE_VALUE=-1,比如CreateFile失败后会返回后者,失败的原因有可能是内存不足或者是安全问题等等。其他对内核操作的函数都需要此句柄值作为参数传递进去,如果传递一个无效的句柄进去,那么GetLastError函数的值将被置为6(ERROR_INVALID_HANDLE)。

    3.2.2 关闭内核对象

    BOOL CloseHandle(HANDLE hobj);

    调用此函数,系统会了清理进程的句柄表中的对应项目,如果使用计数器为0,内核释放该内核对象的资源,如果使用计数器不为0,说明其他进程还在使用此内核对象,则不释放资源。

    当进程忘记调用CloseHandle函数,可能造成内存泄露,但是当进程结束的时候资源一样会被释放。

    如果传递的参数无效,则函数返回FALSE,并且GetLastError函数的值被设置成ERROR_INVALID_HANDLE。如果是DEBUG阶段,则返回错误信息。

     
    3.3 跨越进程边界共享内核对象
    3.3.1 对象句柄的继承性
    1. 在父进程创建子进程的时候,将参数SECURITY_ATTRIBUTES结构的Inherithandle字段设置为TRUE的话,再父进程句柄表中标示该内核对象的项的标志位的值将会变成TRUE,标示该内核对象是可以让子进程继承的,具有可继承性(仅仅标示 该句柄值具有可继承性,而内核对象没有可继承性)。
    2. 将CreateProcess的参数bInherithandle参数的值设置为TRUE,标示创建的进程可以继承有继承性的父进程句柄。
    3. 子进程创建后不会先加载程序,它先搜索父进程的句柄表将有继承性的项目原封不动的拷贝给自己(索引也没有变,所以句柄值也不变)。
    4. 父进程可以有3种方式将句柄值传递给子进程,参数传递,进程间通信和环境变量(GetEnvironmentVariavle函数解析)。
    BOOL
    WINAPI
    CreateProcess(
        __in_opt    LPCSTR lpApplicationName,
        __inout_opt LPSTR lpCommandLine,
        __in_opt    LPSECURITY_ATTRIBUTES lpProcessAttributes,
        __in_opt    LPSECURITY_ATTRIBUTES lpThreadAttributes,
        __in        BOOL bInheritHandles,
        __in        DWORD dwCreationFlags,
        __in_opt    LPVOID lpEnvironment,
        __in_opt    LPCSTR lpCurrentDirectory,
        __in        LPSTARTUPINFOA lpStartupInfo,
        __out       LPPROCESS_INFORMATION lpProcessInformation
        );

    注意:子进程再创建其子进程,如果满足上面方式,可以继续继承。如果父进程再创建子进程后,再创建句柄,子进程不会被继承。3.3.2 改变句柄标志

    BOOL SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags);
    改变句柄的标志,目前可改变的标志有两种
    #define HANDLE_FLAG_INHERIT   0x00000001  // 继承标志
    #define HANDLE_FLAG_PROJECT_FROM_CLOSE   0x00000001 // 保护不允许关闭句柄标志
    可以用OR操作同时设置2个标志。第一个参数是要设置的句柄值,第二个就是要改变的标志,第三个参数是将标志改编成什么值。
    BOOL GetHandleInformation(HANDLE hObkect, PDWORD pdwFlags);
    获取当前句柄的标志的值。
    // 设置句柄值可继承:
    SetHandleInformation(hObject, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
    // 设置句柄不可继承:
    SetHandleInformation(hObject, HANDLE_FLAG_INHERIT, 0);
    // 设置句柄值不可关闭,受保护:
    SetHandleInformation(hObject, HANDLE_FLAG_PROJECT_FROM_CLOSE, HANDLE_FLAG_PROJECT_FROM_CLOSE);
    // 设置句柄值可关闭,不受保护:
    SetHandleInformation(hObject, HANDLE_FLAG_PROJECT_FROM_CLOSE, 0);
    3.3.3 命名对象
    创建内核对象函数族Create&中的最后一个参数是pszName,该参数是如果传递NULL,表示是匿名内核对象,可以通过其他俩种方式来使用其他进程的内核对象。当pszName参数传递以’\0’(最多长度为MAX_PATH 260字符)结尾的字符串时,表示启用命名对象,比如进程A调用CreateMutex(NULL, FALSE, “XI”)的时候,他将创建内核对象名字为“XI”,之后某一时刻如果进程B也调用CreateMutex(NULL, FALSE, “XI”)函数他将经过以下几步:
    1. 判断内核对象名称是否相同。
    2. 判断内核对象类型是否相同,如果名字相同但是类型不相同则Create&函数族返回NULL,GetLastError函数值为6(ERROR_INVALID_HANDLE)。
    3. 判断安全性,返回同2步,GetLastError值同2步。
    4. 如果验证通过则返回句柄(返回句柄的值和该内核对象其他句柄的值不一定相同),GetLastError的值等于ERROR_ALREADY_EXISTS。

    也可以用Open&函数族来打开已经创建的句柄,成功后GetLastError也不会被设置。具体如下

    HANDLE Open&(DWORD, BOOL, PCSTR);

    第一个参数:表示访问权限。

    第二个参数:表示新创建的句柄是否有继承性(注意不是内核对象!)。

    第三个参数:不能传递NULL。如果该句柄不存在则返回NULL,GetLastError被设置为2(ERROR_FILE_NOT_FOUND)。

    3.3.4 终端服务器的名字空间

    Globad,Local,Session程序保留关键字,具体的没弄明白,理解的就是说当服务器的时候,客户端可以访问以这些名字开头的内核对象。

    3.3.5 复制对象句柄

    BOOL DuplicateHandle(
    HANDLE hSourceProcessHandle,
    HANDLE hSourceHandle,
    HANDLE TargetProcessHandle,
    PHANDLE phTargetHandle,
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    DWORD dwOptions);

    执行DuplicateHandle函数的进程为ProcessC,原进程为ProcessS,目标进程为ProcessT。则hSourceProcessHandle为进程ProcessS的进程句柄,TargetProcessHandle为进程ProcessT的进程句柄,ProcessC将句柄hSourceHandle从ProcessC拷贝到ProcessT中,值存在phTargetHandle中,dwDesiredAccess新句柄的反问权限,bInheritHandle新句柄的继承性,参数dwOptions有两种类型分别是:

    DUPLICATE_SAME_ACCESS忽略参数dwDesiredAccess,新句柄和原进程句柄具有相同的反问权限。

    DUPLICATE_CLOSE_SOURCE关闭ProcessS中的拷贝句柄,内核对象的计数不变。

    HANDLE hObjProcessS = CreateMutex(NULL, FALSE, NULL);
    HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessIdT);
    HANDLE hObjProcessT;
    DuplicateHandle(GetCurrentProcess(), hObjProcessS, hProcessT , &hObjProcessT, 0, FALSE, DUPLICATE_SAME_ACCESS);
    CloseHandle(hObjProcessS);
    CloseHandle(hProcessT);

    注意:
    一般DuplicateHandle函数没有在三个进程中使用,因为很难知道原进程的句柄值。
    要使用IPC机制通知目标进程,新句柄已经拷贝过去。

     
     
     
     
     
  • 相关阅读:
    托付和事件的使用
    在使用supervisord 管理tomcat时遇到的小问题
    无法安装vmware tools的解决方PLEASE WAIT! VMware Tools is currently being installed on your system. Dependin
    (转)Openlayers 2.X加载高德地图
    (转)openlayers实现在线编辑
    (转) Arcgis for js加载百度地图
    (转)Arcgis for js加载天地图
    (转) 基于Arcgis for Js的web GIS数据在线采集简介
    (转) Arcgis for js之WKT和GEOMETRY的相互转换
    (转)Arcgis for Js之Graphiclayer扩展详解
  • 原文地址:https://www.cnblogs.com/xi52qian/p/1967510.html
Copyright © 2011-2022 走看看