一. 在驅動中使用檔案
在Windows執行體中,通過檔案對象來代表檔案,該檔案對象是一種由對象管理器管理的執行體對象。例如:目錄也是由檔案對象代表的。
核心組件通過對象名來引用檔案,即在檔案的全路徑前面加\DosDevices。(在Windows 2000及後續作業系統中,\??等同於\DosDevices)。例如,檔案C:\WINDOWS\example.txt的對象名為\DosDevices\C:\WINDOWS\example.txt。你需要用對象名來開啟檔案以擷取控制代碼。
對象名在下面會講述。
使用檔案步驟:
開啟檔案返迴文件控制代碼。
調用合適的ZwXxxFile 函數以完成對檔案的操作。
調用ZwClose函數關閉開啟的檔案控制代碼。
當開啟一個指向檔案的檔案控制代碼時,Windows執行體就建立了一個檔案對象來代表該檔案,同時返回一個代表該對象的檔案控制代碼。因此,對於單個檔案來說,會存在多個檔案對象的情況。同樣,由於使用者模式的應用程式可能會複製檔案控制代碼,因此,對於同一個檔案對象,也會存在多個檔案控制代碼。只有當所有指向一個檔案對象的檔案控制代碼都關閉後,Windows執行體才會刪除該檔案對象。
二. 對象名
核心模式的對象可以是具名的或者是無名的。對象名是一個Unicode字串,不管是使用者模式還是核心模式,都可以額用它來引用對象。例如,\KernelObjects\LowMemoryCondition是一個指示在系統中總的可用記憶體偏低的標準事件對象名稱。
使用者模式和核心模式都利用對象名來開啟指向對象的控制代碼。所有的後續操作都需要用該開啟的控制代碼來完成。
如果對象是無名的,使用者模式的組件無法開啟指向該對象的控制代碼。核心模式則不同,它可以通過指標或控制代碼來引用無名對象。
具名對象被組織成層狀結構。每個對象的命名同其父物件有關係。每個組件的對象名以反斜線開頭。例如,\KernelObjects對象是\KernelObjects\LowMemoryCondition對象的父物件。
只有某些類型的對象才擁有子物件。下面列出其中的一部分:
1. 目錄對象。對象管理器利用目錄對象管理對象,例如,\KernelObjects是一個目錄對象,它用來維護標準事件對象。目錄對象不與真實的磁碟目錄相對應。這裡,目錄的意思不是普通我們講的檔案夾目錄的意思。
2. 磁碟驅動裝置對象。這與磁碟檔案(含常規目錄)相對應。
3. 代表目錄的檔案對象。對應指定目錄下的所有檔案,此處的目錄同常規理解的目錄相同。
4. WDM驅動裝置對象,具有自己的命名空間,可以用在驅動定義的方式中。
檔案具有對象名,其命名與\DosDevices有關。例如,檔案C:\Directory\File的對象名為\DosDevices\C:\Directory\File。
下表描述了一組典型的對象名
對象名 |
描述 |
\DosDevices |
對象目錄 |
\DosDevices\C: |
代表C盤的裝置對象 |
\DosDevices\C:\Directory |
代表名為C:\Director的檔案對象 |
\DosDevices\C:\Directory\File |
代表名為C:\Directo\Filer的檔案對象 |
驅動可以在指定的對象目錄中建立具名對象
三. 開啟指向檔案的控制代碼
按如下步驟來開啟指向檔案的控制代碼:
1. 定義各一個OBJECT_ATTRIBUTES結構體變數,然後調用InitializeObjectAttributes函數初始化該變數。關鍵是設定改變數的ObjectName欄位為檔案對象名。
2. 調用IoCreateFile,
ZwCreateFile, 或者 ZwOpenFile,傳遞上面定義的結構體變數,成功就會返回執行該檔案的控制代碼。
註:驅動一般用ZwCreateFile和ZwOpenFile,IoCreateFile很少使用
當調用ZwCreateFile,ZwOpenFile或IoCreateFile時,Windows執行體建立一個代表該檔案的新的檔案對象,並返回一個指向該對象的控制代碼。檔案對象一直存在,知道你關閉了所有指向它的檔案控制代碼。
四. 使用檔案控制代碼操作檔案
下表列出了驅動中常用的利用檔案控制代碼操作檔案的函數
操作 |
函數 |
讀檔案 |
ZwReadFile |
寫檔案 |
ZwWriteFile |
讀檔案屬性 |
ZwQueryInformationFile |
設定檔案屬性 |
ZwSetInformationFile |
五. 驅動中使用檔案程式碼範例
/** @file *Copyright(C): Information Technology Co Ltd., All rights reserved.*@n*@n 檔案: MyKFile.h*@n 功能: 處理核心檔案的操作*@n 作者: aurain(zhangqiushui@gmail.com) 2009-12-31*/#ifndef __MYKFILE_H__#define __MYKFILE_H__#include "debug.h"/*** 建立或開啟檔案* @param lpFileHandle 返回開啟的檔案控制代碼指標* @param usFileName 需要開啟的檔案路徑,使用物件路徑,如\\??\\c:\test.txt* @param dwDesiredAccess 申請許可權,可以用|(或)組合以下操作寫檔案內容-FILE_WRITE_DATA,設定檔案屬性-FILE_WRITE_ATTRIBUTES,通用寫-GENERIC_WRITE讀檔案內容-FILE_READ_DATA,設定檔案屬性-FILE_READE_ATTRIBUTES,通用寫-GENERIC_READ刪除檔案-DELETE全部許可權-GENERIC_ALL同步開啟檔案-SYNCHRONIZE* @param dwShareAccess 共用方式(是指本代碼開啟這個檔案時,允許別的代碼同時開啟這個檔案所具有的許可權可以用|(或)組合以下操作共用讀-FILE_SHARE_READ共用寫-FILE_SHARE_WRITE共用刪除-FILE_SHARE_DELETE* @param dwCreateDisposition 建立或開啟檔案的目的建立檔案-FILE_CREATE開啟檔案-FILE_OPEN開啟或建立-FILE_OPEN_IF覆蓋-FILE_OVERWRITE建立或覆蓋-FILE_OVERWRITE_IF建立或取代-FILE_SUPERSEDE* @param dwCreateOptions 開啟檔案時選項設定一般用FILE_NOT_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT* @return 讀取成功: STATUS_SUCCESS;讀取失敗:NTSTATUS error code*/__inlineNTSTATUS MyCreateFile(OUT PHANDLE lpFileHandle, IN PUNICODE_STRING usFileName, IN ULONG dwDesiredAccess, IN ULONG dwShareAccess, IN ULONG dwCreateDisposition, IN ULONG dwCreateOptions){ NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; OBJECT_ATTRIBUTES oaName; IO_STATUS_BLOCK iosBlock; if (lpFileHandle != NULL && usFileName != NULL && usFileName->Buffer != NULL) { if (PASSIVE_LEVEL != KeGetCurrentIrql()) { return ntStatus; } InitializeObjectAttributes(&oaName, usFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); ntStatus = ZwCreateFile(lpFileHandle, dwDesiredAccess, &oaName, &iosBlock, NULL, FILE_ATTRIBUTE_NORMAL, dwShareAccess, dwCreateDisposition, dwCreateOptions, NULL, 0); if (!NT_SUCCESS(ntStatus)) { DEBUG_ERROR(("[MyCreateFile]ZwCreateFile(%ws)failed with error:%08x\r\n", usFileName->Buffer, ntStatus)); return ntStatus; } } return ntStatus;}/*** 關閉開啟的檔案控制代碼* @param hFile 檔案控制代碼* @return 讀取成功: STATUS_SUCCESS;讀取失敗:NTSTATUS error code*/__inlineNTSTATUS MyCloseFile(IN HANDLE hFile){ return ZwClose(hFile);}/*** 讀取檔案內容* @param hFile 檔案控制代碼* @param pBuffer 緩衝區* @param ulBufferSize 緩衝區大小* @param pulBytesRead 實際讀取的大小* @return 讀取成功: STATUS_SUCCESS;讀取失敗:NTSTATUS error code*/__inlineNTSTATUS MyReadFile(IN HANDLE hFile, IN PVOID pBuffer, IN ULONG ulBufferSize, OUT PULONG pulBytesRead){ IO_STATUS_BLOCK iosBlock; NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; if (hFile == NULL || pBuffer == NULL) { return ntStatus; } if( PASSIVE_LEVEL < KeGetCurrentIrql()) { DEBUG_ERROR(("All kernel file operating functions must running on PASSIVE_LEVEL\r\n")); return ntStatus; } *pulBytesRead = 0; ntStatus = ZwReadFile(hFile, NULL, NULL, NULL, &iosBlock, pBuffer, ulBufferSize, NULL, NULL); if (NT_SUCCESS(ntStatus)) { //擷取實際讀取到的大小 *pulBytesRead = (ULONG)iosBlock.Information; } else { DEBUG_ERROR(("[MyReadFile]ZwReadFile failed with:%08x\r\n", ntStatus)); } return ntStatus;}/*** 向檔案寫入內容* @param hFile 檔案控制代碼* @param pBuffer 緩衝區* @param ulBufferSize 緩衝區大小* @param pulBytesWrite 實際寫入的大小* @return 讀取成功: STATUS_SUCCESS;讀取失敗:NTSTATUS error code*/__inlineNTSTATUS MyWriteFile(IN HANDLE hFile, IN PVOID pBuffer, IN ULONG ulBufferSize, OUT PULONG pulBytesWrite){ IO_STATUS_BLOCK iosBlock; NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; if (hFile == NULL || pBuffer == NULL) { return ntStatus; } // All kernel file operating functions must running on PASSIVE_LEVEL if (PASSIVE_LEVEL != KeGetCurrentIrql()) { return ntStatus; } *pulBytesWrite = 0; ntStatus = ZwWriteFile(hFile, NULL, NULL, NULL, &iosBlock, pBuffer, ulBufferSize, NULL, NULL); if (NT_SUCCESS(ntStatus)) { *pulBytesWrite = (ULONG)iosBlock.Information; } else { DEBUG_ERROR(("[MyWriteFile]ZwWriteFile failed with:%08x\r\n", ntStatus)); } return ntStatus;}#endif
引用地址:http://www.cppblog.com/aurain/archive/2009/12/31/104563.html