Windows内核函数
字符串處理
在驅(qū)動中一般使用的是ANSI字符串和寬字節(jié)字符串,在驅(qū)動中我們?nèi)匀豢梢允褂肅中提供的字符串操作函數(shù),但是在DDK中不提倡這樣做,由于C函數(shù)容易導致緩沖區(qū)溢出漏洞,針對字符串的操作它提供了一組函數(shù)分別用來處理ANSI字符串和UNICODE字符串。
針對兩種字符串,首先定義了它們的結(jié)構(gòu)體
對于這兩個字符串的打印,可以使用%wZ打印UNICODE_STRING用%Z打印ANSI_STRING
字符串的初始化
VOID RtlInitAnsiString(IN OUT PANSI_STRING DestinationString,IN PCSZ SourceString);VOID RtlInitUnicodeString(IN OUT PUNICODE_STRING DestinationString,IN PCWSTR SourceString);這兩個函數(shù)只是簡單的將SourceString 的首地址賦值給Buffer成員,并初始化相關的長度,所以在使用時需要考慮緩沖的生命周期,權(quán)限,同時如果我們改變SourceString 里面存儲的字符串,那么對應的UNICODE_STRING 或者ANSI_STRING中的值也會改變,比如下面的代碼
RtlInitUnicodeString(&uTest, L"Hello World"); RtlCopyMemory(uTest.Buffer, L"Test");由于Buffer指向的是不可修改的常量內(nèi)存部分,所以后面試圖修改它的時候會造成程序崩潰。
void InitString(&pUnicodeString) {WCHAR szBuf[255] = L"Hello world";RtlInitUnicodeString(pUnicodeString, szBuffer); } void test() {UNICODE_STRING uTest;InitString(&uTest);//后面的操作 }我們在另外一個函數(shù)中利用局部變量來初始化這個字符串的時候由于當函數(shù)調(diào)用完成,函數(shù)中局部變量被銷毀,這個時候指向的那塊內(nèi)存可能已經(jīng)被其他函數(shù)所占用,而我們后面通過操作UNICODE_STRING,又要操作這段內(nèi)存,這個時候一定會出現(xiàn)問題,所以一般如果要在多個函數(shù)中使用這個UNICODE_STRING時一般申請一段堆內(nèi)存,但是在使用完成后一定要記得自己回收這段內(nèi)存,否則會造成內(nèi)存泄露,對此DDK專門提供了一組函數(shù)來銷毀字符串中的堆內(nèi)存
VOID RtlFreeAnsiString(IN PANSI_STRING AnsiString);VOID RtlFreeUnicodeString(IN PUNICODE_STRING UnicodeString);字符串拷貝:
VOID RtlCopyString(IN OUT PSTRING DestinationString,IN PSTRING SourceString OPTIONAL);VOID RtlCopyUnicodeString(IN OUT PUNICODE_STRING DestinationString,IN PUNICODE_STRING SourceString);字符串比較
LONG RtlCompareString(IN PSTRING String1,IN PSTRING String2,BOOLEAN CaseInSensitive//是否忽略大小寫);LONG RtlCompareUnicodeString(IN PUNICODE_STRING String1,IN PUNICODE_STRING String2,IN BOOLEAN CaseInSensitive);字符串轉(zhuǎn)化為大寫
VOID RtlUpperString(IN OUT PSTRING DestinationString,IN PSTRING SourceString);NTSTATUS RtlUpcaseUnicodeString(IN OUT PUNICODE_STRING DestinationString,IN PCUNICODE_STRING SourceString,IN BOOLEAN AllocateDestinationString//是否要求該函數(shù)自行為輸出參數(shù)分配內(nèi)存);這兩個函數(shù)在調(diào)用是目標字符串和源字符串可以是同一個字符串
字符串與整形數(shù)字之間的轉(zhuǎn)化可以使用函數(shù)
ANSI與UNICODE字符串的相互轉(zhuǎn)化可以使用下面的函數(shù)
NTSTATUS RtlUnicodeStringToAnsiString(IN OUT PANSI_STRING DestinationString,IN PUNICODE_STRING SourceString,IN BOOLEAN AllocateDestinationString);NTSTATUS RtlAnsiStringToUnicodeString(IN OUT PUNICODE_STRING DestinationString,IN PANSI_STRING SourceString,IN BOOLEAN AllocateDestinationString);文件操作
創(chuàng)建或者打開一個文件
文件的創(chuàng)建和打開都是使用函數(shù)ZwCreateFile
NTSTATUS ZwCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG CreateDisposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength);| FILE_SUPERSEDE | 新建一個文件替代 | 新建文件 |
| FILE_CREATE | 返回一個錯誤 | 創(chuàng)建文件 |
| FILE_OPEN | 打開文件 | 返回一個錯誤 |
| FILE_OPEN_IF | 打開文件 | 創(chuàng)建文件 |
| FILE_OVERWRITE | 打開,并且將之前的內(nèi)容覆蓋 | 返回錯誤 |
| FILE_OVERWRITE_IF | 打開,并且將之前的內(nèi)容覆蓋 | 創(chuàng)建文件 |
9. CreateOptions打開或者創(chuàng)建文件時的附加操作,一般給FILE_SYNCHRONOUS_IO_NONALERT
10. EaBuffer指向擴展空間的指針
11. EaLength擴展空間的大小
這個函數(shù)與應用層的CreateFile不同的時,在指定打開或者創(chuàng)建文件名時是使用結(jié)構(gòu)OBJECT_ATTRIBUTES來指定,針對這個結(jié)構(gòu),有一個函數(shù)能夠初始化它
Attributes:該對象的描述信息,一般給OBJ_CASE_INSENSITIVE 表示對大小寫敏感
RootDirectory :該文件的根目錄,一般給NULL
SecurityDescriptor :安全描述符,一般也是給NULL
另外這里的名稱必須使用符號鏈接名或者設備名,而不是我們熟悉的“C:\”這種形式對于C盤可以使用名稱“\??\C”或者“\Device\HarddiskVolum1”這種形式
當程序結(jié)束時需要調(diào)用ZwClose來清理文件句柄這個函數(shù)的參數(shù)比較簡單,只是簡單的傳入文件句柄即可
獲取和設置文件的相關信息
可以下面兩個函數(shù)分別獲取和設置文件的相關信息
NTSTATUS ZwQueryInformationFile(IN HANDLE FileHandle,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID FileInformation,IN ULONG Length,IN FILE_INFORMATION_CLASS FileInformationClass);NTSTATUS ZwSetInformationFile(IN HANDLE FileHandle,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PVOID FileInformation,IN ULONG Length,IN FILE_INFORMATION_CLASS FileInformationClass);其中FileInformationClass是一個枚舉值,根據(jù)這個值得不同F(xiàn)ileInformation可以被解析成不同的內(nèi)容。
1. 當這個參數(shù)為FileStandardInformation時,使用結(jié)構(gòu)體FILE_STANDARD_INFORMATION
其中時間參數(shù)是一個LARGE_INTEGER類型的整數(shù),代表從1601年到現(xiàn)在經(jīng)過多少個100ns。文件屬性參數(shù)如果為FILE_ATTRIBUTE_DIRECTORY表示這是一個目錄文件,FILE_ATTRIBUTE_NORMAL表示是一個普通文件,FILE_ATTRIBUTE_HIDDEN表示這是一個隱藏文件,FILE_ATTRIBUTE_SYSTEM表示這是一個系統(tǒng)文件,FILE_ATTRIBUTE_READONLY表示這是一個只讀文件
3. 當這個參數(shù)為FileNameInformation時,使用結(jié)構(gòu)體FILE_NAME_INFORMATION
讀寫文件
寫文件調(diào)用函數(shù)ZwCreateFile
NTSTATUS ZwWriteFile(IN HANDLE FileHandle,//文件句柄IN HANDLE Event OPTIONAL,//時間對象一般給NULLIN PIO_APC_ROUTINE ApcRoutine OPTIONAL,//一般給NULLIN PVOID ApcContext OPTIONAL,//一般給NULLOUT PIO_STATUS_BLOCK IoStatusBlock,//記錄寫操作的狀態(tài)用里面的Information成員記錄實際寫了多少字節(jié)IN PVOID Buffer,//寫入文件中緩沖區(qū)的指針IN ULONG Length,//緩沖區(qū)中數(shù)據(jù)的長度IN PLARGE_INTEGER ByteOffset OPTIONAL,//從文件的多少地址開始寫IN PULONG Key OPTIONAL//一般給NULL);讀文件使用函數(shù)ZwReadFile
NTSTATUS ZwReadFile(IN HANDLE FileHandle,//文件句柄IN HANDLE Event OPTIONAL,//一般給NULLIN PIO_APC_ROUTINE ApcRoutine OPTIONAL,//一般給NULLIN PVOID ApcContext OPTIONAL,//一般給NULLOUT PIO_STATUS_BLOCK IoStatusBlock, //讀取的字節(jié)數(shù)保存在結(jié)構(gòu)的成員Information中OUT PVOID Buffer,//緩沖區(qū)的指針IN ULONG Length,//緩沖區(qū)的長度IN PLARGE_INTEGER ByteOffset OPTIONAL,//從文件的多少位置開始讀IN PULONG Key OPTIONAL//一般給NULL);注冊表操作
注冊表中有下面幾個概念:
1. 注冊表項:注冊表項類似于目錄的概念,下面可以有子項或者注冊表的鍵-值對
2. 注冊表子項:類似于子目錄的概念
3. 鍵名:通過鍵名可以尋找到相應的鍵值
4. 鍵值類別:每個鍵值在存儲的時候有不同的類型,相當于變量的類型,主要有字符串和整型
5. 鍵值:鍵名下對應存儲的數(shù)據(jù)
創(chuàng)建和關閉注冊表
創(chuàng)建注冊表使用函數(shù)ZwCreateKey
NTSTATUS ZwCreateKey(OUT PHANDLE KeyHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN ULONG TitleIndex,IN PUNICODE_STRING Class OPTIONAL,IN ULONG CreateOptions,OUT PULONG Disposition OPTIONAL);其中應用層中注冊表項與內(nèi)核中注冊表項的對應關系如下:
| HKEY_CLASSES_ROOT | 沒有對應的路徑 |
| HKEY_CURRENT_USER | 沒有簡單的對應路徑,但是可以求得 |
| HKEY_USERS | \Registry\User |
| HKEY_LOCAL_MACHINE | \Registry\Machine |
4. TitleIndex:一般設置為0
5. Class 一般給NULL
6. CreateOptions:創(chuàng)建選項,一般給REG_OPTION_NON_VOLATILE
7. Disposition:返回創(chuàng)建的狀態(tài),如果是REG_CREATED_NEW_KEY表示創(chuàng)建了一個新的注冊表項如果是REG_OPENED_EXISTING_KEY表示打開一個已有的注冊表項
8. ### 添加、修改注冊表鍵
注冊表中的鍵是類似與字典中的鍵值對,通過鍵名找到對應的值,鍵值的類型大致可以分為下面幾種
| REG_BINARY | 鍵值采用二進制存儲 |
| REG_SZ | 鍵值用寬字符串,以\0結(jié)尾 |
| REG_EXPAND_SZ | 與上面的REG_SZ相同,它是上面那個字符串的擴展字符 |
| REG_MULTI_SZ | 能夠存儲多個字符串,每個都以\0隔開 |
| REG_DWORD | 鍵值用4字節(jié)整型存儲(這個類型的數(shù)據(jù)在驅(qū)動中使用ULONG來替代) |
| REG_QWORD | 鍵值用8字節(jié)存儲(這個用LONGLONG) |
用函數(shù)ZwSetValueKey可以添加和修改注冊表的一項內(nèi)容
NTSTATUS ZwSetValueKey(IN HANDLE KeyHandle, //注冊表句柄IN PUNICODE_STRING ValueName,//要修改或者新建的鍵名IN ULONG TitleIndex OPTIONAL,//一般設置為0IN ULONG Type,//在上面的表中選擇一個IN PVOID Data,//鍵值IN ULONG DataSize//鍵值數(shù)據(jù)的大小);當傳入的鍵值不存在則創(chuàng)建一個新鍵值,否則就修改原來的鍵值
查詢注冊表
查詢注冊表使用函數(shù)ZwQueryValueKey
NTSTATUS ZwQueryValueKey(IN HANDLE KeyHandle, //注冊表句柄IN PUNICODE_STRING ValueName,//注冊表鍵名IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,OUT PVOID KeyValueInformation,//接收返回信息的緩沖區(qū)IN ULONG Length,//緩沖區(qū)的大小OUT PULONG ResultLength//真實緩沖區(qū)的大小);使用這個函數(shù)時利用參數(shù)KeyValueInformationClass來指定接收數(shù)據(jù)的類型,根據(jù)這個值的不同,函數(shù)會返回不同的結(jié)構(gòu)體放到一個緩沖區(qū)中。一般這個值可取:KeyValueBasicInformation 返回注冊表項的基礎信息
KeyValueFullInformation 返回注冊表的全部信息
KeyValuePartialInformation 返回注冊表的部分信息
一般情況下使用KeyValuePartialInformation查詢鍵值數(shù)據(jù)
利用這個函數(shù)來查詢時一般也是采用兩次調(diào)用的方式,第一次返回數(shù)據(jù)所需緩沖,然后分配緩沖并進行第二次調(diào)用
枚舉子項
DDK提供了兩個函數(shù)用于這個功能
NTSTATUS ZwQueryKey(IN HANDLE KeyHandle,//注冊表句柄IN KEY_INFORMATION_CLASS KeyInformationClass,//保存注冊表信息的結(jié)構(gòu)體的類型OUT PVOID KeyInformation,//返回查詢到信息的緩沖IN ULONG Length,//緩沖的大小OUT PULONG ResultLength//真正信息的大小);NTSTATUS ZwEnumerateKey(IN HANDLE KeyHandle,//句柄IN ULONG Index,//這個值是表示第幾個子項IN KEY_INFORMATION_CLASS KeyInformationClass,//查詢到的信息的結(jié)構(gòu)體OUT PVOID KeyInformation,//返回信息的緩沖IN ULONG Length,//緩沖長度OUT PULONG ResultLength//返回信息的長度);其中ZwQueryKey函數(shù)用于查詢某個注冊表項中有多少個子項,在調(diào)用這個函數(shù)時傳入的KeyInformationClass的值一般給KeyFullInformation,在這個結(jié)構(gòu)體中的SubKeys表示有多少個子項,而ZwEnumerateKey則是用于查詢各個子項中的具體內(nèi)容,通過指定Index表示我們要查詢該項中的第幾個子項,將KeyInformationClass填入KeyBasicInformation,這樣在結(jié)構(gòu)體的Name里面可以得到具體的注冊表子項的名稱
枚舉子健
枚舉子鍵的方法于上面的大致相同,首先利用ZwQueryKey查詢注冊表,然后取結(jié)構(gòu)體KeyFullInformation的成員Values,根據(jù)這個值在循環(huán)中依次調(diào)用函數(shù)ZwEnumerateValueKey,結(jié)構(gòu)體類填入 KeyValueBasicInformation查詢基本信息即可
刪除子項
刪除子項使用的內(nèi)核函數(shù)是ZwDeleteKey
NTSTATUS ZwDeleteKey(IN HANDLE KeyHandle);這個函數(shù)只能刪除沒有子項的項目,如果有子項,則需要先刪除所有子項。
其他注冊表函數(shù)
為了簡化注冊表操作,DDK提供了另外一組以Rtl開頭的函數(shù),把之前的Zw函數(shù)進行了封裝,下面是這些函數(shù)與它們功能的對應關系
| RtlCreateRegistryKey | 創(chuàng)建注冊表項 |
| RtlCheckRegistryKey | 查看注冊表中的某項是否存在 |
| RtlWriteRegistryValue | 寫注冊表 |
| RtlDeleteRegistryValue | 刪除注冊表的子鍵 |
轉(zhuǎn)載于:https://www.cnblogs.com/lanuage/p/7725717.html
總結(jié)
以上是生活随笔為你收集整理的Windows内核函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 500mbps是几兆(图文)
- 下一篇: 搭建一个redis高可用系统