1、內核編程的環境
32位系統的進程可訪問的內存大小是4G,低位2G是用戶空間,高位2G是內核空間。應用程序運行在用戶態,進程空間是相互獨立的,不必擔心進程間訪問同一地址空間出錯,但是如果如果內核空間獲取的信息肯定是一樣的。
內核模式也被稱爲內核態,x86架構下R0層的代碼纔可以訪問內核空間,普通應用程序編譯出來都運行在R3層,R3層的代碼如果要調用R0層的功能,需要通過系統提供的入口來實現,調用內核API.
內核模塊也代表實際的驅動程序,內核空間是所有進程所共享的,系統進程一般是一個名爲“system”的進程,PID始終是4。windows一般都用系統進程來加載內核模塊,並不是說明內核代碼始終運行在System進程裏。
2、數據類型
基本數據類型,跟win32應用程序開發用到的基本一樣,只是重命名了。
unsigned long | ULONG |
---|---|
unsigned char | UCHAR |
unsigned int | UINT |
void | VOID |
unsigned long * | PULONG |
unsigned char * | PUCHAR |
unsigned int * | PUINT |
void * | PVOID |
絕大部分內核API的返回值類型爲NTSTATUS,取值如下:
STATUS_SUCCESS | 成功 |
---|---|
STATUS_INVALID_PARAMETER | 參數錯誤 |
STATUS_INSUFFICIENT_RESOURCES | 資源不足 |
STATUS_PENDING | 請求未決 |
STATUS_BUFFER_OVERFLOW | 緩衝長度不夠 |
STATUS_BUFFER_TOO_SMALL | 緩衝長度不夠 |
和win32應用開發的字符串不一樣,驅動開發裏的字符串使用的是一個結構裏
type struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
}UNICODE_STRING *PUNICODE_STRING;
字符串使用的是寬字符,雙字節結構。
3、重要的數據結構
驅動對象(DRIVER_OBJECT),代表一個驅動程序,或者說一個內核模塊。在Windows啓動之後,這些內核對象都在內存中,驅動對象可以通過WinObj工具查看,顯示所有的內核對象。
設備對象,設備對象是內核中的重要對象,類似於windows編程中的窗口,窗口時唯一可以接收消息的東西,任何消息都是發給一個窗口的。內核模塊中,大部分消息都以請求(IRP)的方式傳遞。設備對象(DEVICE_OBJECT)是唯一可以接收請求的實體,任何一個請求都是發送給某個設備對象的。
一個驅動程序含有一個驅動對象,一個驅動對象對應有多個設備對象。
4、函數調用
大部分內核API都有前綴,主要的函數以Io-、Ex、Rtl-、Ke、Zw-、Nt-、和Ps-開頭。
Ex開頭常用的是分配內存,獲取互斥體函數。如:ExAllocatePool、ExFreePoll、ExAcquireFastMutex、ExReleaseFastMutex、ExRaiseStatus
Zw開頭常用的是文件操作相關函數,如:ZwCreateFile、ZwWriteFile、ZwReadFile、ZwQueryDirectoryFile、ZwDeviceControlFile、ZwCreateKey、ZwQueryValueKey
Rtl開頭常用的是字符串操作相關函數,如:RtlInitUnicodeString、RtlCopyUnicodeString、RtlAppendUnicodeToString、RtlStringCbPrintf、RtlCopyMemory、RtlMoveMemory、RtlZeroMemory、RtlCompareMemory、RtlGetVersion
Io開頭的是Io管理相關函數。如:IoCreateFile、IoCreateDevice、IoCallDriver、IoCompleteRequest、IoCopyCurrentIrpStackLocationToNext、IoSkipCurrentIrpStackLocationToNext、IoGetCurrentIrpStackLocation
Ps開頭常用的是與進程、線程相關的函數,如:PsGetCurrentProcessId