目錄編程
在內核中咱們的註冊表只有兩個 keyapi
內核 | 對應ring3 | |
---|---|---|
\\Registry\\Machine\\software |
HKEY_LOCAL_MACHINE | |
\\Registry\\User\\ |
HKEY_USERS |
其它的三個是從這些內核中映射出來的。數組
重啓刪除,其實信息是放在註冊表中的。網絡
以下:
內核:
\Registry\Machine\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
函數
對應Ring3
計算機\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\pendingFileRenameOperations
這個key裏面有個值是 REG_MULTI_SZ類型,這個類型存儲的是多個 \0結尾的路徑。code
使用 MoveFileEx(路徑,NULL,MOVEFILE_DELAY_UNTIL_REBOOT)這個函數進行重啓刪除。
參數2不爲空,就是替換,爲NULL就是刪除。 就是移動某個文件到某個目錄下,若是某個目錄存在就替換。orm
參數3: 參數3是很重要的。若是你替換的時候文件在使用則替換不了。給了這個參數。
那麼在重啓以後。會給你進行替換。也就是重啓刪除了。blog
此次重啓刪除則會放到上面那個註冊表中。ip
操做Key的函數內存
API | 做用 | |
---|---|---|
ZwCreateKey | 建立或者打開Key | |
ZwEnumerateKey | 枚舉key | |
ZwQueryKey | 查詢Key | |
ZwDeleteKey | 刪除Key |
操做Valuekey的函數.也就是key下面的值.
API | 做用 | |
---|---|---|
ZwEnumerateValueKey | 枚舉Valuekey 值 | |
ZwQueryValueKey | 查詢valuekey值 | |
ZwSetValueKey | 設置ValueKey的值 | |
ZwDeleteValueKey | 刪除Valuekey的值 |
建立key須要注意參數. 分別爲建立臨時key跟建立永久key
讀取共享文件夾下的路徑.
計算機\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\你共享文件夾的名字
找到文件共享名字.尋找值取出路徑進行拼接.
對應內核:
registry\machine\SYSTEM\CurrentControlSet\Services\LanmanServer\Shares\你的共享文件夾名
UNC路徑 = \\共享網絡名字\共享文件夾的名字\xxx文件
代碼以下
#include <ntddk.h> #include <ntstrsafe.h> DRIVER_UNLOAD DriverUnLoad; //************************************ // Method: ntIBinaryCreateKey // FullName: ntIBinaryCreateKey // Access: public // Returns: NTSTATUS // Qualifier: 建立註冊表鍵值 // Parameter: UNICODE_STRING uPathKeyName //************************************ NTSTATUS ntIBinaryCreateKey(UNICODE_STRING uPathKeyName); NTSTATUS ntIBinaryInit(); void DriverUnLoad (PDRIVER_OBJECT pDeviceObject) { KdPrint(("驅動已卸載")); } NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT pDriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; KdPrint(("驅動加載成功")); pDriverObject->DriverUnload = DriverUnLoad; return ntIBinaryInit(); } NTSTATUS ntIBinaryInit() { NTSTATUS status = STATUS_ERROR_PROCESS_NOT_IN_JOB; UNICODE_STRING uKeyPath; RtlUnicodeStringInit(&uKeyPath,L"\\registry\\machine\\SoftWare\\IBinary"); status = ntIBinaryCreateKey(uKeyPath); if (!NT_SUCCESS(status)) { KdPrint(("建立Key失敗")); return status; } return status; } NTSTATUS ntIBinaryCreateKey(UNICODE_STRING uPathKeyName) { NTSTATUS status = STATUS_ERROR_PROCESS_NOT_IN_JOB; OBJECT_ATTRIBUTES objAttri; HANDLE hKeyHandle; UNICODE_STRING uSubKey; HANDLE hSubKey; OBJECT_ATTRIBUTES objSubAttri; ULONG isRegStatus; //註冊表的狀態,傳出. InitializeObjectAttributes( &objAttri, &uPathKeyName, OBJ_CASE_INSENSITIVE, //句柄只能內核訪問,並且只能一個打開. NULL, NULL); status = ZwCreateKey(&hKeyHandle, KEY_ALL_ACCESS, &objAttri, 0, NULL, REG_OPTION_BACKUP_RESTORE, (PULONG)(&isRegStatus) ); if (!NT_SUCCESS(status)) { ZwClose(hKeyHandle); return status; } //建立子Key RtlUnicodeStringInit(&uSubKey, L"MyReg"); /* InitializeObjectAttributes(p, n, a, r, s) { \ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ (p)->RootDirectory = r; \ (p)->Attributes = a; \ (p)->ObjectName = n; \ (p)->SecurityDescriptor = s; \ (p)->SecurityQualityOfService = NULL; \ } */ //InitializeObjectAttributes(&objAttri, &uSubKey, OBJ_CASE_INSENSITIVE, hKeyHandle, NULL); //不使用宏,手工進行賦值. objSubAttri.Length = sizeof(OBJECT_ATTRIBUTES); objSubAttri.Attributes = OBJ_CASE_INSENSITIVE; objSubAttri.ObjectName = &uSubKey; objSubAttri.SecurityDescriptor = NULL; objSubAttri.SecurityQualityOfService = NULL; objSubAttri.RootDirectory = hKeyHandle; //注意這裏.父目錄設置爲咱們上面建立的key status = ZwCreateKey(&hSubKey, //傳出建立的Key KEY_ALL_ACCESS, //權限 &objSubAttri, //路徑 0, NULL, REG_OPTION_NON_VOLATILE, //建立的Key重啓是否存在仍是臨時的 &isRegStatus); //保存key的狀態,建立成功仍是打開 if (!NT_SUCCESS(status)) { ZwClose(hSubKey); ZwClose(hKeyHandle); return status; } ZwClose(hSubKey); ZwClose(hKeyHandle); KdPrint(("建立Key成功")); return status; }
ZwCreateKey 來建立Key. 建立子Key也是用這個函數.只不過你須要在初始化子類的路徑的時候.傳入父類的Key便可.
刪除Key很簡單了.使用 ZwOpenKey打開key ZwDeleteKey刪除key
NTSTATUS ntIBinaryDeleteKey(UNICODE_STRING uPathKeyName) { NTSTATUS ntStatus; HANDLE hKey; OBJECT_ATTRIBUTES ObjAttr; ULONG isRegStatus; ObjAttr.Length = sizeof(OBJECT_ATTRIBUTES); ObjAttr.Attributes = OBJ_CASE_INSENSITIVE; ObjAttr.ObjectName = &uPathKeyName; ObjAttr.RootDirectory = NULL; ObjAttr.SecurityDescriptor = NULL; ObjAttr.SecurityQualityOfService = NULL; __try { ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr);//打開Key在進行刪除 if (!NT_SUCCESS(ntStatus)) { ZwClose(hKey); return ntStatus; } ntStatus = ZwDeleteKey(hKey); if (!NT_SUCCESS(ntStatus)) { ZwClose(hKey); return ntStatus; } KdPrint(("刪除Key成功")); } __except (GetExceptionCode()) { KdPrint(("刪除Key出現異常")); } return ntStatus; }
查詢遍歷Key也很簡單.
1.使用函數 ZwOpenKey
打開你想遍歷的Key
2.兩次調用 ZwQueryKey
* ,第一次獲取你想遍歷Key的緩衝區大小.第二次.得到緩衝區大小了.爲這個結構體申請內存.傳入這個結構體.繼續遍歷.關於結構體能夠查看MSDN介紹.
3.經過結構體成員.拿到子key數量.創建for循環遍歷子key
4.遍歷過程當中.調用兩次 ZwEnumerateKey
第一次調用.
拿到你遍歷當前key的基本信息結構體的大小.而後爲結構體申請內存.
第二次調用傳入結構體.獲得當前key的基本信息.這個基本信息是放在這個結構體中.
最後初始化UNICODE_STRING字符串.進行打印便可.
代碼:
NTSTATUS ntIBinaryQueryKey(UNICODE_STRING uPathKeyName) //查詢Key { NTSTATUS ntStatus; HANDLE hKey; OBJECT_ATTRIBUTES objAttri = { 0 }; PKEY_FULL_INFORMATION pkfinfo = NULL; ULONG uSize = 0; ULONG iteratorValue = 0; //遍歷的變量 PKEY_BASIC_INFORMATION pBaseinfo = NULL; UNICODE_STRING uDbgValue = { 0 };//遍歷出來的信息保存到UNICODE_STRING結構體中 //首先打開Key,而後遍歷Key __try { InitializeObjectAttributes( &objAttri, &uPathKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttri); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } //遍歷Key.須要兩次調用.第一次調用得出數據大小.第二次調用則是填充數據 ntStatus = ZwQueryKey(hKey, KeyFullInformation, NULL, 0, &uSize); //得出KEY_FUN_INFOMATION 結構的大小.進行內存申請便可. //查詢MSDN得出,ZwQuery當數據不足會返回兩個狀態.因此判斷一下便可. //STATUS_BUFFER_OVERFLOW或STATUS_BUFFER_TOO_SMALL if (ntStatus != STATUS_BUFFER_OVERFLOW && ntStatus != STATUS_BUFFER_TOO_SMALL) { ZwClose(hKey); return ntStatus; } pkfinfo = (PKEY_FULL_INFORMATION)ExAllocatePoolWithTag(PagedPool, uSize, 'niBI'); if (NULL == pkfinfo) { ZwClose(hKey); return ntStatus; } //申請了KEY_FULL_INFOMATION結構數組大小.而後進行獲取大小 ntStatus = ZwQueryKey(hKey, KeyFullInformation, pkfinfo, uSize, &uSize); if (!NT_SUCCESS(ntStatus)) { ExFreePoolWithTag(pkfinfo, 'niBI'); ZwClose(hKey); return ntStatus; } for (iteratorValue = 0; iteratorValue < pkfinfo->SubKeys; iteratorValue++) { //遍歷出Key就要進行枚舉出Key的詳細信息.使用ZwEnumerateKey便可.也是枚舉一個結構. ntStatus = ZwEnumerateKey(hKey, 0, KeyBasicInformation, NULL, 0, &uSize); if (ntStatus != STATUS_BUFFER_OVERFLOW && ntStatus != STATUS_BUFFER_TOO_SMALL) { ZwClose(hKey); return ntStatus; } pBaseinfo = (PKEY_BASIC_INFORMATION)ExAllocatePoolWithTag(PagedPool, uSize, 'niBI'); if (NULL == pkfinfo) { ZwClose(hKey); return ntStatus; } //繼續申請一次得出須要的 ntStatus = ZwEnumerateKey(hKey, 0, KeyBasicInformation, pBaseinfo, uSize, &uSize); if (!NT_SUCCESS(ntStatus)) { if (NULL != pBaseinfo) ExFreePoolWithTag(pBaseinfo, 'niBI'); if (NULL != pkfinfo) ExFreePoolWithTag(pkfinfo, 'niBI'); ZwClose(hKey); return ntStatus; } //得出信息則能夠進行進一步操做了. //初始化UNICODE結構.進行打印輸出便可. uDbgValue.Length = (USHORT)pBaseinfo->NameLength; uDbgValue.MaximumLength = (USHORT)pBaseinfo->NameLength; uDbgValue.Buffer = pBaseinfo->Name; KdPrint(("得出的key 名字 = %wZ", &uDbgValue)); ExFreePool(pBaseinfo); //同上釋放內存 } //釋放資源 if (NULL != pkfinfo) ExFreePool(pkfinfo); ZwClose(hKey); } __except (GetExceptionCode()) { KdPrint(("出現異常,異常代碼爲: %ld", GetExceptionCode())); } return ntStatus; }
結果
上面說的只是建立key.下面則是怎麼設置對應的Value
代碼也很簡單.
原理以下下:
1.打開Key
2.使用函數 ZwSetValueKey
建立而且設置Value便可.
代碼以下
NTSTATUS ntIBinarySetKeyValue(UNICODE_STRING uPathKeyName) { NTSTATUS ntStatus; OBJECT_ATTRIBUTES objAttri; HANDLE hKey; UNICODE_STRING uSetValueKeyName; ULONG Value = 10; InitializeObjectAttributes(&objAttri, &uPathKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); ntStatus = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &objAttri); if (!NT_SUCCESS(ntStatus)) { return ntStatus; } //設置KEY value的值 RtlUnicodeStringInit(&uSetValueKeyName, L"IBinaryFrist"); ntStatus = ZwSetValueKey(hKey, &uSetValueKeyName, 0, REG_DWORD, &Value, sizeof(ULONG)); if (!NT_SUCCESS(ntStatus)) { ZwClose(hKey); return ntStatus; } KdPrint(("設置Key成功")); ZwClose(hKey); return ntStatus; }
代碼演示.