跨越进程边界共享内核对象

来源:互联网 发布:web编程基础 编辑:程序博客网 时间:2024/05/14 13:43

3个不同的机制 :

1对象句柄的继承性 

只有当进程具有父子关系时,才能使用对象句柄的继承性。 

首先,当父进程创建内核对象时,必须向系统指明,它希望对象的句柄是个可继承的句柄。请记住,虽然内核对象句柄具有继承性,但是内核对象本身不具备继承性。 

若要创建能继承的句柄,父进程必须指定一个SECURITY_A TTRIBUTES结构并对它进行初始化 ,

下 面 的 代 码 用 于 创 建 一 个 互 斥 对 象 ,并将一个可继承的句柄返回给它: 

SECURITY_ATTRIBUTES sa;sa.nLength=sizeof(sa);sa.lpSecurityDescriptor=NULL;//默认安全性sa.bInheritHandle=TRUE;//让该句柄具有继承性
HANDLE hMutex = CreateMutex(&sa,FALSE,NULL);

使用对象句柄继承性时要执行的下一个步骤是让父进程生成子进程。这要使用C r e a t eP r o c e s s函数来完成: 

BOOL CreateProcess(PCTSTR pszApplicationName,PTSTR pszCommandLine,PSECURITY_ATTRIBUTES psaProcess,PSECURITY_ATTRIBUTES pszThread,BOOL bInheritHandles,DWORD dwCreationFlags,PVOID pvEnviroment,PCTSTR pszCurrentDirectory,LPSTARTUPINFO pStartupInfo,PPROCESS_INFORMATION pProcessInformation);

注意 bInheritHandles这个参数 ,一般 来 说 , 当 生 成 一 个 进 程 时 , 将 为 该 参 数 传 递 FA L S E。 该 值 告 诉 系 统 , 不 希 望 子 进 程 继 承 父 进程的句柄表中的可继承句柄。但是,如果为该参数传递T R U E ,那么子进程就可以继承父进程的可继承句柄值。 

除了拷贝句柄表项目外,系统还要递增内核对象的使用计数,因为现在两个进程都使用该对象。如果要撤消内核对象,那么父进程和子进程必须调用该对象上的C l o s e H a n d l e函 数 , 也可以终止进程的运行。 


2改变句柄的标志 

有时会遇到这样一种情况,父进程创建一个内核对象,以便检索可继承的句柄,然后生成两个子进程。父进程只想要一个子进程来继承内核对象的句柄。 

可以调用SeHandleInformation函数: 

BOOL SetHandleInformation(HANDLE hObject,DWORD daMask,DWORD dwFlags);


可以看到,该函数拥有 3 个参数。第一个参数h O b j e c t用 于 标 识 一 个 有 效 的 句 柄 。 第 二 个 参数d w M a s k告 诉 该 函 数 想 要 改 变 哪 个 或 那 几 个 标 志 。 目 前 有 两 个 标 志 与 每 个 句 柄 相 关 联 : 


#define HANDLE_FLAG_INFERIT  0✖️00000001

#define HANDLE_FLAG_PROTECT_FROM_CLOSE   0✖️00000002

 要 打开一个内核对象句柄的继承标志,请创建下面的代码: 

SetHandleInformation(hobj,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);

若要关闭该标志,请创建下面的代码:

SetHandleInformation(hobj,HANDLE_FLAG_INHERIT,0);


H A N D L E _ F L A G _ P R O T E C T _ F R O M _ C L O S E标 志 用 于 告 诉 系 统 , 该 句 柄 不 应 该 被 关 闭 : 

SetHandleInformation(hobj,HANDLE_FLAG_PROTECT_FROM_CLOSE,HANDLE_FLAG_PROTECT_FROM_CLOSE);CloseHandle(hobj);//Exception is raised

3命名对象 

共享跨越进程边界的内核对象的第二种方法是给对象命名 ,下面的所有函数都可以创建命名的内核对象 :

HANDLE CreateMutex(PSECURITY_ATTRIBUTES psa,BOOL bInitialOwner,PCTSTR pszName);..CreateEvent..CreateSemaphore..CreateWaitableTimer..CreateFileMapping..CreateJobObject..


所有这些函数都有一个共同的最后参数 p s z N a m e。当为该参数传递N U L L时,就向系统指明了想创建一个未命名的(匿名)内核对象。 


如果试图创建一个称为“ J e ff O b j” 的 对 象 , 那 么 不 能 保 证 系 统 中不存在一个名字为“J e ff O b j” 的 对 象 。 更 为 糟 糕 的 是 , 所 有 这 些 对 象 都 共 享 单 个 名 空 间 。 由 于这个原因,对下面这个C r e a t e S e m a p h o r e函数的调用将总是返回N U L L

HANDLE hMutex=CreateMutex(NULL,FALSE,"JeffObj");HANDLE hSem=CreateSemaphore(NULL,1,1,"JeffObj");DWORD dwErrorCode=GetLastError();

如果在执行上面的代码后观察d w E r r o r c o d e的值,会看到返回的代码是6(E R R O R _INV ALID_HANDLE)。 


应用程序先确定是否创建了一个新内核对象,否则就打开了一个现有的对象。方法是在调用C r e a t e *函数后立即调用G e t L a s t E r r o r

