共享内核对象

使用对象句柄继承
进程之间的继承。
  1. 父进程指定对象句柄可以继承,把SECURUTY_ATTRIBUTESbInheritHandle设为TRUE(不想被继承就设为FALSE),使用这个结构创建的对象句柄可以被继承(FALSE就不行)。同时会把进程句柄表里面的相应标志设置(TRUE是0x00000001,FALSE是0x00000000)。
  2. 父进程创建子进程。
CreateProcess(
  LPCTSTR lpApplicationName,//可执行模块名
  LPTSTR lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributs,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL bInHeritHandle,//是否继承父进程的句柄表
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCTSTR lpCurrentDirectory,
  LPSTARTUPINFO lpStartuoInfo,
  LPPROCESS_INFORMATION  pProcessInformation
);

bInHeritHandle是TRUE,子进程会遍历父进程的句柄表,并把可继承的项复制到子进程句柄表(这个句柄表是新建的空白句柄表)的同一位置,这意味着在父进程和子进程中,对一个内核对象进行标识的句柄值起来完全一样的,并且会递增被继承的内核对象的使用计数。

  1. 对象句柄的继承只发生在生成子进程的时候,也就是说父进程在创建子进程(被继承)之后,父进程创建的新的可继承的句柄还是不会被之前创建的子进程所继承
  • 改变句柄状态
BOOL SetHandleInformation(
  HANDLE hObject,
  DWORD dwMask,//要更改的句柄标志
  DWORD dwFlags);//把标志设为这个值
  BOOL GetHandleInformation(
  HANDLE hObject,
  PDWORD pdwFlags
);

//打开一个内核对象句柄的继承标志
SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);

//关闭一个内核对象句柄的继承标志
SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, 0);

//告诉系统不允许关闭句柄
SetHandleInformation(hObj, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
CloseHandle(hObj);  //会引发异常
  • 获取句柄状态
BOOL GetHandleInformation(
  Handle hObject,
  PWORD pdwFlags
);

//检查一个句柄是否可以继承,执行:
DWORD dwFlags;
GetHandleInformation(hObj, dwFlags);
BOOL fHandleIsInheritable = (0 != (dwFlags & HANDLE_FLAG_INHERIT));
  • dwMask标志:
    1、 HANDLE_FLAG_INHERIT 0x00000001
    2、 HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002(告诉系统不允许关闭句柄,一般会用于父进程-子进程-孙进程……)
  1. 子进程不知道自己继承了任何句柄。到目前为止,为了使子进程得到它想要的一个内核对象的句柄值,最常见的方式是将句柄值作为命令行参数传递给子进程,子进程在初始化时,解析命令行并提取句柄值。
  2. 注意,句柄继承之所以能够实现,唯一的原因就是“共享的内核对象”的句柄值在父进程和子进程中是完全一样的。
  3. 其他进程间通信将继承的内核对象句柄值从父进程传入子进程:
    1、让父进程等待子进程完成初始化(WaitForInputIdle函数),然后父进程可以将一条消息发送或发布到由子进程中的一个线程创建的一个窗口
    2、让父进程向其环境块中添加一个环境变量。变量的名称应该是子进程知道的一个名称,而变量的值应该是准备被子进程继承的那个内核对象的句柄值。然后,当父进程生成子进程的时候,这个子进程会继承父进程的环境变量,通过调用GetEnvironmentVariable来获得继承到内核对象的句柄值。环境变量可以反复继承
为对象命名
  • 很多内核对象创建函数的最后一个参数是名称(为NULL表示匿名),以\0结尾的最长MAX_PATH的字符串。
  • 这个要特别注意新建的内核对象的名称会不会已经存在了,如果是在同一个进程里,哪怕是它们的内核对象类型不同也是不可以的。
  • 如果是进程创建另一个进程中创建的内核对象,如果内核对象的类型相同,并且对它具有完全访问权限,然后这个进程就会新建一个空白项,并初始化指向它。如果类型不匹配或者调用者被拒绝访问,返回失败。
  • 进程B成功创建一个已经存在的内核对象时,并不会实际创建一个新的内核对象,而是给进程B分配一个新的句柄值,它标识了内核中的一个现有的互斥量对象。由于在进程B的句柄表中,所以引用计数会递增
  • 可以创建命名的内核对象的函数:
HANDLE CreateMutex(
  PSECURITY_ATTRIBUTES psa,
  BOOL bInitialOwner,
  PCTSTR pszName
);

HANDLE CreateEvent(
  PSECURITY_ATTRIBUTES psa,
  BOOL bManualReset,
  BOOL bInitialState,
  PCTSTR pszName
);

HANDLE CreateSemaphore(
  PSECURITY_ATTRIBUTES psa,
  LONG lInitialCount,
  LONG lMaximumCount,
  PCTSTR pszName
);

HANDLE CreateWaitableTimer(
  PSECURITY_ATTRIBUTES psa,
  BOOL bManualReset,
  PCTSTR pszName
);

HANDLE CreateFileMapping(
  HANDLE hFile,
  PSECURITY_ATTRIBUTES psa,
  DWORD flProtext,
  DWORD dwMaximumSizeHigh,
  DWORD dwMaximumSizeLow,
  PCTSTR pszName
);

HANDLE CreateJobObject(
  PSECURITY_ATTRIBUTES psa,
  PCTSTR pszName
);
  • 通过名称来实现内核对象共享时,进程B调用CreateMutex时,它会向函数传递安全属性信息和第二个参数。如果已经存在一个指定名称的对象,这些参数会被忽略。

  • 在调用Create *之后,马上调用GetLastError来判断自己是真正创建了一个新的内核对象还是打开了一个已有的。(已有:ERROR_ALREADY_EXEISTS)


    image.png
  • 调用Create *和Open *的区别主要在于,如果对象不存在Create *会创建它;而Open *只是简单地以调用失败而告终。

// 03-内核对象.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("{Test-djskvhbkejwvhkhvhdjhdhjvdbdbhdhbvdhbdh}"));    
    if (GetLastError() == ERROR_ALREADY_EXISTS)
    {
        printf("内核对象已存在! {Test-djskvhbkejwvhkhvhdjhdhjvdbdbhdhbvdhbdh}");
        CloseHandle(hMutex);
        return 0;
    }
    printf("创建内核对象! {Test-djskvhbkejwvhkhvhdjhdhjvdbdbhdhbvdhbdh}");
    getchar();
    CloseHandle(hMutex);    //Close的时候会关闭句柄,并且使用计数-1,使用为0时销毁对象
    return 0;
}
终端服务命名空间

