1、何為內(nèi)核對(duì)象
每個(gè)內(nèi)核對(duì)象都只是一個(gè)內(nèi)存塊,它由操作系統(tǒng)內(nèi)核分配,并只能由操作系統(tǒng)內(nèi)核訪問(wèn)。這個(gè)內(nèi)存塊是一個(gè)數(shù)據(jù)結(jié)構(gòu),其成員維護(hù)著于對(duì)象相關(guān)的信息。少數(shù)成員(安全描述符何使用計(jì)數(shù)等)是所有對(duì)象都有的,但其他大多數(shù)成員都是不同類型的對(duì)象特有的。
e.g. 訪問(wèn)令牌(access token)對(duì)象、事件對(duì)象、文件對(duì)象、文件映射對(duì)象、I/O完成端口對(duì)象、作業(yè)對(duì)象、郵件槽(mailsolt)對(duì)象、互斥量(mutex)對(duì)象、管道(pipe)對(duì)象等
*可利用Sysintenals的WinObj(http://technet.microsoft.com/zh-cn/sysinternals/bb896657.aspx)工具查看內(nèi)核對(duì)象類型的列表。
1.1、使用計(jì)數(shù)
使用計(jì)數(shù)事所有內(nèi)核對(duì)象類型都有的一個(gè)數(shù)據(jù)成員。初次創(chuàng)建對(duì)象事,其使用計(jì)數(shù)被設(shè)為1。如果另一進(jìn)程獲得對(duì)現(xiàn)有內(nèi)核對(duì)象的訪問(wèn)后,使用計(jì)數(shù)會(huì)遞增。進(jìn)程終止運(yùn)行后,操作系統(tǒng)內(nèi)核將自動(dòng)遞減進(jìn)程仍然打開(kāi)的所有內(nèi)核對(duì)象的使用計(jì)數(shù)。一旦對(duì)象的使用計(jì)數(shù)變?yōu)?span style="COLOR: red">0,操作系統(tǒng)內(nèi)核就會(huì)銷毀該對(duì)象。
1.2、內(nèi)核對(duì)象的安全性
內(nèi)核對(duì)象可以用一個(gè)安全描述(security descriptor, SD)符來(lái)保護(hù)。它描述了誰(shuí)擁有對(duì)象;哪些組和用戶被允許訪問(wèn)或使用此對(duì)象;哪些組何用戶被拒絕訪問(wèn)此對(duì)象。
用于創(chuàng)建內(nèi)核對(duì)象的所有函數(shù)幾乎都有指向一個(gè)SECURITY_ATTRIBUTES結(jié)構(gòu)的指針
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID nLength; //Specifies the size, in bytes, of this structure,一般為sizeof(此結(jié)構(gòu)變量)
LPVOID lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL lpSecurityDescriptor; //和安全性有關(guān)的成員
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
2、進(jìn)程內(nèi)核對(duì)象句柄表
進(jìn)程的句柄表結(jié)構(gòu)
索引
|
指向內(nèi)核對(duì)象內(nèi)存塊的指針
|
訪問(wèn)掩碼(包含標(biāo)志位的一個(gè)DWORD)
|
標(biāo)志
|
1
|
0x?????????
|
0x?????????
|
0x?????????
|
2
|
0x?????????
|
0x?????????
|
0x?????????
|
…
|
…
|
…
|
…
|
2.1、創(chuàng)建一個(gè)內(nèi)核對(duì)象
用于創(chuàng)建內(nèi)核對(duì)象的任何函數(shù)都會(huì)返回一個(gè)與進(jìn)程相關(guān)的句柄,這個(gè)句柄可由同一個(gè)進(jìn)程中運(yùn)行的所有線程使用。由于句柄值實(shí)際事作為進(jìn)程句柄表的索引來(lái)使用的,索引這些句柄是與當(dāng)前這個(gè)進(jìn)程相關(guān)的,無(wú)法供其他進(jìn)程使用。
調(diào)用函數(shù)來(lái)創(chuàng)建一個(gè)內(nèi)核對(duì)象時(shí),如果調(diào)用失敗,多數(shù)返回的句柄值是0(NULL),但有幾個(gè)函數(shù)會(huì)返回-1(也就是在Winbase.h中定義的INVALID_HANDLE_VALUE)。檢查它們的返回值是,務(wù)必相當(dāng)仔細(xì)。
2.2、關(guān)閉內(nèi)核對(duì)象
無(wú)論以什么方式創(chuàng)建內(nèi)核對(duì)象,我們都要調(diào)用CloseHandle向系統(tǒng)表明我們已經(jīng)結(jié)束使用對(duì)象。
BOOL CloseHandle(
HANDLE hObject // handle to object
);
在內(nèi)部,該函數(shù)首先檢查主調(diào)進(jìn)程的句柄表,驗(yàn)證“傳給函數(shù)的句柄值”標(biāo)識(shí)的是“進(jìn)程確實(shí)有權(quán)訪問(wèn)的一個(gè)對(duì)象”。
1)如果句柄是有效的,系統(tǒng)就將獲得內(nèi)核對(duì)象的數(shù)據(jù)結(jié)構(gòu)的地址,并將結(jié)構(gòu)中的“使用計(jì)數(shù)”成員遞減,如果使用計(jì)數(shù)變成0,內(nèi)核對(duì)象將被銷毀,并從內(nèi)存中去除。
2)如果句柄是無(wú)效的,
如果進(jìn)程是正常運(yùn)行的,CloseHandle將返回FALSE,而GetLastError返回ERROR_INVALID_HANDLE。
如果進(jìn)程正在被調(diào)試,那么系統(tǒng)將拋出0xC0000008異常(“指定了無(wú)效的句柄”)。
hObject // handle to object
);
在內(nèi)部,該函數(shù)首先檢查主調(diào)進(jìn)程的句柄表,驗(yàn)證“傳給函數(shù)的句柄值”標(biāo)識(shí)的是“進(jìn)程確實(shí)有權(quán)訪問(wèn)的一個(gè)對(duì)象”。
1)如果句柄是有效的,系統(tǒng)就將獲得內(nèi)核對(duì)象的數(shù)據(jù)結(jié)構(gòu)的地址,并將結(jié)構(gòu)中的“使用計(jì)數(shù)”成員遞減,如果使用計(jì)數(shù)變成0,內(nèi)核對(duì)象將被銷毀,并從內(nèi)存中去除。
2)如果句柄是無(wú)效的,
如果進(jìn)程是正常運(yùn)行的,CloseHandle將返回FALSE,而GetLastError返回ERROR_INVALID_HANDLE。
如果進(jìn)程正在被調(diào)試,那么系統(tǒng)將拋出0xC0000008異常(“指定了無(wú)效的句柄”)。
*檢測(cè)內(nèi)核對(duì)象泄露:
用Windows任務(wù)管理器,選擇(查看)->(選擇列),然后選擇顯示(句柄數(shù))。便可在進(jìn)程出監(jiān)視任何一個(gè)應(yīng)用程序的內(nèi)核對(duì)象數(shù)了。
使用Sysinternals提供的Process Explorer工具(http://technet.microsoft.com/zh-cn/sysinternals/bb896653.aspx),選擇(View)->(Select Columns),選擇(Handle),選中所有列標(biāo)題。 在頂部選擇想要檢查的進(jìn)程,按F5來(lái)獲得一份最新的內(nèi)核對(duì)象列表。 然后啟動(dòng)應(yīng)用程序并開(kāi)始指向一個(gè)待查的工作流。完成之后,再次按F5。在此期間生成的每個(gè)內(nèi)核對(duì)象都顯示為綠色。
3、跨進(jìn)程邊界共享內(nèi)核對(duì)象
內(nèi)核對(duì)象的句柄是與每一個(gè)進(jìn)程相關(guān)的,是為確保健壯性(可靠性)和安全性。
3.1、使用對(duì)象句柄繼承
只有在進(jìn)程之間有一個(gè)父-子關(guān)系的時(shí)候,才可以使用對(duì)象句柄繼承。
首先,父進(jìn)程必須向系統(tǒng)指出它希望這個(gè)對(duì)象的句柄是可繼承的。
e.g.
SECURITY_ATTRIBUTES sa;
sa.nLength = siezof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE; //Make the returned handle inheritable

HANDLE hMutex = CreateMutex(&sa, FALSE, NULL);
然后,由父進(jìn)程生成子進(jìn)程,通過(guò)
CreateProcess函數(shù)完成
BOOL CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles, //通常情況下設(shè)為FALSE(表明我們不希望子進(jìn)程繼承父進(jìn)程句柄表中的“可繼承句柄”)
//如果傳遞TRUE,子進(jìn)程就會(huì)繼承父進(jìn)程的“可繼承句柄”的值。
//(系統(tǒng)會(huì)遍歷符進(jìn)程的句柄表,對(duì)它的每一個(gè)記錄項(xiàng)進(jìn)行檢查,凡是包含一個(gè)
//有效的“可繼承句柄”的項(xiàng),都會(huì)被完整地復(fù)制到子進(jìn)程的句柄表)
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
除了復(fù)制句柄表的記錄項(xiàng),系統(tǒng)還會(huì)遞增內(nèi)核對(duì)象的使用計(jì)數(shù),引擎兩個(gè)進(jìn)程現(xiàn)在都在使用這個(gè)對(duì)象。
3.2改變句柄的標(biāo)志
1)父進(jìn)程想控制哪些子進(jìn)程能繼承內(nèi)核對(duì)象句柄??梢哉{(diào)用
SetHandleInformation函數(shù)來(lái)改變內(nèi)核對(duì)象句柄的繼承標(biāo)志。
BOOL SetHandleInformation(
HANDLE hObject, //有效句柄標(biāo)志
DWORD dwMask, //想要更改那個(gè)或哪些標(biāo)志
DWORD dwFlags //希望把標(biāo)志設(shè)為什么
);
每個(gè)句柄都關(guān)聯(lián)了兩個(gè)標(biāo)志:
#define HANDLE_FLAG_INHERIT 0x00000001
#define HANDLE_FLAG_PROTECT_FROM_CLOSE 0x00000002
如果想打開(kāi)一個(gè)內(nèi)核對(duì)象句柄的繼承標(biāo)志
SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
如果想關(guān)閉這個(gè)標(biāo)志
SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, 0);
如果告訴系統(tǒng)不允許關(guān)閉句柄
SetHandleInformation(hObj,,HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);
CloseHandle(hObj); //會(huì)引發(fā)異常
2)使用
GetHandleInformation函數(shù)返回句柄標(biāo)志
BOOL GetHandleInformation(
HANDLE hObject,
LPDWORD lpdwFlags
);
e.g.檢查句柄是否可繼承
DWORD dwFlags;
GetHandleInformation(hObj, &dwFlags);
BOOL fHandleIsInheritable = (0 != (dwFlags & HANDLE_FLAG_INHERIT));
3.3為對(duì)象命名
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);

HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName
);

HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCTSTR lpName
);
所有這些函數(shù)的最后一個(gè)參數(shù)都是pszName。傳入NULL,相當(dāng)于向系統(tǒng)表明我們要?jiǎng)?chuàng)建一個(gè)未命名的(即匿名)內(nèi)核對(duì)象。
要根據(jù)對(duì)象名稱來(lái)共享一個(gè)對(duì)象,我們必須為此對(duì)象指定一個(gè)名稱。傳入一個(gè)“以0為終止的名稱字符串”的地址。
//進(jìn)程A
HANDLE hMutexProcessA = CreateMutex(NULL, FALSE, TEXT("JeffMutex"));

//進(jìn)程B
HANDLE hMutexProcessB = CreateMutex(NULL, FALSE, TEXT("JeffMutex"));
當(dāng)進(jìn)程B調(diào)用CreateMutex時(shí),系統(tǒng)會(huì)查看是否存在一個(gè)名為 "JeffMutex "("JeffMutex "的對(duì)象是一個(gè)互斥量對(duì)象)的內(nèi)核對(duì)象。如果存在,接著檢查對(duì)象的類型,和調(diào)用者是否擁有該對(duì)象的完全訪問(wèn)權(quán)限。 如果答案是肯定的,系統(tǒng)就會(huì)在進(jìn)程B的句柄表中查找一個(gè)空白記錄項(xiàng),并將其初始化為指向現(xiàn)有的內(nèi)核對(duì)象;否則,返回NULL(失敗)。
也可以調(diào)用Open*函數(shù):
posted on 2009-11-26 11:06
longshen 閱讀(961)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
VC++