内核对象——Windows核心编程学习手札系列之三
內(nèi)核對(duì)象
——Windows核心編程學(xué)習(xí)手札系列之三
內(nèi)核對(duì)象可供系統(tǒng)和應(yīng)用程序使用來管理各種各樣的資源,如進(jìn)程、線程、文件等,是內(nèi)核分配的一個(gè)內(nèi)存塊,只能又內(nèi)核訪問,該內(nèi)存塊是一種數(shù)據(jù)結(jié)構(gòu),它的成員負(fù)責(zé)維護(hù)該對(duì)象的各種信息。內(nèi)核對(duì)象的數(shù)據(jù)結(jié)構(gòu),也就是內(nèi)存塊是不允許應(yīng)用程序直接修改其內(nèi)容,而由Windows提供一組函數(shù)進(jìn)行訪問,創(chuàng)建內(nèi)核對(duì)象的函數(shù)會(huì)返回對(duì)象的句柄,該句柄對(duì)于進(jìn)程中的任何線程都可見,這個(gè)句柄傳遞給Windows各個(gè)函數(shù),操作系統(tǒng)就知道要操作的內(nèi)核對(duì)象。內(nèi)核句柄與進(jìn)程相關(guān),如果跨越進(jìn)程調(diào)用句柄可能會(huì)失敗,如何實(shí)現(xiàn)多進(jìn)程共享單個(gè)內(nèi)核對(duì)象需要一定機(jī)制,后文將提到。
內(nèi)核對(duì)象為內(nèi)核所擁有,而非進(jìn)程。如果一個(gè)進(jìn)程創(chuàng)建了內(nèi)核對(duì)象,在進(jìn)程終止運(yùn)行后內(nèi)信對(duì)象不一定被撤消。內(nèi)核通過內(nèi)核對(duì)象類型中的常用數(shù)據(jù)成員使用計(jì)數(shù)知道有多少個(gè)進(jìn)程正在使用該內(nèi)核對(duì)象。當(dāng)進(jìn)程終止時(shí),內(nèi)核會(huì)對(duì)使用計(jì)數(shù)進(jìn)行減一操作,如果到零則撤消該對(duì)象,確保在沒有任何進(jìn)程引用該對(duì)象情況下系統(tǒng)中不保留該內(nèi)核對(duì)象。
創(chuàng)建內(nèi)核對(duì)象的函數(shù)都有一個(gè)SECURITY_ATTRIBUTES結(jié)構(gòu)的指針作為參數(shù),其結(jié)構(gòu)成員lpSecurityDescriptor與內(nèi)核對(duì)象安全性有關(guān)。安全描述符描述了誰創(chuàng)建了內(nèi)核對(duì)象,誰可以訪問或使用該對(duì)象。這里可以通過設(shè)置SECURITY_ATTRIBUTES結(jié)構(gòu)內(nèi)lpSecurityDescriptor成值來滿足。對(duì)于用戶對(duì)象或圖形設(shè)備接口(菜單、窗口、光標(biāo)、字體等)的創(chuàng)建函數(shù)是不需要設(shè)定安全屬性的信息,而內(nèi)核對(duì)象則需要。
進(jìn)程初始化時(shí),操作系統(tǒng)會(huì)為其分配一個(gè)句柄表,該表用于設(shè)置內(nèi)核對(duì)象數(shù)據(jù)結(jié)構(gòu)的內(nèi)存地址、訪問權(quán)限以及繼承等標(biāo)志位。進(jìn)程的線程在創(chuàng)建內(nèi)核對(duì)象時(shí),內(nèi)核為其分配內(nèi)存塊并初始化并到進(jìn)程的句柄表中掃描空項(xiàng)并設(shè)置相關(guān)信息。當(dāng)進(jìn)程調(diào)用BOOL CloseHandle(HANDLE hobj)函數(shù)結(jié)束內(nèi)核對(duì)象時(shí),函數(shù)也會(huì)先檢查進(jìn)程句柄表,以標(biāo)識(shí)進(jìn)程無權(quán)訪問該對(duì)象,同時(shí)獲得內(nèi)核對(duì)象數(shù)據(jù)結(jié)構(gòu)地址中使用計(jì)數(shù)的數(shù)據(jù)成員,如為零則從內(nèi)存中撤消該內(nèi)核對(duì)象。當(dāng)然,如果忘記調(diào)用CloseHandle函數(shù)將導(dǎo)致內(nèi)存泄露的可能,不過僅存在進(jìn)程運(yùn)行時(shí)才會(huì)發(fā)生。因?yàn)橐坏┻M(jìn)程終止運(yùn)行,操作系統(tǒng)將對(duì)進(jìn)程內(nèi)的任何資源進(jìn)行釋放,體現(xiàn)在內(nèi)核對(duì)象的釋放上就是通過訪問進(jìn)程句柄表;當(dāng)進(jìn)程終止運(yùn)行,系統(tǒng)會(huì)掃描進(jìn)程句柄表,如果該表仍有無效項(xiàng)目(終止進(jìn)程前沒有關(guān)閉的對(duì)象),系統(tǒng)將自動(dòng)關(guān)閉這些對(duì)象,如果這些對(duì)象的使用計(jì)數(shù)為零則由內(nèi)核撤消該對(duì)象。
不同進(jìn)程中運(yùn)行的線程在如下情況中需要共享內(nèi)核對(duì)象:文件映射對(duì)象使你能夠在同一臺(tái)機(jī)器上運(yùn)行的兩個(gè)進(jìn)程之間共享數(shù)據(jù)塊;郵箱或指定的管道使得應(yīng)用程序能夠在聯(lián)網(wǎng)的不同機(jī)器上運(yùn)行的進(jìn)程之間發(fā)送數(shù)據(jù)塊;互斥對(duì)象、信標(biāo)和事件使得不同進(jìn)程中線程能夠同步它們的連續(xù)運(yùn)行,這與一個(gè)應(yīng)用程序在完成某項(xiàng)任務(wù)時(shí)需要通知另一個(gè)應(yīng)用程序的情況相同。總的來說是數(shù)據(jù)共享、數(shù)據(jù)發(fā)送、同步控制三方面的需要。
內(nèi)核對(duì)象句柄的繼承性,內(nèi)核對(duì)象句柄是和進(jìn)程相關(guān)的。當(dāng)父進(jìn)程創(chuàng)建內(nèi)核對(duì)象句柄時(shí),向操作系統(tǒng)指明對(duì)象句柄是個(gè)可繼承的句柄,通過對(duì)SECURITY_ATTRIBUTES結(jié)構(gòu)中bInheritHandle設(shè)置來實(shí)現(xiàn),這將對(duì)進(jìn)程句柄表中繼承標(biāo)志位設(shè)為1。內(nèi)核對(duì)象本身不具備繼承性,但內(nèi)核對(duì)象句柄具有繼承性。父進(jìn)程中設(shè)置了該對(duì)象句柄可繼承,那么在創(chuàng)建子進(jìn)程的函數(shù)CreateProcess中bInheritHandle參數(shù)也需要設(shè)為TRUE,這時(shí)操作系統(tǒng)同樣為子進(jìn)程分配新的和空的句柄表之外還會(huì)遍歷父進(jìn)程句柄表,拷貝父進(jìn)程有效的可繼承的句柄項(xiàng)目到子進(jìn)程句柄表中,同時(shí)遞增內(nèi)核對(duì)象的使用計(jì)數(shù)。對(duì)于已經(jīng)運(yùn)行的子進(jìn)程,父進(jìn)程正創(chuàng)建的帶有可繼承句柄的新內(nèi)核對(duì)象是無法繼承的,也就是說對(duì)象句柄的繼承性只有在生成子進(jìn)程時(shí)候才能使用。若要改變句柄標(biāo)志,可通過SetHandleInformation函數(shù):
BOOL SetHandleInformation( HANDLE hObject,DWORD dwMask,DWORD dwFlags);
第一個(gè)參數(shù)hObject是一個(gè)有效句柄;第二個(gè)參數(shù)dwMask告訴函數(shù)想要改變哪個(gè)標(biāo)志,目前有兩個(gè)標(biāo)志與每個(gè)句柄關(guān)聯(lián),#define HANDLE_FLAG_INHERIT 0x00000001/#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002,同時(shí)改變這兩個(gè)標(biāo)志可用OR連接起來;第三個(gè)參數(shù)是dwFlags指明想將標(biāo)志設(shè)置成什么值,如要打開一個(gè)內(nèi)核對(duì)象句柄的繼承標(biāo)志,可用下面代碼:
SetHandleInformation(hObj,HANDLE_FLAG_INHERIT,HANDLE_FLAG_INHERIT);
若要關(guān)閉標(biāo)志,則:
SetHandleInformation(hObj,HANDLE_FLAG_INHERIT,0);
HANDLE_FLAG_PROTECT_FROM_CLOSE標(biāo)志用于告訴系統(tǒng),該句柄不應(yīng)被關(guān)閉:
SetHandleInfomation(hObj,HANDLE_FLAG_PROTECT_FROM_CLOSE,HANDLE_FLAG_PROTECT_FROM_CLOSE);
CloseHandle(hObj);
如果一個(gè)線程試圖關(guān)閉一個(gè)受保護(hù)的句柄,CloseHandle會(huì)產(chǎn)生一個(gè)異常條件。當(dāng)然可以通過GetHandleInformation來獲取句柄的標(biāo)志是否滿足可繼承性,如下面:
DWORD dwFlags;
GetHandleInformation(hObj,&dwFlags);
BOOL fHandleIsInheritable=(0!=(dwFlags & HANDLE_FLAG_INHERIT));
if(fHandleIsInheritable) //可繼承
else //不可繼承
給對(duì)象命名是實(shí)現(xiàn)共享跨越進(jìn)程邊界內(nèi)核對(duì)象的第二種方法。對(duì)對(duì)象命名,而后要共享者打開該名字,即可共享該對(duì)象。服務(wù)器的名字命名空間對(duì)象是放在全局名字空間中,按照默認(rèn)設(shè)置,在終端服務(wù)器中,應(yīng)用程序的命名內(nèi)核對(duì)象將放入會(huì)話的名字空間中。將命名對(duì)象置于全局名字空間的代碼:
HANDLE h=CreateEvent(NULL,FALSE,FALSE,”Global//myname”);
將內(nèi)核對(duì)象放入會(huì)話的名字空間代碼:
HANDLE h=CreateEvent(NULL,FALSE,FALSE,”Local//myname”);
終端服務(wù)器擁有內(nèi)核對(duì)象的多個(gè)名字空間,全局名字空間和會(huì)話名字空間。全局名字空間意味著所有客戶程序都可以訪問,該名字空間主要供服務(wù)程序使用;而會(huì)話名字空間則屬于每個(gè)客戶程序自己的名字空間,可防止運(yùn)行相同應(yīng)用程序的兩個(gè)或多個(gè)會(huì)話之間出現(xiàn)互相干擾情況,一個(gè)會(huì)話無法訪問另一個(gè)會(huì)話的對(duì)象,盡管對(duì)象之間可能擁有相同名字。Microsoft將Golbal和Local作為保留關(guān)鍵字。
復(fù)制對(duì)象句柄是共享跨越進(jìn)程邊界內(nèi)核對(duì)象最后方法:
BOOL DuplicateHandle(
??????????? HANDLE hSourceProcessHandle,
??????????? HANDLE hSoruceHandle,
??????????? HANDLE hTargetProcessHandle,
?????? ?????PHANDLE phTargetHandle,
??????????? DWORD dwDesiredAccess,
??????????? BOOL? bInheritHandle,
??????????? DWORD dwOptions);
這個(gè)函數(shù)將一個(gè)進(jìn)程句柄表中的項(xiàng)目取出,拷貝到另一個(gè)進(jìn)程的句柄表中。例子:Process S擁有對(duì)一個(gè)內(nèi)核對(duì)象的訪問權(quán),想讓Process T能夠訪問該對(duì)象:
//All of the following code is executed by Process S
//Create a mutex object accessible by Process S
HANDLE hObjProcessS=CreateMutex(NULL,FALSE,NULL);
//Open a handle to Process T’s kernel object.
HANDLE hProcessT=OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessIDT);
HANDLE hObjProcessT;//An uninitialized handle relative to Process T
//Give Process T access to our mutex object.
DuplicateHandle(GetCurrentProcess(),hObjProcessS,hProcessT,&hObjProcessT,0,FALSE,
????????????? DUPLICATE_SAME_ACCESS);
//Use some IPC mechanism to get the handle
//value in hObjProcessS into Process T
……
//We no longer need to communicate with ProcessT.
CloseHandle(hProcessT);
……
//When Process S no longer needs to use the mutex,ti should close it
CloseHandle(hObjProcessS);
IPC(Internet Process Connection)是共享"命名管道"的資源,它是為了讓進(jìn)程間通信而開放的命名管道,通過提供可信任的用戶名和口令,連接雙方可以建立安全的通道并以此通道進(jìn)行加密數(shù)據(jù)的交換,從而實(shí)現(xiàn)對(duì)遠(yuǎn)程計(jì)算機(jī)的訪問。
??????????????? 如非 2008-11-25
總結(jié)
以上是生活随笔為你收集整理的内核对象——Windows核心编程学习手札系列之三的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 进程——Windows核心编程学习手札系
- 下一篇: 作业——Windows核心编程学习手札系