什麼是核心(kernel)對象?

來源:互聯網
上載者:User
 

        作為一個軟體開發人員,你會建立,開啟,操作核心對象。系統會建立和操作多種類型的核心對象,例如access token 對象, event 對象,file對象,file-mapping對象,I/O完成連接埠對象,job對象,mailslot對象,mutex對象,pipe對象,process對象,semaphore對象,thread對象,waitable time對象,和threa pool worker factory對象.有一個自由的WinObj工具允許你看到所有的核心對象列表。(地址為:http://www.microsoft.com/technet/sysinternals/utilities/winobj.mspx)

        注意你必須在Administrator下運行他,通過Windows Explorer你能看到它的列表。

 

        這些對象通過調用各式各樣的函數來建立,對象名不必映射到kernel層級上使用的對象的類型上。例如:CreateFileMapping函數使系統建立了一個與Section對象相關的檔案對應,正如你在WinObj中看到的。每個核心對象只是被核心分配的一塊記憶體塊。但只有核心可以訪問。這個記憶體塊是一個成員包括對象的主要資訊的資料結構。一些成員(安全描述,引用計數,等等)對所有的物件類型來說是一樣的。但是大多數是針對專門的類型。例如,一個process對象有有一個process ID,一個基本的優先順序,和一個結束碼,在什麼地方有位元組位移,共用模式,開啟模式。

        因為核心對象資料結構僅僅可以被核心訪問,所以一個應用程式就無法在記憶體中定位這些資料結構以及直接改變它的內容。Microsoft 強制使用這種限制是為了使核心對象結構保持一致性。這種限制也允許Microsoft增加,移除和改變這些結構的成員而不用破壞任何應用程式。

        如果我們不能直接改變這些結構,那麼我們的應用程式該怎麼控制這些核心對象呢?回答是Windows提供了一套函數用來控制這些結構。這些核心對象總是經過這些函數訪問。當你調用一個函數建立一個核心對象的時候,函數返回了一個標識這個對象的控制代碼。設想這個控制代碼可以作為一個透明值而被進程裡的所有線程使用。控制代碼是在32位的Windows系統中是32位的值,在64位的系統中是64位的值。你傳遞這個控制代碼給各個Windows函數以便系統知道哪一個核心對象你想去控制。

        為了使作業系統更健壯,這些控制代碼的值是進程相關的。所以如果你傳遞這個控制代碼到另外一個進程內的線程(用一些處理序間通訊的方式),別的進程使用這個進程控制代碼可能失敗,更糟糕的是,他們會建立一個完全不同的核心對象的引用。

        使用計數

        核心對象被核心擁有,而不是被進程擁有。也就是說,如果你的進程建立了一個調用核心對象的函數然後你的進程結束,核心對象不必銷毀,在大多數的環境裡,對象將被銷毀;但是如果另一個進程正在使用你的進程建立的核心對象,核心會等到另外的進程停止使用它,然後再銷毀它。需要記住的是核心對象比建立它的進程更持久。

        核心知道有多少進程正在使用一個核心對象是因為每個對象包含一個引用計數。引用計數通常是所有的核心對象的一個資料成員。當一個對象第一次被建立,它的引用計數被設為一。當另一個進程訪問一個已經存在的核心對象時,使用計數被增加。當一個進程結束時,核心自動減少所有進程仍然開啟的核心對象的引用計數。如果對象的引用計數變為0,核心銷毀這個對象。這確保沒有進程引用對象的時候系統中就不會有核心對象。

        安全

        核心對象可以用一個安全性描述元來表示,安全性描述元描述誰擁有對象(通常是他的建立者),哪個組或使用者能有權訪問或者使用對象,哪個組或使用者無權訪問對象。在寫服務程式的時候通常要用到安全描述。然而,在Microsoft Windows Vista中,對擁有私人命名空間的用戶端應用程式,這個特徵變的更加明顯。

        儘管所有的函數建立核心對象的時候都有一個指向SECURITY_ATTRIBUTES結構的參數,就象下面這個函數顯示的:

        HANDLE CreateFileMapping(
                       HANDLE hFile,
                       PSECURITY_ATTRIBUTES psa,
                       DWORD flProtect,
                       DWORD dwMaximumSizeHigh,
                       DWORD dwMaximumSizeLow,
                       PCTSTR pszName);

        大多數的應用程式只是簡單的傳遞一個NULL到這個參數,這樣對象通過預設的安全建立,這個安全是建立在當前的進程安全符上。然而,你可以分配一個SECURITY_ATTRIBUTES結構,初始化它,並且傳遞這個結構的地址,一個SECURITY_ATTRIBUTES結構看起來象下面一樣:

typedef struct _SECURITY_ATTRIBUTES {   DWORD nLength;   LPVOID lpSecurityDescriptor;   BOOL bInheritHandle;} SECURITY_ATTRIBUTES;

 

        儘管這個結構被叫作SECURITY_ATTRIBUTES,它實際上只包括一個成員去做與安全相關的所有事情:lpSecurityDescriptor.如果你想要限定對你建立的核心的訪問,你必須建立一個安全描述並且初始化SECURITY_ATTRIBUTES 結構:

SECURITY_ATTRIBUTES sa;sa.nLength = sizeof(sa);         // Used for versioningsa.lpSecurityDescriptor = pSD;   // Address of an initialized SDsa.bInheritHandle = FALSE;       // Discussed laterHANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,   PAGE_READWRITE, 0, 1024, TEXT("MyFileMapping"));

 

當你想要訪問已存在的核心對象時,你必須指定在對象上視圖執行的操作。例如,如果我想要獲得一個訪問已存在的filemapping核心對象的許可權去從它那讀取資料,我可以調用OpenFileMapping,

HANDLE hFileMapping = OpenFileMapping(FILE_MAP_READ, FALSE,   TEXT("MyFileMapping"));

通過傳遞FILE_MAP_READ 作為第一個參數,我能指出在我獲得許可權後我要從檔案對應中讀。OpenFileMapping函數在返回控制代碼之前首先要進行一個安全檢測。如果我被允許訪問已經存在的檔案對應核心對象,OpenFileMapping 返回一個安全控制代碼。然而,如果我沒有許可權,OpenFileMapping 返回NULL並且從GetLastError會返回(ERROR_ACCESS_DENIED).不要忘了如果返回的控制代碼被用來調用需要與FILE_MAP_READ不同許可權的API,同樣會產生禁止訪問的錯誤。

        儘管許多應用程式不需要包含安全,但是許多Windows函數需要你傳遞訪問資訊的安全描述。許多為以前版本設計的應用程式不能在Windows Vista下工作的原因就是當應用程式執行的時候缺少一些安全資訊。

        例如,假設一個應用程式啟動,讀取一些註冊鍵的資料。這時候你的代碼就需要調用RegOpenKeyEx,並且傳遞KEY_QUERY_VALUE到訪問描述。

        然而,許多的應用程式最初都是為早期版本的Windows2000作業系統開發的,沒有考慮任何安全。一些軟體開發人員可能調用RegOpenKeyEx的時候,傳遞的是KEY_ALL_ACCESS作為訪問描述開發人員使用它的原因是解決起來更簡單,並且不需要開發人員真正的去考慮要進行那種訪問。問題是註冊子鍵,例如HKLM可能是唯讀,不可以寫,對於非Administrator使用者來說。當這樣一個應用程式運行在Windows Vista上時,調用RegOpenKeyEx時用KEY_ALL_ACCESS會失敗。並且沒有恰當的錯誤偵測,可能會產生不可預知的結果。

        如果開發人員考慮到安全,只需要簡單的將KEY_ALL_ACCESS改為KEY_AUERY_VALUE(這個例子中必須這樣),那麼就能在所有的作業系統下運行。

        忽略合適的安全訪問標識是開發中的最大錯誤。使用合適的標識將使他更容易相容各種版本的Windows系統。然而,你也需要認識到每個新的Windows版本帶來的新的約束限制。例如,在Windows Vista,你需要小心User Account Control(UAC)特徵,UAC強迫應用程式運行在一個受限的安全層級下,儘管當前的使用者是Administrator組的一部分。

        另外,除了使用核心對象外,你的應用程式可能要使用其他的物件類型,例如menus,windows,游標,畫刷和字型,這些對象是使用者物件或者圖形使用者介面,而不是核心對象。當你第一回使用Windows編寫程式的時候,你可能無法區別開使用者物件和核心對象。例如,icon是一個使用者物件還是一個核心對象?識別一個對象是核心對象的最簡單的方法是檢測建立對向的函數。幾乎所有建立核心對象的函數都有一個參數來允許你設定安全屬性資訊,就像CreateFileMapping函數在前面展示的。

        沒有一個建立使用者和GDI對象的函數有SECURITY_ATTRIBUTES參數。例如,看下面的CreateIcon函數:

HICON CreateIcon(   HINSTANCE hinst,   int nWidth,   int nHeight,   BYTE cPlanes,   BYTE cBitsPixel,   CONST BYTE *pbANDbits,   CONST BYTE *pbXORbits);

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.