回爐重造之重讀Windows核心編程-003-內核對象

来源:https://www.cnblogs.com/leoTsou/archive/2020/02/23/12348449.html
-Advertisement-
Play Games

內核對象是個比較難理解的概念,問題的根源就在於即使是《核心編程》書中也沒有說清楚它的定義,只是不停地舉例和描述它的性質,還有如何使用。 盲人摸象,難見全貌。只能儘可能列舉它的性質,註意使用了。 引用計數(書中的說法是使用計數)就是內核對象的一個很關鍵的性質。由於內核對象的擁有者是內核而不是進程,所以 ...


  內核對象是個比較難理解的概念,問題的根源就在於即使是《核心編程》書中也沒有說清楚它的定義,只是不停地舉例和描述它的性質,還有如何使用。

  盲人摸象,難見全貌。只能儘可能列舉它的性質,註意使用了

  引用計數(書中的說法是使用計數)就是內核對象的一個很關鍵的性質。由於內核對象的擁有者是內核而不是進程,所以只能由內核來做撤銷內核對象的操作。而通常一個內核對象不一定只被一個進程使用的,創建或者撤銷內核對象,就要看引用計數了。引用計數在內核對象被創建的時候被置為1,被進程訪問一次引用計數就遞增1。當引用計數降為0,內核就撤銷這個內核對象。(至於何時引用計數遞減1,書中沒有明確說明,不過有編程經驗的你肯定知道是什麼時候了)

  安全性也是內核對象的一個重要的性質,它用於描述內核對象的訪問者。由於創建內核對象的時候幾乎都會有一個參數,指向Security_Attributes結構體的指針,例如CreateFileMapping(定義不詳)。如果這個指針是NULL值,那就是預設的安全性,只有管理對象的小組成員和創建者可以訪問;不過,只要你初始化並操作lpSecurityDescriptor這個成員,就可以設置它的安全性了。這樣,內核對象被訪問的時候(例如OpenFileMapping),在返回一個有效的句柄之前會執行一次安全檢查,如果不通過檢查返回的就不是一個有效句柄,而是NULL了,它的LastError是5(ERROR_ACCESS_DENIED)。

  進程的內核對象句柄表,在進程被創建的時候被分配。當線程共有內核對象產生的時候,內核會在句柄表中找出一個空項,把內核對象的記憶體塊指針寫進去。

  如果一個線程中調用函數返回一個句柄,這個句柄可以也只可以被線程中的所有線程使用。這些句柄的值實際上是句柄在當前進程句柄表中的索引,但不是固定的,如在Win2k中返回的句柄是用於標識句柄表的該對象的位元組數。如果給句柄表中傳入一個無效值,GetLastError則會返回6(ERROR_INVALID_HANDLE)。

  如果調用函數創建內核對象失敗了,那麼句柄的值通常是0(NULL),也有些函數返回的是INVALID_HANDLE_VALUE。但是無論用什麼方式創建內核對象,都要通過CloseHandle來結束對對象的操作。這個函數會先檢查句柄表,確定傳入的索引是否有效,並查看引用計數,如果是0則撤銷這個對象。

  一個無效的句柄傳給CloseHandle的話,GetLastError會返回ERROR_INVALID_HANDLE。如果進程正在被調試,則通知調試器,以確定這個錯誤。

  加入忘記調用CloseHandle,有可能會產生資源泄漏。因為進程終止的時候,系統會掃描它的句柄表中的無效項目,然後關閉這些對象句柄。這時句柄的引用計數就有機會降為0而被撤銷了。

  當進程間有父子關係的時候,父進程才有機會使用一個或多個內核對象句柄,並且父進程還可以產生一個可以訪問這個內核對象的子進程。步驟如下:

  • 父進程創建內核對象時,必須指明這個句柄可以被繼承。(不是內核對象本身可以被繼承)
  • 指定一個SECURITY_ATTRIBUTES結構並對它進行初始化,然後把結構的地址傳給Create函數。
  • sa.bInheritHandle = TRUE;

  每個句柄表項中都有一個標誌位,用以指明這個句柄是否有繼承性。如果是bInheritHandle屬性是TRUE,標誌位被置1,否則置0。

   此後只要調用CreateProcess中的參數bInheritHandle是TRUE,那麼被創建的進程就在創建空的句柄表的同時,遍歷父進程的句柄表找到有繼承屬性的項目,並拷貝到新的句柄表中完全相同的位置、遞增引用計數。這樣即使父進程關閉了這個句柄,由於引用計數還沒到0,也要等子進程終止的時候才能置零。這樣子進程只要知道句柄的值就可以使用了。

  改變句柄的標誌,可以使用SetHandleInformation,第一個參數是句柄,第二個參數就確定修改哪些標誌了。和每個句柄相關的就是HANDLE_FLAG_INHERITHANDLE_FLAG_PROJECT_FROM_CLOSE了。第三個參數dwFlags,可以用於指明內核對象的繼承標誌:

  • 打開繼承標誌:SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
  • 關閉繼承標誌:SetHandleInformation(hObj, HANDLE_FLAG_INHERIT, 0);

  使用SetHandleInformation(hObj, HANDLE_FLAG_PROJECT_FROM_CLOSE, HANDLE_FLAG_PROJECT_FROM_CLOSE),會告訴系統這個句柄不應該被關閉,如果關閉則會產生一個異常。只有一種特殊的情況,就是子進程又產生了子進程,而有繼承屬性的句柄也有可能會被傳遞到新的子進程。但是舊的子進程有可能在新的子進程生成之前關閉這個句柄,那麼父進程就不能和新的子進程通信了,因為沒有繼承這個內核對象。這種情況下,告訴系統句柄不應該關閉才有意義

  跨進程共用內核對象的第二種方法是給對象命名。

  1. 進程A創建了一個名字為“JeffMutex”的互斥內核對象。
  2. 進程B也創建一個名字為“JeffMutex”的互斥內核對象,系統會有以下操作:
    1. 查看是否已經有同名的內核對象
      1. 如果同名,就檢查同名內核對象的類型。
        1. 如果類型也相同,系統會查看調用者的訪問許可權。
          1. 如果有就找個空項目,初始化再指向現有的內核對象
          2. 沒有許可權則返回NULL。
        2. 如果類型不匹配,返回NULL。
      2. 不同名就創建新的內核對象。
    2. 沒有就創建新的內核對象。

  進程B調用函數成功後,不是返回一個內核對象,而是返回一個和進程相關的句柄值。

  按名字共用的另一種方法是不使用Create*函數,而是Open*函數。原型相同。最後一個參數必須是0結尾的地址,不能傳遞NULL。如果不存在,GetLastError返回值是2(ERROR_FIEL_NOT_FOUND)。還得檢查訪問許可權,如果有就把引用計數遞增1。

  為了保證對象的唯一性,建議創建GUID用來當作對象的名字。這種方法也多用於檢查你的應用程式有另一個進程正在運行。

  跨進程共用內核對象的最後一個方法是使用DuplicateHandle函數。簡單地說,這個函數只是取出這個進程的句柄表中的一項,拷貝到另一個進程的句柄表中。

  DuplicateHandle的參數雖然多,但不複雜。既然是複製句柄,自然少不了源進程和源句柄,以及目標進程和目標句柄了,設計句柄,就得有它的屏蔽值與繼承性,這裡給了三個。前四個參數不難理解,只是後面的參數要註意:

  • dwOption參數可以是0,也可以是DUPLICATE_SAME_ACCESSDUPLICATE_CLOSE_SOURCE
  • 如果設定了DUPLICATE_SAME_ACCESS,則目標進程的句柄擁有相同的訪問屏蔽,並讓函數忽略dwDesiredAccess參數。
  • 如果設定DUPLICATE_CLOSE_SOURCE,則可以關閉源進程中的句柄。使用該標誌時,內核對象的引用計數不會受到影響。

  最後書中的例子提到,使用DuplicateHandle函數的時候,dwDesiredAccess參數應該設置為只讀(FILE_MAP_READ),這樣就可以不影響源進程的句柄,提高健壯性。

  

