Windows內核對象(2) -- 內核對象跨進程訪問

      網友投稿 1014 2025-03-31

      雖然內核對象位于獨立于進程之外的內核區(qū)域,我們在開發(fā)中卻只能通過調用Win32 API傳入HANDLE參數來操作內核對象(如SetEvent等)。然而HANDLE句柄只對當前進程有效,離開了當前進程該句柄就無效了(具體原因參考:Windows內核對象(1) – 內核對象與句柄)。所以說,跨進程訪問內核對象的關鍵在于我們怎么跨進程訪問句柄HANDLE?


      下面介紹幾種方法來實現跨進程共享內核對象。

      一、使用句柄繼承的方式

      只有進程之間有父子關系時,才可以使用句柄繼承的方式。在這種情況下,父進程可以生成一個子進程,并允許子進程訪問父進程的內核對象。為了使這種繼承生效,父進程必須執(zhí)行幾個步驟:

      (1). 父進程在創(chuàng)建一個內核對象時,父進程必須向系統指定它希望這個內核對象的句柄是可以繼承的。為了創(chuàng)建一個可繼承的內核對象,必須分配并初始化一個SECURITY_ATTRIBUTES結構,如:

      SECURITY_ATTRIBUTES?sa; sa.nLength?=?sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle?=?TRUE;??//?可繼承的 sa.lpSecurityDescriptor?=?NULL; HANDLE?h?=?CreateEvent(&sa,?TRUE,?FALSE,?NULL);

      (2). 父進程通過CreateProcess生成子進程,且指定bInheritHandles為TRUE,從而允許子進程來繼承父進程的那些“可繼承的句柄”。

      //?啟動子進程TestB.exe,將句柄h作為啟動參數傳給進程TestB // TCHAR?cmd_buf[MAX_PATH]; StringCchPrintf(cmd_buf,?MAX_PATH,?TEXT("TestB.exe?%ld"),?(long)h); STARTUPINFO?si?=?{?sizeof(si)?}; PROCESS_INFORMATION?pi; BOOL?ret?=?CreateProcess( NULL,? cmd_buf,? NULL,? NULL,? TRUE,??//?指定子進程可以繼承父進程的“可繼承句柄” 0,? NULL,? NULL,? &si,? &pi ); CloseHandle(pi.hProcess); CloseHandle(pi.hThread);

      由于我們傳給bInheritHandles參數的值是TRUE,所以系統在創(chuàng)建子進程時會多做一件事情:它會遍歷父進程的句柄表,對它的每一項進行檢查,凡是包含一個有效的“可繼承的句柄”的項,都會將該項完整的復制到子進程的句柄表。在子進程的句柄表中,復制項的位置與它在父進程句柄表中的位置完全一樣(包含索引),這個就意味著:在父進程和子進程中,對一個內核對象進行標識的句柄值也是完全一樣的。所以我們只需要通過某種方式(如上面示例中的啟動參數的方式,或者環(huán)境變量的方式等任何進程間通訊的方式)將這個值告訴子進程,子進程就可以將該值轉成HANDLE,然后使用這個HANDLE來調用系統API。

      二、使用DuplicateHandle方式

      明白DuplicateHandle的工作原理,需要先了解進程句柄表,可以參考Windows內核對象(1) – 內核對象與句柄)

      2.1 DuplicateHandle功能

      DuplicateHandle函數可以將指定“源進程的句柄表”中的某一項復制到“目的進程句柄表”中(除了索引),并且返回該項在目的進程句柄表中的索引(即HADNLE)。

      可以在任何時候調用DuplicateHandle函數,DuplicateHandle對源句柄是否是可繼承的沒有要求。

      函數聲明如下:

      BOOL?DuplicateHandle( ??HANDLE?hSourceProcessHandle, ??HANDLE?hSourceHandle, ??HANDLE?hTargetProcessHandle, ??LPHANDLE?lpTargetHandle, ??DWORD?dwDesiredAccess, ??BOOL?bInheritHandle, ??DWORD?dwOptions );

      DuplicateHandle詳細介紹可以參考MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx

      2.2 支持的句柄類型

      DuplicateHandle函數不能復制所有類型的句柄,只能復制如下類型的句柄(從MSDN復制而來):

      不同的事件類型對應的dwDesiredAccess參數不同,具體參考MSDN。

      Windows內核對象(2) -- 內核對象跨進程訪問

      2.3 使用示例

      進程TestA源碼

      int?main(int?argc,?char**?argv)?{ HANDLE?h?=?CreateEvent(NULL,?TRUE,?FALSE,?NULL); //?啟動子進程TestB.exe // TCHAR?cmd_buf[MAX_PATH]; StringCchPrintf(cmd_buf,?MAX_PATH,?TEXT("D:\\TestB.exe"),?(long)h); STARTUPINFO?si?=?{?sizeof(si)?}; PROCESS_INFORMATION?pi; BOOL?ret?=?CreateProcess(NULL,?cmd_buf,?NULL,?NULL,?TRUE,?0,?NULL,?NULL,?&si,?&pi); assert(ret); assert(pi.hProcess); HANDLE?duplicated_h?=?NULL; ret?=?DuplicateHandle(GetCurrentProcess(),?h,?pi.hProcess,?&duplicated_h,?0,?FALSE,?DUPLICATE_SAME_ACCESS); WaitForSingleObject(pi.hProcess,?INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); bool?has_signal?=?WaitForSingleObject(h,?0)?==?WAIT_OBJECT_0; assert(has_signal?==?true); return?0; }

      子進程TestB源碼

      int?main(int?argc,?char**?argv) { long?l?=?0; printf("Input?Handle:"); scanf("%ld",?&l); HANDLE?h?=?(HANDLE)l; bool?has_signal?=?WaitForSingleObject(h,?0)?==?WAIT_OBJECT_0; assert(has_signal?==?false); SetEvent(h); ????return?0; }

      在父進程TestA中創(chuàng)建一個不可繼承的事件 -> 然后啟動子進程TestB -> 調用DuplicateHandle復制句柄項到TestB進程句柄表 -> 并向TestB輸入句柄值 -> TestB訪問該事件句柄,將事件置為有信號狀態(tài)。

      三、使用命名的內核對象的方式

      3.1 實現原理

      這種方式嚴格的說已經不是文章開頭說到的跨進程訪問句柄了,有點類似跨進程直接訪問內核對象了。

      該方式實現起來比較簡單,就是在調用創(chuàng)建內核對象的Create***函數時,通過pszName參數為內核對象取一個名字。

      如創(chuàng)建事件Event的函數CreateEvent:

      HANDLE?WINAPI?CreateEvent( ??LPSECURITY_ATTRIBUTES?lpEventAttributes, ??BOOL?bManualReset, ??BOOL?bInitialState, ??LPCTSTR?lpName??//?指定名稱 );

      HANDLE?h?=?CreateEvent(NULL,?TRUE,?FALSE,?TEXT("TestA_Obj"));

      若在其他進程中要訪問這個內核對象,只需要使用打開函數Open***打開該內核對象,系統就會在進程的句柄表中插入一條記錄,并返回這條記錄的索引,也就是句柄。需要注意的是,在打開內核對象時需要留意返回值和GetLastError函數的返回值。由于內核對象是有訪問權限的,有時候雖然這個名字的內核對象存在,但該進程卻不見得有權限可以打開它,這個時候GetLastError函數會返回失敗的原因。

      以打開事件的函數OpenEvent為例:

      HANDLE?h?=?OpenEvent(READ_CONTROL,?FALSE,?TEXT("TestA_Obj")); if?(h?==?NULL)?{ if?(GetLastError()?==?ERROR_ACCESS_DENIED)?{?//?沒有READ_CONTROL權限 } }

      3.2 全局命令空間

      不同的會話(Session)有不同的內核對象命名空間(如windows服務程序位于Session 0,而普通的用戶進程位于Session 1),要通過名稱訪問其他會話中的內核對象,需要在名稱前面加上Session\<當前會話ID>。Windows提供了一個全局的內核對象命名空間,處于任何會話中的進程都可以訪問該命名空間,將內核對象放入全局命令空間的方式很簡單:只需要在內核對象名稱前加入Global\即可。

      如:

      HANDLE?h?=?CreateEvent(NULL,?TRUE,?FALSE,?TEXT("Global\\TestA_Obj"));

      windows

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel甘特圖制作方法(excel怎么制作甘特圖)
      下一篇:物聯網預測性維護會給制造業(yè)帶來什么
      相關文章
      亚洲综合视频在线| 亚洲一区AV无码少妇电影☆| 亚洲中文字幕第一页在线| 精品国产亚洲AV麻豆| 亚洲人成激情在线播放| 亚洲精品一卡2卡3卡三卡四卡| 久久亚洲一区二区| 亚洲91av视频| 亚洲天堂男人天堂| 亚洲永久永久永久永久永久精品| 亚洲成年轻人电影网站www | 狠狠色伊人亚洲综合网站色| 亚洲综合丁香婷婷六月香| 99999久久久久久亚洲| 在线观看亚洲AV日韩AV| 亚洲欧美日韩国产成人| 久久久久亚洲国产AV麻豆| 久久亚洲AV成人无码国产最大| www.亚洲色图| jlzzjlzz亚洲乱熟在线播放| 亚洲一本大道无码av天堂| 国产亚洲精久久久久久无码77777| 最新精品亚洲成a人在线观看| 在线A亚洲老鸭窝天堂| 亚洲AV综合色区无码一区| 久久亚洲精品中文字幕无码| 亚洲五月六月丁香激情| 亚洲综合激情六月婷婷在线观看| 亚洲毛片无码专区亚洲乱| 中中文字幕亚洲无线码| 蜜桃传媒一区二区亚洲AV| 国产精品V亚洲精品V日韩精品| 国产亚洲情侣一区二区无| 亚洲av最新在线网址| 亚洲字幕在线观看| 国产亚洲国产bv网站在线| 国产精品亚洲а∨无码播放麻豆 | 亚洲精品视频免费| 国产成人精品日本亚洲| 精品日韩亚洲AV无码| 456亚洲人成在线播放网站|