8.5 Windows驅動開發:內核注冊表增刪改查

注冊表是Windows中的一個重要的數據庫,用于存儲系統和應用程序的設置信息,注冊表是一個巨大的樹形結構,無論在應用層還是內核層操作注冊表都有獨立的API函數可以使用,而在內核中讀寫注冊表則需要使用內核裝用API函數,如下將依次介紹并封裝一些案例,實現對注冊表的創建,刪除,更新,查詢等操作。

在Windows內核中,注冊表是一種存儲系統配置信息的機制,包括應用程序、硬件、驅動程序和操作系統的各種設置。內核提供了一些API函數,可以讓驅動程序通過代碼訪問和修改注冊表,以實現系統的配置和管理。下面簡單介紹一下內核中的注冊表增刪改查操作:

注冊表查詢

  • 在內核中,可以使用ZwQueryValueKey或ZwEnumerateValueKey函數查詢指定鍵的值。其中,ZwQueryValueKey函數可以查詢指定鍵的值,而ZwEnumerateValueKey函數可以枚舉指定鍵下的所有值。這兩個函數都需要指定鍵的句柄和要查詢的值的名稱,查詢結果將返回在指定的緩沖區中。

注冊表修改

  • 在內核中,可以使用ZwSetValueKey函數修改指定鍵的值。該函數需要指定鍵的句柄、要修改的值的名稱、值的類型和值的數據。在修改注冊表時,需要注意權限和安全性問題,以避免潛在的安全問題。

注冊表添加

  • 在內核中,可以使用ZwCreateKey函數創建一個新的鍵。該函數需要指定要創建鍵的父鍵的句柄、新鍵的名稱、新鍵的屬性等信息。如果成功創建了新鍵,則可以使用ZwSetValueKey函數向其添加值。

注冊表刪除

  • 在內核中,可以使用ZwDeleteValueKey函數刪除指定鍵的值,或使用ZwDeleteKey函數刪除指定鍵及其下面的所有子鍵和值。這兩個函數都需要指定要刪除的鍵的句柄或路徑。在刪除注冊表時,同樣需要注意權限和安全性問題,以避免潛在的安全問題。

需要注意的是,對注冊表的操作可能會對系統的穩定性產生影響。因此,在實現這些技術時,需要遵循操作系統和安全軟件的規定,以確保系統的安全和穩定。

8.5.1 ZwCreateKey

創建注冊表Key鍵,內核函數ZwCreateKey可用于創建新的注冊表項或打開現有注冊表項。

ZwCreateKey是Windows內核中的一個函數,用于創建一個新的注冊表鍵(registry key)。它通常被驅動程序使用來添加新的配置信息或者修改已有的配置信息。

以下是ZwCreateKey函數的一般形式:

NTSTATUS ZwCreateKey(_Out_ PHANDLE            KeyHandle,_In_  ACCESS_MASK        DesiredAccess,_In_  POBJECT_ATTRIBUTES ObjectAttributes,_Reserved_ ULONG         TitleIndex,_In_  PUNICODE_STRING    Class,_In_  ULONG              CreateOptions,_Out_ PULONG             Disposition
);

參數說明:

  • KeyHandle: 輸出參數,指向新創建的注冊表鍵的句柄(handle)。
  • DesiredAccess: 指定新創建的鍵所需的訪問權限,比如KEY_QUERY_VALUE等,具體請參考MSDN文檔。
  • ObjectAttributes: 指向一個OBJECT_ATTRIBUTES結構體的指針,該結構體包含了注冊表鍵的一些屬性信息,比如名稱、路徑等。
  • TitleIndex: 指定鍵的標題索引。
  • Class: 指向一個UNICODE_STRING結構體的指針,它用于指定新創建的鍵的類名。
  • CreateOptions: 指定創建鍵的選項,比如REG_OPTION_NON_VOLATILE等。
  • Disposition: 輸出參數,指向一個ULONG類型的指針,返回創建的鍵的狀態信息,比如REG_CREATED_NEW_KEY等。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwCreateKey函數之前,必須先初始化OBJECT_ATTRIBUTES結構體,以包含要創建的注冊表鍵的完整路徑。

在使用ZwCreateKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的類名、訪問權限和創建選項等參數的設置,以確保所創建的鍵能夠正確地滿足應用程序的需求。