DUPLICATE_CLOSE_SOURCE


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝PuTTY時自動安裝了PSFTP 使用PSFTP可以實現Winodws、Linux之間的文件傳輸。 打開PSFTP,輸入Linux的ip地址,輸入要登錄的用戶名、密碼 open Linux的ip地址 Windows向Linux傳文件: put D:\jdk-8u241-linux-x64.rpm ...
  • 頁式存儲管理 頁式存儲管理的基本原理 分頁存儲器將主存劃分成多個大小相等的頁架,受頁架尺寸限制,程式的邏輯地址也自然分成頁,不同的頁可以放在不同頁架中,不需要連續,頁表用於維繫進程的主存完整性 頁式存儲管理中的地址 頁式存儲管理的邏輯地址由兩部分組成,頁號和單元號,邏輯地址形式:頁號,單元號 頁式存 ...
  • Shell腳本命令的工作方式有兩種: 互動式(Interactive):用戶每輸入一條命令就立即執行。 批處理(Batch):由用戶事先編寫好一個完整的Shell腳本,Shell會一次性執行腳本中諸多的命令。 一、編寫簡單的腳本 一個Shell腳本主要由三部分組成:腳本聲明、腳本註釋、腳本命令。 腳 ...
  • Yarn 對你的代碼來說是一個包管理器, 你可以通過它使用全世界開發者的代碼, 或者分享自己的代碼。Yarn 做這些快捷、安全、可靠,所以你不用擔心什麼。通過Yarn你可以使用其他開發者針對不同問題的解決方案,使自己的開發過程更簡單。 使用過程中遇到問題,你可以將其上報或者貢獻解決方案。一旦問題被修 ...
  • 方式一可以官方下載,安裝使用方式二使用 RT-Thread env工具,其中集成了scons工具env工具配置打開設置添加到右鍵菜單使用scons生成mdk5工程> scons --target=mdk5使用scons編譯> scons ...
  • 單片機的學習情況: 目 錄 第一講 初識、試用單片機……………………………..….……..… 第二講 讓 LED 舞起來……………………………………….……. 第三講 “開挖”單片機…………………………………….….….. 第四講 藉助定時器的單片機輸入輸出控制……………………… 第五講 八段數位管 ...
  • >test.txt set /p="Hello" <nul >>test.txt set /p=" world!" <nul 正文 平時,CMD中輸出一個字元串到文本文件,可使用echo,配合輸出重定向實現: echo "line1" > test.txt echo "line2" >> test. ...
  • 內核體系設計分:單內核,微內核 windows是微內核設計。 Linux是單內核設計,但充分借鑒了為微內核體系的優點,為內核引入了模塊化機制。 內核的組成部分 kernel:內核核心,一般為bz壓縮的image文件,通常位於/boot目錄,名稱為vmlinuz VERSION release ker ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...