在正在运行终端服务的计算机中,有多个用于内核对象的命名空间。其中一个是全局命名空间,所有客户端都能访问的内核对象放在这个命名空间中,这个命名空间主要是由服务使用。此外,每个客户端会话都有一个自己的命名空间,可以避免会话之间彼此干扰。

  • 查看当前进程在哪个Terminal Services会话中运行
#include "stdafx.h"
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwCurProcessID = GetCurrentProcessId();
    DWORD dwSessionID;
    if (ProcessIdToSessionId(dwCurProcessID, &dwSessionID))
    {
        printf("ProcessID:%u, SessionID:%u\n", dwCurProcessID, dwSessionID);
    }
    else
    {
        printf("GetSessionID failed!\n");
    }
    return 0;
}
  • 一个服务的命名内核对象始终位于全局命名空间内。默认情况下,在终端服务中,应用程序自己的命名内核对象在会话的命名空间内。也可以强制把一个命名对象放到全局命名空间中,具体做法是:在其名称前面加上“Global\”前缀;显式把命名内核对象放入当前会话的命名孔家,做法:在名称前加“Local\”前缀
  • Microsoft认为Global和Local是保留关键字,所以除非是为了强制一个特定的命名空间,否则不应该在对象名称中使用它们
专有命名空间
  • 创建内核对象时,可以传递一个指向SECURITY_ATTRIBUTES结构的指针,从而保护对该对象的访问。
  • 在Windows Vista发布之前,我们不可能防止一个共享对象的名称被“劫持”。任何进程(即时是最低权限的进程)都能用任何指定的名称来创建一个对象。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,030评论 0 2
  • 简介 AbstractMutableList 是一个超级好用的抽象类,里面实现了好多对集合操作的直观方法,新鲜事物...
    坑吭吭阅读 1,976评论 2 2
  • 从小到大,学习并不是一直都好,并不是那种让大家熟知的故事那样,一路三好学生到底,,更不是一直都坏,一路都没有救了路...
    雨飞飞雨阅读 359评论 1 5
  • 【英语课堂】Beauty is to fight for rather than to wait for. 只有拼...
    剑桥有约阅读 191评论 0 0