#include <ntifs.h>// 創建或者打開已存在注冊表鍵
BOOLEAN MyCreateRegistryKeyA(UNICODE_STRING ustrRegistry)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };ULONG ulResult = 0;NTSTATUS status = STATUS_SUCCESS;// 創建或者打開已存在注冊表鍵InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);// 創建Keystatus = ZwCreateKey(&hRegister,KEY_ALL_ACCESS,&objectAttributes,0,NULL,REG_OPTION_NON_VOLATILE,&ulResult);if (!NT_SUCCESS(status)){return FALSE;}if (REG_CREATED_NEW_KEY == ulResult){DbgPrint("[*] 注冊表已被創建 \n");}else if (REG_OPENED_EXISTING_KEY == ulResult){DbgPrint("[*] 注冊表打開 \n");}// 關閉注冊表鍵句柄ZwClose(hRegister);return TRUE;
}// 創建鍵值對
BOOLEAN MyCreateRegistryKeyB(LPWSTR KeyName)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);// 初始化InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 創建KeyntStatus = ZwCreateKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);if (NT_SUCCESS(ntStatus)){DbgPrint("[*] 注冊表已被創建 \n");ZwClose(hRegister);return TRUE;}else{DbgPrint("[*] 注冊表創建失敗 \n");return FALSE;}return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;// 創建注冊表鍵UNICODE_STRING ustrRegistry;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");flag = MyCreateRegistryKeyA(ustrRegistry);if (flag == TRUE){DbgPrint("注冊表鍵已創建 \n");}// 創建注冊表鍵flag = MyCreateRegistryKeyB(L"\\Registry\\Machine\\Software\\LySharkKeysB");if (flag == TRUE){DbgPrint("注冊表鍵已創建 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

運行如上代碼即可在計算機\HKEY_LOCAL_MACHINE\SOFTWARE\目錄下分別創建LySharkKeysALySharkKeysB兩個空目錄,輸出效果如下圖;

8.5.2 ZwDeleteKey

刪除注冊表Key鍵,內核函數ZwDeleteKey可從注冊表中刪除打開的項。

ZwDeleteKey是Windows內核中的一個函數,用于刪除指定的注冊表鍵(registry key)。它通常被驅動程序使用來刪除不再需要的配置信息或者清理無用的鍵。

以下是ZwDeleteKey函數的一般形式:

NTSTATUS ZwDeleteKey(_In_ HANDLE            KeyHandle
);

參數說明:

  • KeyHandle:要刪除的鍵的句柄(handle)。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwDeleteKey函數之前,需要先打開要刪除的鍵,獲取其句柄。

在使用ZwDeleteKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要刪除的鍵是正確的,并且不會對系統造成不良影響。

另外,需要注意的是,ZwDeleteKey函數只能用于刪除空的注冊表鍵。如果要刪除非空的鍵,需要先遞歸地刪除該鍵下的所有子鍵和值。

#include <ntifs.h>// 刪除注冊表鍵
BOOLEAN MyDeleteRegistryKeyA(UNICODE_STRING ustrRegistry)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;// 打開注冊表鍵InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 刪除注冊表鍵status = ZwDeleteKey(hRegister);if (!NT_SUCCESS(status)){ZwClose(hRegister);return FALSE;}// 關閉注冊表鍵句柄ZwClose(hRegister);return TRUE;
}// 刪除注冊表鍵
BOOLEAN MyDeleteRegistryKeyB(LPWSTR KeyName)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);// 初始化InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開KeyntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (NT_SUCCESS(ntStatus)){ntStatus = ZwDeleteKey(hRegister);ZwClose(hRegister);return TRUE;}else{return FALSE;}return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;// 刪除注冊表鍵UNICODE_STRING ustrRegistry;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");flag = MyDeleteRegistryKeyA(ustrRegistry);if (flag == TRUE){DbgPrint("[*] 已刪除 \n");}// 刪除注冊表鍵flag = MyDeleteRegistryKeyB(L"\\Registry\\Machine\\Software\\LySharkKeysB");if (flag == TRUE){DbgPrint("[*] 已刪除 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行如上程序,則可將ZwCreateKey創建的Key鍵刪除,當嘗試再次打開LySharkKeysB則會提示打開失敗,輸出效果如下所示;

8.5.3 ZwRenameKey

重命名注冊表Key鍵,內核函數ZwRenameKey可修改特定注冊表鍵名,此函數需要自行導出。

ZwRenameKey是Windows內核中的一個函數,用于重命名一個指定的注冊表鍵。它通常被驅動程序使用來更改配置信息或者重命名鍵。

以下是ZwRenameKey函數的一般形式:

NTSTATUS ZwRenameKey(_In_ HANDLE            KeyHandle,_In_ PUNICODE_STRING   NewName
);

參數說明:

  • KeyHandle: 要重命名的鍵的句柄(handle)。
  • NewName: 新鍵名稱的Unicode字符串。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwRenameKey函數之前,需要先打開要重命名的鍵,獲取其句柄。

在使用ZwRenameKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要重命名的鍵是正確的,并且不會對系統造成不良影響。另外,需要確保新鍵名稱是唯一的,且符合注冊表鍵名稱的規范。

需要注意的是,ZwRenameKey函數只能用于重命名單個鍵,如果需要批量重命名鍵,則需要自行實現遞歸操作。