if(GetLastError()==ERROR_ALREADY_EXISTS){<span style="white-space:pre"></span>//打开一个现有的句柄对象}else{<span style="white-space:pre"></span>//创建一个新句柄对象}


打开一个现有的句柄对象,调用下面显示的O p e n * 函数中的某一个: 

HANDLE OpenMutex(DWORD dwDesiredAccess,BOOL bInheritHandle,PCTSTR pszName);..OpenEvent..OpenSemaphore..OpenWaitableTimer..OpenFileMapping..OpenJobObject..


最后一个参数p s z N a m e用 于 指 明 内 核 对 象 的 名 字 。 


Window程序防止双开:

i

nt WINAPI WinMain(HINSTANCE hinstExe,HINSTANCE,PSTR pszCmdLine,int nCmdShow){HANDLE h= CreateMutex(NULL,FLASE,"myMutex");if(GetLastError()==ERROR_ALREADY_EXITSTS){//说明已经有一个实例程序在运行,这个试图双开的程序即将结束return 0;}//这里是你的第一个实例程序,依然在运行中...//结束时要把句柄关闭CloseHandle(h);return 0;}

5复制对象句柄

共享跨越进程边界的内核对象的最后一个方法是使用D u p l i c a t e H a n d l e函数 :

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

D u p l i c a t e H a n d l e函数最普通的用法要涉及系统中运行的3个不同进程。 

当调用 D u p l i c a t e H a n d l e函数时,第一和第三个参数h S o u r c e P r o c e s s H a n d l eh Ta rg e tP r o c e s s H a n d l e是内核对象句柄。这些句柄本身必须与调用D u p l i c a t e H a n d l e函 数 的 进 程 相 关 。 

第二个参数 h S o u r c e H a n d l e是任何类型的内核对象的句柄。但是该句柄值与调用D u p l i c a t eH a n d l e的进程并无关系。相反,该句柄必须与h S o u r c e P r o c e s s H a n d l e句 柄 标 识 的 进 程 相 关 。 第四个参数phTargetHandleHANDLE变量的地址,它将接收获取源进程句柄信息拷贝的项目索引。 

D u p l i c a t e H a n d l e的最后3个 参 数 用 于 指 明 该 目 标 进 程 的 内 核 对 象 句 柄 表 项 目 中 使 用 的 访 问屏 蔽 值 和 继 承 性 标 志 。d w O p t i o n s参 数 可 以 是0 ( 零 ), 也 可 以 是 下 面 两 个 标 志 的 任 何 组 合 :DUPLICA TE_SAME_ACCESSDUPLICA TE_CLOSE_SOURCE。 

如果设定了DUPLICATE_SAME_ACCESS标志,则告诉DuplicateHandle函数,你希望目标进程的句柄拥有与源进程句柄相同的访问屏蔽。使用该标志将使D u p l i c a t e H a n d l e忽略它的d w D e s i r e d A c c e s s参数。 

如果设定了 DUPLICA TE_CLOSE_SOURCE标志,则可以关闭源进程中的句柄。该标志使得一个进程能够很容易地将内核对象传递给另一个进程。当使用该标志时,内核对象的使用计数不会受到影响。 

可以像下面这样调用 D u p l i c a t e H a n d l e : 

//下面这些代码是运行在Process S//在Process S中创建互次对象HANDLE hObjProcessS=CreateMutes(NULL,FALSE,NULL);//匿名对象//打开Process T的内核对象HANDLE hProcessT=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessIdT);//没有初始化的句柄对象,即将把 hObjProcessS复制给它并属于Process THANDLE hObjProcessT;DuplicateHandle(GetCurrentProcess(),HObjProcessS,hProcessT,&hObjProcessT,0,FALSE,DUPLICATE_SAME_ACESS);....//不再使用ProcessT 时,关闭CloseHandle(hProcessT);//不再使用互斥对象时,CloseHandle(hObjProcessS);//一旦 D u p l i c a t e H a n d l e返回, h O b j P r o c e s s T 就是与 P r o c e s s T 相关的句柄 //一定不要执行下面的代码。//CloseHandle(hObjProcessT);

下面是使用 D u p l i c a t e H a n d l e函 数 的 另 一 种 方 法 。 假 设 一 个 进 程 拥 有 对 一 个 文 件 映 射 对 象 的读和写访问权。在某个位置上,一个函数被调用,它通过读取文件映射对象来访问它。为了使应 用 程 序 更 加 健 壮 , 可 以 使 用D u p l i c a t e H a n d l e为 现 有 的 对 象 创 建 一 个 新 句 柄 , 并 确 保 这 个 新 句柄拥有对该对象的只读访问权。然后将只读句柄传递给该函数,这样,该函数中的代码就永远不会偶然对该文件映射对象执行写入操作。下面这个代码说明了这个例子: 

int WINAPI WinMain(HINSTANCE,hinstExe,HINSTANCE,LPSTR szCmdLine,intnCmdShow){HANDLE hFileMapRW= CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,10240,NULL);HANDLE hFileMapRO;DuplicateHandle(GetCurrentProcess(),hFileMapRW,GetCurrentProcess(),&hFileMapRO,FILE_MAP_READ,FALSE,0);ReadFromTheFileMapping(hFileMapRO);//...Read onlyCloseHandle(hFileMapRO);//....Read and writeCloseHandle(hFileMapRW);}



0 0
原创粉丝点击