#include <ntifs.h>// ZwRenameKey 需要自己導出
typedef NTSTATUS(__fastcall *ZWRENAMEKEY)(HANDLE KeyHandle, PUNICODE_STRING NewName);ZWRENAMEKEY MyZwRenameKey = NULL;// 根據函數名得到函數內存地址
PVOID GetFunctionAddr(PCWSTR FunctionName)
{UNICODE_STRING UniCodeFunctionName;RtlInitUnicodeString(&UniCodeFunctionName, FunctionName);return MmGetSystemRoutineAddress(&UniCodeFunctionName);
}// 重命名注冊表Key
BOOLEAN RegRenameKey(LPWSTR OldKeyName, LPWSTR NewKeyName)
{OBJECT_ATTRIBUTES objectAttributes;HANDLE hRegister;NTSTATUS ntStatus;UNICODE_STRING usOldKeyName, usNewKeyName;RtlInitUnicodeString(&usOldKeyName, OldKeyName);RtlInitUnicodeString(&usNewKeyName, NewKeyName);InitializeObjectAttributes(&objectAttributes, &usOldKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 得到函數內存地址MyZwRenameKey = (ZWRENAMEKEY)GetFunctionAddr(L"ZwRenameKey");ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (NT_SUCCESS(ntStatus)){// 重命名Key鍵ntStatus = MyZwRenameKey(hRegister, &usNewKeyName);ZwFlushKey(hRegister);ZwClose(hRegister);return TRUE;}else{return FALSE;}return FALSE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;// 重命名鍵flag = RegRenameKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"SuperLyShark");if (flag == TRUE){DbgPrint("[*] 已被重命名 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行這段驅動程序,自動將LySharkKeysA改名為SuperLyShark,輸出效果如下所示;

8.5.4 ZwSetValueKey

在鍵中創建Value值,在一個Key中增加一個新的值。

ZwSetValueKey是Windows內核中的一個函數,用于向指定的注冊表鍵中寫入值。它通常被驅動程序使用來修改或添加配置信息或者鍵值。

以下是ZwSetValueKey函數的一般形式:

NTSTATUS ZwSetValueKey(_In_ HANDLE            KeyHandle,_In_ PUNICODE_STRING   ValueName,_In_opt_ ULONG         TitleIndex,_In_ ULONG             Type,_In_opt_ PVOID         Data,_In_ ULONG             DataSize
);

參數說明:

  • KeyHandle: 要寫入值的鍵的句柄(handle)。
  • ValueName: 要寫入值的名稱的Unicode字符串。
  • TitleIndex: 零基索引,用于在鍵的名稱列表中查找與ValueName相對應的索引值。
  • Type: 要寫入的值的類型。
  • Data: 要寫入的數據的指針。
  • DataSize: 要寫入的數據的長度。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwSetValueKey函數之前,需要先打開要寫入值的鍵,獲取其句柄。

在使用ZwSetValueKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要寫入值的鍵是正確的,并且不會對系統造成不良影響。另外,需要確保寫入的數據類型和長度正確,以避免造成不必要的問題。

需要注意的是,ZwSetValueKey函數只能用于向單個鍵寫入單個值,如果需要批量寫入值,則需要自行實現循環操作。

#include <ntifs.h>
#include <windef.h>// 在鍵中增加值
BOOLEAN RegSetValueKey(LPWSTR KeyName, LPWSTR ValueName, DWORD DataType, PVOID DataBuffer, DWORD DataLength)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName, usValueName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);RtlInitUnicodeString(&usValueName, ValueName);InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (NT_SUCCESS(ntStatus)){// 設置注冊表ntStatus = ZwSetValueKey(hRegister, &usValueName, 0, DataType, DataBuffer, DataLength);// 將請求刷新到磁盤ZwFlushKey(hRegister);ZwClose(hRegister);return TRUE;}else{return FALSE;}return FALSE;
}// 添加或者修改注冊表鍵值
BOOLEAN MySetRegistryKeyValue(UNICODE_STRING ustrRegistry, UNICODE_STRING ustrKeyValueName, ULONG ulKeyValueType, PVOID pKeyValueData, ULONG ulKeyValueDataSize)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開注冊表鍵status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 添加或者修改鍵值status = ZwSetValueKey(hRegister, &ustrKeyValueName, 0, ulKeyValueType, pKeyValueData, ulKeyValueDataSize);if (!NT_SUCCESS(status)){ZwClose(hRegister);return FALSE;}// 關閉注冊表鍵句柄ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;DWORD set_dw = 1024;BOOLEAN is_true = TRUE;WCHAR sz_char[256] = L"hello lyshark";// 新建設置valueflag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth", REG_DWORD, &set_dw, sizeof(set_dw));if (flag == TRUE){DbgPrint("[*] 創建is_auth值成功 \n");}// 新建設置boolflag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_trhe", REG_BINARY, &is_true, sizeof(is_true));if (flag == TRUE){DbgPrint("[*] 創建is_true值成功 \n");}// 新建設置charflag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"1001", REG_SZ, &sz_char, sizeof(sz_char));if (flag == TRUE){DbgPrint("[*] 創建char值成功 \n");}// 添加注冊表鍵值UNICODE_STRING ustrRegistry;UNICODE_STRING ustrKeyValueName;WCHAR wstrKeyValueData[] = L"I am LyShark";RtlInitUnicodeString(&ustrKeyValueName, L"1002");RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");flag = MySetRegistryKeyValue(ustrRegistry, ustrKeyValueName, REG_SZ, wstrKeyValueData, sizeof(wstrKeyValueData));if (flag == TRUE){DbgPrint("[*] 創建char值成功 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行如上代碼,即可在\\Registry\\Machine\\Software\\LySharkKeysA分別創建一個整數,布爾值,字符串類型,效果圖如下;

8.5.5 ZwQueryValueKey

查詢某個Key鍵中的值,調用后可輸出特定鍵中的值。

ZwQueryValueKey是Windows內核中的一個函數,用于從指定的注冊表鍵中讀取指定值的數據。它通常被驅動程序使用來獲取配置信息或者鍵值。

以下是ZwQueryValueKey函數的一般形式:

NTSTATUS ZwQueryValueKey(_In_ HANDLE            KeyHandle,_In_ PUNICODE_STRING   ValueName,_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,_Out_opt_ PVOID        KeyValueInformation,_In_ ULONG             Length,_Out_ PULONG           ResultLength
);

參數說明:

  • KeyHandle: 要讀取值的鍵的句柄(handle)。
  • ValueName: 要讀取值的名稱的Unicode字符串。
  • KeyValueInformationClass: 指定要獲取的鍵值的信息類型。
  • KeyValueInformation: 存儲讀取的鍵值信息的緩沖區。
  • Length: KeyValueInformation緩沖區的大小。
  • ResultLength: 實際讀取的鍵值信息的大小。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwQueryValueKey函數之前,需要先打開要讀取值的鍵,獲取其句柄。

在使用ZwQueryValueKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要讀取值的鍵是正確的,并且不會對系統造成不良影響。另外,需要確保KeyValueInformation緩沖區的大小足夠,以存儲讀取的鍵值信息。

需要注意的是,ZwQueryValueKey函數只能用于讀取單個鍵的單個值,如果需要讀取多個鍵的值,則需要自行實現循環操作。

#include <ntifs.h>
#include <windef.h>// 查詢Key鍵中的Value值
BOOLEAN RegQueryValueKey(LPWSTR KeyName, LPWSTR ValueName, PKEY_VALUE_PARTIAL_INFORMATION *pkvpi)
{ULONG ulSize;NTSTATUS ntStatus;PKEY_VALUE_PARTIAL_INFORMATION pvpi;OBJECT_ATTRIBUTES objectAttributes;HANDLE hRegister;UNICODE_STRING usKeyName;UNICODE_STRING usValueName;RtlInitUnicodeString(&usKeyName, KeyName);RtlInitUnicodeString(&usValueName, ValueName);// 初始化InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開注冊表KeyntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 查詢長度ntStatus = ZwQueryValueKey(hRegister, &usValueName, KeyValuePartialInformation, NULL, 0, &ulSize);if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND || ulSize == 0){return FALSE;}// 分配空間保存查詢結果pvpi = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(PagedPool, ulSize);ntStatus = ZwQueryValueKey(hRegister, &usValueName, KeyValuePartialInformation, pvpi, ulSize, &ulSize);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 這里的pvpi未被釋放,可在外部釋放// 執行 ExFreePool(pvpi); 釋放*pkvpi = pvpi;return TRUE;
}// 查詢注冊表鍵值
BOOLEAN MyQueryRegistryKeyValue(UNICODE_STRING ustrRegistry, UNICODE_STRING ustrKeyValueName)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;ULONG ulBufferSize = 0;PKEY_VALUE_PARTIAL_INFORMATION pKeyValuePartialInfo = NULL;// 初始化InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開注冊表Keystatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 先獲取查詢注冊表鍵值所需緩沖區的大小status = ZwQueryValueKey(hRegister, &ustrKeyValueName, KeyValuePartialInformation, NULL, 0, &ulBufferSize);if (0 == ulBufferSize){ZwClose(hRegister);return FALSE;}// 申請緩沖區pKeyValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePool(NonPagedPool, ulBufferSize);// 查詢注冊表鍵值并獲取查詢結果status = ZwQueryValueKey(hRegister, &ustrKeyValueName, KeyValuePartialInformation, pKeyValuePartialInfo, ulBufferSize, &ulBufferSize);if (!NT_SUCCESS(status)){ExFreePool(pKeyValuePartialInfo);ZwClose(hRegister);return FALSE;}// 顯示查詢結果DbgPrint("KeyValueName=%wZ, KeyValueType=%d, KeyValueData=%S\n", &ustrKeyValueName, pKeyValuePartialInfo->Type, pKeyValuePartialInfo->Data);// 釋放內存, 關閉句柄ExFreePool(pKeyValuePartialInfo);ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");BOOLEAN flag = FALSE;DWORD get_dw = 0;PKEY_VALUE_PARTIAL_INFORMATION pkvi;// 查詢設置flag = RegQueryValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth", &pkvi);if (flag == TRUE){// 拷貝查詢結果RtlCopyMemory(&get_dw, pkvi->Data, pkvi->DataLength);// 輸出結果DbgPrint("[*] 查詢結果: %d \n", get_dw);ExFreePool(pkvi);}// 第二種查詢方式UNICODE_STRING ustrRegistry;UNICODE_STRING ustrKeyValueName;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");RtlInitUnicodeString(&ustrKeyValueName, L"is_auth");MyQueryRegistryKeyValue(ustrRegistry, ustrKeyValueName);Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行這段程序,將會查詢\\Registry\\Machine\\Software\\LySharkKeysA下面的is_auth字段中的值,輸出效果如下圖所示;

8.5.6 ZwEnumerateKey

枚舉某個主鍵底部的子鍵值,實現對指定主鍵中所有的子鍵的枚舉。

ZwEnumerateKey是Windows內核中的一個函數,用于列舉指定注冊表鍵下的子鍵。它通常被驅動程序使用來獲取鍵列表,以及子鍵的數量和名稱等信息。

以下是ZwEnumerateKey函數的一般形式:

NTSTATUS ZwEnumerateKey(_In_ HANDLE                KeyHandle,_In_ ULONG                 Index,_In_ KEY_INFORMATION_CLASS KeyInformationClass,_Out_ PVOID                KeyInformation,_In_ ULONG                 Length,_Out_ PULONG               ResultLength
);

參數說明:

  • KeyHandle: 要列舉子鍵的鍵的句柄(handle)。
  • Index: 指定要列舉的子鍵的索引。
  • KeyInformationClass: 指定要獲取的子鍵信息類型。
  • KeyInformation: 存儲讀取的子鍵信息的緩沖區。
  • Length: KeyInformation緩沖區的大小。
  • ResultLength: 實際讀取的子鍵信息的大小。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwEnumerateKey函數之前,需要先打開要列舉子鍵的鍵,獲取其句柄。

在使用ZwEnumerateKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要列舉子鍵的鍵是正確的,并且不會對系統造成不良影響。另外,需要確保KeyInformation緩沖區的大小足夠,以存儲讀取的子鍵信息。

需要注意的是,ZwEnumerateKey函數只能用于列舉單個鍵下的子鍵,如果需要列舉多個鍵的子鍵,則需要自行實現循環操作。

#include <ntifs.h>
#include <windef.h>// 枚舉子鍵
BOOLEAN EnumRegistrySubKey(WCHAR *MY_KEY_NAME)
{UNICODE_STRING RegUnicodeString;HANDLE hRegister;OBJECT_ATTRIBUTES objectAttributes;NTSTATUS ntStatus;ULONG ulSize, i;UNICODE_STRING uniKeyName;PKEY_FULL_INFORMATION pfi;// 初始化UNICODE_STRING字符串RtlInitUnicodeString(&RegUnicodeString, MY_KEY_NAME);// 初始化objectAttributes OBJ_CASE_INSENSITIVE(大小寫敏感)InitializeObjectAttributes(&objectAttributes, &RegUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開注冊表ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 第一次調用獲取KEY_FULL_INFORMATION數據的長度ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 第二次調用獲取KEY_FULL_INFORMATION數據的數據ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);// 循環輸出子鍵for (i = 0; i<pfi->SubKeys; i++){PKEY_BASIC_INFORMATION pbi;// 第一次調用獲取KEY_BASIC_INFORMATION數據的長度ZwEnumerateKey(hRegister, i, KeyBasicInformation, NULL, 0, &ulSize);pbi = (PKEY_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 第二次調用獲取KEY_BASIC_INFORMATION數據的數據ZwEnumerateKey(hRegister, i, KeyBasicInformation, pbi, ulSize, &ulSize);uniKeyName.Length = (USHORT)pbi->NameLength;uniKeyName.MaximumLength = (USHORT)pbi->NameLength;uniKeyName.Buffer = pbi->Name;DbgPrint("[LyShark] 序號: %d | 子Key名: %wZ \n", i, &uniKeyName);ExFreePool(pbi);}ExFreePool(pfi);ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");WCHAR MY_KEY_NAME[] = L"\\Registry\\Machine\\Software";BOOLEAN flag = EnumRegistrySubKey(MY_KEY_NAME);if (flag == TRUE){DbgPrint("[*] 枚舉結束 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行如上代碼片段,則會枚舉\\Registry\\Machine\\Software底部的所有子鍵值,輸出效果圖如下所示;

8.5.7 ZwEnumerateValueKey

用于枚舉子鍵下所有鍵值對的值,原理與上方枚舉子鍵類似。

ZwEnumerateValueKey是Windows內核中的一個函數,用于列舉指定注冊表鍵下的所有值。它通常被驅動程序使用來獲取鍵值列表,以及每個鍵值的名稱、類型和數據等信息。

以下是ZwEnumerateValueKey函數的一般形式:

NTSTATUS ZwEnumerateValueKey(_In_ HANDLE                KeyHandle,_In_ ULONG                 Index,_In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,_Out_ PVOID                KeyValueInformation,_In_ ULONG                 Length,_Out_ PULONG               ResultLength
);

參數說明:

  • KeyHandle: 要列舉值的鍵的句柄(handle)。
  • Index: 指定要列舉的值的索引。
  • KeyValueInformationClass: 指定要獲取的值信息類型。
  • KeyValueInformation: 存儲讀取的值信息的緩沖區。
  • Length: KeyValueInformation緩沖區的大小。
  • ResultLength: 實際讀取的值信息的大小。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwEnumerateValueKey函數之前,需要先打開要列舉值的鍵,獲取其句柄。

在使用ZwEnumerateValueKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要列舉值的鍵是正確的,并且不會對系統造成不良影響。另外,需要確保KeyValueInformation緩沖區的大小足夠,以存儲讀取的值信息。

需要注意的是,ZwEnumerateValueKey函數只能用于列舉單個鍵下的所有值,如果需要列舉多個鍵的所有值,則需要自行實現循環操作。

#include <ntifs.h>
#include <windef.h>// 枚舉子鍵
BOOLEAN EnumegistrySubValue(WCHAR *MY_KEY_NAME)
{UNICODE_STRING RegUnicodeString;HANDLE hRegister;OBJECT_ATTRIBUTES objectAttributes;ULONG ulSize, i;UNICODE_STRING uniKeyName;PKEY_FULL_INFORMATION pfi;NTSTATUS ntStatus;// 初始化UNICODE_STRING字符串RtlInitUnicodeString(&RegUnicodeString, MY_KEY_NAME);// 初始化objectAttributesInitializeObjectAttributes(&objectAttributes, &RegUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開注冊表ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(ntStatus)){return FALSE;}// 查詢VALUE的大小ZwQueryKey(hRegister, KeyFullInformation, NULL, 0, &ulSize);pfi = (PKEY_FULL_INFORMATION)ExAllocatePool(PagedPool, ulSize);ZwQueryKey(hRegister, KeyFullInformation, pfi, ulSize, &ulSize);for (i = 0; i<pfi->Values; i++){PKEY_VALUE_BASIC_INFORMATION pvbi;// 查詢單個VALUE的大小ZwEnumerateValueKey(hRegister, i, KeyValueBasicInformation, NULL, 0, &ulSize);pvbi = (PKEY_VALUE_BASIC_INFORMATION)ExAllocatePool(PagedPool, ulSize);// 查詢單個VALUE的詳情ZwEnumerateValueKey(hRegister, i, KeyValueBasicInformation, pvbi, ulSize, &ulSize);uniKeyName.Length = (USHORT)pvbi->NameLength;uniKeyName.MaximumLength = (USHORT)pvbi->NameLength;uniKeyName.Buffer = pvbi->Name;DbgPrint("[*] 子鍵: %d | 名稱: %wZ | ", i, &uniKeyName);if (pvbi->Type == REG_SZ){DbgPrint("類型: REG_SZ \n");}else if (pvbi->Type == REG_MULTI_SZ){DbgPrint("類型: REG_MULTI_SZ \n");}else if (pvbi->Type == REG_DWORD){DbgPrint("類型: REG_DWORD \n");}else if (pvbi->Type == REG_BINARY){DbgPrint("類型: REG_BINARY \n");}ExFreePool(pvbi);}ExFreePool(pfi);ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");WCHAR MY_KEY_NAME[] = L"\\Registry\\Machine\\Software\\LySharkKeysA";BOOLEAN flag = EnumegistrySubValue(MY_KEY_NAME);if (flag == TRUE){DbgPrint("[*] 枚舉結束 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行如上這段代碼,則可枚舉出\\Registry\\Machine\\Software\\LySharkKeysA底部的所有子鍵以及該子鍵的鍵值,輸出效果如下圖所示;

8.5.8 ZwDeleteValueKey

用于刪除指定鍵里面鍵值對的某個值。如果使用函數RegDeleteKey則刪除鍵包括里面的所有值。

ZwDeleteValueKey是Windows內核中的一個函數,用于刪除指定注冊表鍵下的一個值。它通常被驅動程序使用來刪除指定鍵下的一個值,以及釋放該值占用的空間。

以下是ZwDeleteValueKey函數的一般形式:

NTSTATUS ZwDeleteValueKey(_In_ HANDLE           KeyHandle,_In_ PUNICODE_STRING ValueName
);

參數說明:

  • KeyHandle: 要刪除值的鍵的句柄(handle)。
  • ValueName: 要刪除的值的名稱,為Unicode字符串指針。

函數執行成功時,將返回STATUS_SUCCESS,否則返回相應的錯誤代碼。需要注意的是,在使用ZwDeleteValueKey函數之前,需要先打開要刪除值的鍵,獲取其句柄。

在使用ZwDeleteValueKey函數時,需要注意權限和安全性問題,以避免潛在的安全問題。同時,需要仔細考慮鍵的名稱和路徑等信息,確保要刪除的值是正確的,并且不會對系統造成不良影響。

需要注意的是,ZwDeleteValueKey函數只能用于刪除單個鍵下的一個值,如果需要刪除多個鍵的多個值,則需要自行實現循環操作。

#include <ntifs.h>
#include <windef.h>// 刪除鍵中的值
BOOLEAN RegDeleteValueKey(LPWSTR KeyName, LPWSTR ValueName)
{OBJECT_ATTRIBUTES objectAttributes;UNICODE_STRING usKeyName, usValueName;NTSTATUS ntStatus;HANDLE hRegister;RtlInitUnicodeString(&usKeyName, KeyName);RtlInitUnicodeString(&usValueName, ValueName);InitializeObjectAttributes(&objectAttributes, &usKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);// 打開注冊表ntStatus = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (NT_SUCCESS(ntStatus)){ntStatus = ZwDeleteValueKey(hRegister, &usValueName);ZwFlushKey(hRegister);ZwClose(hRegister);return TRUE;}else{return FALSE;}return FALSE;
}// 刪除注冊表鍵值
BOOLEAN MyDeleteRegistryKeyValue(UNICODE_STRING ustrRegistry, UNICODE_STRING ustrKeyValueName)
{HANDLE hRegister = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };NTSTATUS status = STATUS_SUCCESS;// 打開注冊表鍵InitializeObjectAttributes(&objectAttributes, &ustrRegistry, OBJ_CASE_INSENSITIVE, NULL, NULL);status = ZwOpenKey(&hRegister, KEY_ALL_ACCESS, &objectAttributes);if (!NT_SUCCESS(status)){return FALSE;}// 刪除注冊表鍵status = ZwDeleteValueKey(hRegister, &ustrKeyValueName);if (!NT_SUCCESS(status)){ZwClose(hRegister);return FALSE;}// 關閉注冊表鍵句柄ZwClose(hRegister);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint(("Uninstall Driver Is OK \n"));
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");// 刪除值BOOLEAN flag = RegDeleteValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth");if (flag == TRUE){DbgPrint("[*] 刪除子鍵 \n");}UNICODE_STRING ustrRegistry;UNICODE_STRING ustrKeyValueName;RtlInitUnicodeString(&ustrRegistry, L"\\Registry\\Machine\\Software\\LySharkKeysA");RtlInitUnicodeString(&ustrKeyValueName, L"is_trhe");flag = MyDeleteRegistryKeyValue(ustrRegistry, ustrKeyValueName);if (flag == TRUE){DbgPrint("[*] 刪除子鍵 \n");}Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

編譯并運行如上驅動程序,則會將\\Registry\\Machine\\Software\\LySharkKeysA里面的is_trhe以及is_auth刪除,效果圖如下所示;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/163629.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/163629.shtml
英文地址,請注明出處:http://en.pswp.cn/news/163629.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

海外媒體推廣發稿平臺這8種方法助你一臂之力-華媒舍

在全球經濟一體化和信息技術快速進步的背景下&#xff0c;海外市場的開拓對于企業的發展至關重要。要在海外市場上取得成果并非易事&#xff0c;因此我們需要借助一些方法來幫助我們取得成功。其中&#xff0c;海外媒體推廣發稿平臺是非常有效的工具之一。本文將介紹8種方法&am…

組件庫篇 | EUI | 輸入框

組件庫篇 | EUI | 輸入框 輸入框 Input 創建輸入框 Input input(230, 50, 180, 30); // 創建了一個寬230,高50的輸入框,坐標為(180,30)一個輸入框就出現在界面上了,如果你用過EasyX的InputBox,你就會深刻體會到現代化的輸入框和古老輸入框的區別。 注意: input是一個…

SSM家具個性定制管理系統開發mysql數據庫web結構java編程計算機網頁源碼eclipse項目

一、源碼特點 SSM 家具個性定制管理系統是一套完善的信息系統&#xff0c;結合springMVC框架完成本系統&#xff0c;對理解JSP java編程開發語言有幫助系統采用SSM框架&#xff08;MVC模式開發&#xff09;&#xff0c;系統具有完整的源代碼和數據庫&#xff0c;系統主要采用…

低代碼表單設計器:可視化+靈活+易操作,降本增效輕松實現!

在現代化辦公環境中&#xff0c;擁有先進的低代碼表單設計器&#xff0c;可以讓企業降本又增效&#xff0c;節約企業成本的同時&#xff0c;也能高效利用企業內部資源&#xff0c;為實現數字化轉型升級提供夯實根基。那么&#xff0c;低代碼表單設計器擁有什么樣的特點&#xf…

張弛語言課,喜劇為什么使人快樂?

在為喜劇類電視劇或電影進行配音時&#xff0c;配音員需要展現出對幽默元素的敏感把握、對劇中笑料的恰到好處的呈現&#xff0c;以及對節奏的精確控制。喜劇的魅力在于其歡樂和幽默&#xff0c;所以配音工作的目標是激發觀眾的笑感&#xff0c;同時保持故事的流暢性和角色的個…

Composer update 跳過指定依賴

在使用Compose進PHP 依賴管理只時&#xff0c;有時候我們可能希望忽略版本批配&#xff0c;即使依賴項的景新版本已經發布&#xff0c;也然續使用當前的樂本。這種情況下&#xff0c;我們可以使用Composer的 --ignore-platform-reqs 選項來實現 可以使用--ignore-platform-req…

文心一言AI大模型,前端接入

文心一言AI大模型&#xff0c;前端接入 一、參考接口資料 模型廣場&#xff1a;https://console.bce.baidu.com/qianfan/modelcenter/model/buildIn/list 我的應用&#xff1a;https://console.bce.baidu.com/qianfan/ais/console/onlineService 千帆大模型調用API介紹&…

捷誠管理信息系統 SQL注入漏洞

聲明 本文僅用于技術交流&#xff0c;請勿用于非法用途 由于傳播、利用此文所提供的信息而造成的任何直接或者間接的后果及損失&#xff0c;均由使用者本人負責&#xff0c;文章作者不為此承擔任何責任。 一、產品介紹 捷誠管理信息系統是一款功能全面&#xff0c;可以支持自…

地埋式積水監測儀廠家直銷推薦,致力于積水監測

地埋式積水監測儀是一種高科技設備&#xff0c;能夠實時監測地面積水深度&#xff0c;并及時發出預警信息&#xff0c;有效避免因積水而產生的安全隱患。這種智能監測儀可以安裝在城市道路、立交橋、地下車庫等易積水地勢較低的地方&#xff0c;以確保及時監測特殊地段的積水&a…

數據庫數據恢復—SQLserver數據庫中勒索病毒被加密的數據恢復案例

SQLserver數據庫數據恢復環境&故障&#xff1a; 一臺服務器上的SQLserver數據庫被勒索病毒加密&#xff0c;無法正常使用。該服務器上部署有多個SQLserver數據庫&#xff0c;其中有2個數據庫及備份文件被加密&#xff0c;文件名被篡改&#xff0c;數據庫無法使用。 SQL se…

基于框架的線性回歸

線性回歸是機器學習中最簡單和最常用的回歸方法之一。它建立了自變量和因變量之間的線性關系&#xff0c;并通過擬合一條直線或超平面來預測和分析數據。 基于框架的線性回歸是構建線性回歸模型的一種常見方法&#xff0c;它利用現有的機器學習框架來實現線性回歸模型的建立、…

企業郵箱即時提醒服務推薦

現在用企業郵箱比較多&#xff0c;但是不能即時提醒&#xff0c;總是誤事&#xff0c;什么郵箱可以即時提醒呢&#xff1f;隨著工作和生活節奏的加快&#xff0c;傳統的電子郵件系統由于不能即時提醒&#xff0c;往往會導致重要郵件的漏接&#xff0c;從而引發一系列的麻煩和誤…

探秘ARouter:Android路由的藝術

引言 在Android的組件化架構中&#xff0c;有效地管理活動&#xff08;Activity&#xff09;跳轉和服務調用是至關重要的。ARouter作為一個前沿的路由框架&#xff0c;提供了強大的工具來簡化這一過程。本博客將深入探討ARouter的實現原理&#xff0c;幫助開發者更好地理解其背…

postgresql docker 安裝和需要關注點

1. 關于 最近都在搞國產化信創&#xff0c;關于DB這塊也來一波浪潮&#xff0c;很多國產化的數據庫也是基于postgesql研發的。 PostgreSQL開源生態是國內數據庫發展及應用的強大引擎&#xff0c;越來越多的國產數據庫選擇加入到PostgreSQL生態中&#xff0c;開枝散葉。 看下官…

理解C++編譯指令#pragma pack(1)

#pragma pack(1)是一個編譯器指令&#xff0c;它用來指定結構體&#xff0c;聯合體&#xff0c;和類的成員的內存對齊方式。內存對齊是一種優化內存訪問速度的技術&#xff0c;它會根據數據類型的大小來調整數據在內存中的位置&#xff0c;使得數據的起始地址是它的大小的整數倍…

Python基礎【三】--數據類型-Number【2023.11.23】

1.數值類型 Number數據類型只要包括三個分別是&#xff1a;整型&#xff08;int&#xff09;、浮點型&#xff08;float&#xff09;、復數&#xff08;complex&#xff09; 整型&#xff1a;包括正整數、負整數。如&#xff1a;1024、-1024。整型有四種進制表示&#xff0c;分…

QGIS之二十五兩個面圖層數據中選擇圖形完全一致的數據

效果 步驟 1、準備數據 2、按位置選擇 在Qgis工具箱中搜索"按位置選擇"工具 選擇要素和比較要素根據實際選擇 運行 3、結果

JAVA爬蟲1 - HttpClient的使用

一、簡介 HttpClient 是 Apache Jakarta Common 下的子項目,用來提供高效的、最新的、功能豐富的支持 HTTP協議的客戶端編程工具包,并且它支持HTTP協議最新的版本和建議。HttpClient已經應用在很多的 項目中,比如Apache Jakarta上很著名的另外兩個開源項目Cactus和HTMLUnit…

解決錯誤0x80071ac3的問題,錯誤代碼0x80071ac3的原因

在使用電腦的過程中可能會出現錯誤0x80071ac3的代碼問題&#xff0c;一旦出現這樣的問題解決起來可能會有點麻煩&#xff0c;其實這個錯誤是和磁盤的問題相關&#xff0c;可以將電腦重啟嘗試能否解決錯誤0x80071ac3問題&#xff0c;如果依然不能解決問題的話&#xff0c;那么大…

XC3320 離線式、無電感交流輸入線性穩壓器 可替代KP3310 固定5V輸出電壓

XC3320 是一款緊湊型無電感設計的離線式線性穩壓器。XC3320 可獲得 5V輸出電壓。XC3320 是一種簡單可靠的獲得偏置供電的離線式電源解決方案。XC3320 集成了 650V 功率 MOSFET&#xff0c;啟動控制電路,VDD 電壓控制電路,AC 交流信號同步檢測電路&#xff0c;低壓差穩壓器等。該…