驱动开发:内核注册表增删改查

news2024/10/7 2:19:52

注册表是Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息,注册表是一个巨大的树形结构,无论在应用层还是内核层操作注册表都有独立的API函数可以使用,而在内核中读写注册表则需要使用内核装用API函数,如下将依次介绍并封装一些案例,实现对注册表的创建,删除,更新,查询等操作。

在Windows内核中,注册表是一种存储系统配置信息的机制,包括应用程序、硬件、驱动程序和操作系统的各种设置。内核提供了一些API函数,可以让驱动程序通过代码访问和修改注册表,以实现系统的配置和管理。下面简单介绍一下内核中的注册表增删改查操作:

注册表查询

  • 在内核中,可以使用ZwQueryValueKey或ZwEnumerateValueKey函数查询指定键的值。其中,ZwQueryValueKey函数可以查询指定键的值,而ZwEnumerateValueKey函数可以枚举指定键下的所有值。这两个函数都需要指定键的句柄和要查询的值的名称,查询结果将返回在指定的缓冲区中。

注册表修改

  • 在内核中,可以使用ZwSetValueKey函数修改指定键的值。该函数需要指定键的句柄、要修改的值的名称、值的类型和值的数据。在修改注册表时,需要注意权限和安全性问题,以避免潜在的安全问题。

注册表添加

  • 在内核中,可以使用ZwCreateKey函数创建一个新的键。该函数需要指定要创建键的父键的句柄、新键的名称、新键的属性等信息。如果成功创建了新键,则可以使用ZwSetValueKey函数向其添加值。

注册表删除

  • 在内核中,可以使用ZwDeleteValueKey函数删除指定键的值,或使用ZwDeleteKey函数删除指定键及其下面的所有子键和值。这两个函数都需要指定要删除的键的句柄或路径。在删除注册表时,同样需要注意权限和安全性问题,以避免潜在的安全问题。

需要注意的是,对注册表的操作可能会对系统的稳定性产生影响。因此,在实现这些技术时,需要遵循操作系统和安全软件的规定,以确保系统的安全和稳定。

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);

	// 创建Key
	status = 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);

	// 创建Key
	ntStatus = 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.com \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两个空目录,输出效果如下图;

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);
	
	// 打开Key
	ntStatus = 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.com \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则会提示打开失败,输出效果如下所示;

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.com \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,输出效果如下所示;

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.com \n");

	BOOLEAN flag = FALSE;

	DWORD set_dw = 1024;
	BOOLEAN is_true = TRUE;
	WCHAR sz_char[256] = L"hello lyshark";

	// 新建设置value
	flag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_auth", REG_DWORD, &set_dw, sizeof(set_dw));
	if (flag == TRUE)
	{
		DbgPrint("[*] 创建is_auth值成功 \n");
	}

	// 新建设置bool
	flag = RegSetValueKey(L"\\Registry\\Machine\\Software\\LySharkKeysA", L"is_trhe", REG_BINARY, &is_true, sizeof(is_true));
	if (flag == TRUE)
	{
		DbgPrint("[*] 创建is_true值成功 \n");
	}

	// 新建设置char
	flag = 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分别创建一个整数,布尔值,字符串类型,效果图如下;

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);

	// 打开注册表Key
	ntStatus = 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);

	// 打开注册表Key
	status = 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.com \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字段中的值,输出效果如下图所示;

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.com \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底部的所有子键值,输出效果图如下所示;

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);

	// 初始化objectAttributes
	InitializeObjectAttributes(&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.com \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底部的所有子键以及该子键的键值,输出效果如下图所示;

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.com \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.coloradmin.cn/o/669621.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring Cloud灰度部署

1、背景(灰度部署) 在我们系统发布生产环境时&#xff0c;有时为了确保新的服务逻辑没有问题&#xff0c;会让一小部分特定的用户来使用新的版本&#xff08;比如客户端的内测版本&#xff09;&#xff0c;而其余的用户使用旧的版本&#xff0c;那么这个在Spring Cloud中该如何…

第五届双态IT北京用户大会回顾 | 基于运维数据治理的数智化转型

专题演讲人&#xff1a;擎创科技CTO 葛晓波 文末附有本场专题演讲视频 ●前言 各行业的云原生发展程度各有不同&#xff0c;并不是所有业务应用都适合云原生的形态&#xff0c;如若过度追求云原生化反而会使得企业运维压力骤增&#xff0c;运维成本激增。 从数字化转型的角度…

软考:软件工程:软件定义,特点,软件生命周期,软件危机,软件开发模型

软考&#xff1a;软件工程: 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &#xff08;1&#…

C++——vector容器模拟实现

目录 1. 基本成员函数 2. 默认成员函数 2.1 构造函数 2.2 析构函数 2.3 拷贝构造函数 2.4 赋值运算符重载函数 3. 容器访问相关函数 3.1 operator[ ]运算符重载 3.2 迭代器 3.3 范围for 4. vector空间增长问题 4.1 vector 容量和大小 4.2 vector扩容 4.3 重新定义…

均匀B样条采样从LiDAR数据中快速且鲁棒地估计地平面

文章&#xff1a;Fast and Robust Ground Surface Estimation from LiDAR Measurements using Uniform B-Splines 作者&#xff1a;Sascha Wirges, Kevin Rsch, Frank Bieder and Christoph Stiller 编辑&#xff1a;点云PCL 代码&#xff1a; https://github.com/KIT-MRT/poin…

全志V3S嵌入式驱动开发(编译器升级到7.5)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 看过我们文章的朋友都知道&#xff0c;前面为了做v3s的驱动&#xff0c;对linux kernel进行了两次升级。第一次升级是从4.10.y升级到4.14.y&#x…

【Python】open打开文件出现的错误解决

一、Python中关于打开open打开文件出现的错误解决 &#xff08;第一种&#xff09;UnicodeDecodeError: ‘utf-8’.......... &#xff08;第二种&#xff09;UnicodeDecodeError: ‘gbk’......... 二、问题解决 两种解决方式针对不同错误&#xff0c;实际应用中可以都试试…

PCB设计实验|第五周|LED显示电路PCB库设计|3月27日

目录 实验四 LED显示电路PCB库设计 一、实验原理 二、实验环境 三、实验结果 四、实验总结 实验四 LED显示电路PCB库设计 一、实验原理 LED(Light- Emitting-Diode中文意思为发光二极管)是一种能够将电能转化为可见光的半导体&#xff0c;它改变了白炽灯钨丝发光与节能…

裁剪图片软件有哪些?这些图片裁剪工具很好用

有哪些好用的图片裁剪软件呢&#xff1f;有时候&#xff0c;将一张大图缩小到更小的尺寸可以改善图片的质量&#xff0c;因为它可以减少像素和噪点。这对于那些需要在网上展示高质量图片的人来说尤其重要。裁剪后的图片可能更清晰、更锐利&#xff0c;并且更适合在各种设备上观…

Alex-Net 与 VGG-16

Alex-Net 由加拿大多伦多大学的 Alex Krizhevsky、Ilya Sutskever(G. E. Hinton 的两位博士生)和 Geoffrey E. Hinton 提出&#xff0c;网络名“Alex-Net”即 取自第一作者名。 下图所示是 Alex-Net 的网络结构&#xff0c;共含五层卷积层和三层全连接层。其中&#xff0c;Ale…

03.SELF-INSTRUCT+Alpaca

文章目录 前言泛读储备知识提示学习提示工程Promt Engineering答案工程 背景介绍研究SELF-INSTRUCT的动机研究意义&贡献 精读Overview种子任务步骤1&#xff1a;定义指令数据步骤2&#xff1a;自动指令数据生成步骤2.1指令生成步骤2.2指令分类步骤2.3实例生成步骤2.4筛选和…

19.组件之间传递数据

不同组件传递数据的时候&#xff0c;最好不要直接传递复杂数据类型(比如对象&#xff0c;数组) 前端需要处理的数据层级一般不会很多&#xff0c;需要在多处使用的数据一般会被放到数据库中 目录 1 组件的关系 2 父向子传递数据-props 3 子向父传递数据-自定义事件 4 …

分布式任务调度平台 XXL-JOB 实战

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

Scrum敏捷估算

无论是团队研发一款产品或者开发某一个项目&#xff0c;我们都需要回答“我们大概什么时间能够完成&#xff1f;”&#xff0c; 或者到某一个时间点&#xff0c;我们能够做到什么程度&#xff0c; 因此和传统的开发模式一样&#xff0c;我们在工作开始之前需要对我们需要做的事…

Linux Vim基本操作(文件的打开和编辑)完全攻略(有图有真相)

首先学习如何使用 Vim 打开文件。 Vim 打开文件 使用 Vim 打开文件很简单&#xff0c;例如在命令行模式下打开一个自己编写的文件 /test/vi.test&#xff0c;打开方法如下&#xff1a; [rootitxdl ~]# vim /test/vi.test 刚打开文件时 Vim 处于命令模式&#xff0c;此时文件…

CTFshow-pwn入门-前置基础pwn26-pwn28

什么是ASLR 大多数的攻击都基于这样一个前提&#xff0c;即攻击者知道程序的内存布局&#xff0c;需要提前知道shellcode或者其他一些数据的位置。因此&#xff0c;引入内存布局的随机化能够有效增加漏洞利用的难度&#xff0c;其中一种技术就是ASLR&#xff08;Address Space…

无线wifi视频传输方案|基于qca9531方案SKW99的无线视频流云端推送方案

为满足物联网智慧校园&#xff0c;智能家居&#xff0c;智慧工厂&#xff0c;智能交通、智慧博物馆、培训机构等不同行业实时直播的需求。本篇以集成200万高清摄像头功能的高通方案qca9531 wifi模块SKW99为为例&#xff0c;简单介绍基于WiFi技术的无线视频流云端推送方案。 1、…

上位机与两台PLC之间无线PPI通信

在实际系统中&#xff0c;人机界面与PLC通常不在一起&#xff0c;中心计算机一般放置在控制室&#xff0c;而PLC安装在现场车间&#xff0c;二者之间距离往往从几十米到几千米。如果布线的话&#xff0c;需要挖沟施工&#xff0c;比较麻烦&#xff0c;这种情况下比较适合采用无…

0基础学习VR全景平台篇第47篇:底部菜单-场景/分组复制功能

大家好&#xff0c;欢迎观看蛙色VR官方系列——后台使用课程&#xff01; 本期为大家带来蛙色VR平台&#xff0c;底部菜单—场景/分组复制功能操作。 功能位置示意 一、本功能将用在哪里&#xff1f; 平台用户在编辑作品时可以使用本功能将作品中的某一分组或者某一场景进行复…

岩土工程监测案例:完整链条的振弦传感器、采集仪和在线监测系统

岩土工程监测案例&#xff1a;完整链条的振弦传感器、采集仪和在线监测系统 在岩土工程监测中&#xff0c;振弦传感器被广泛应用于测量土体或岩体的振动情况&#xff0c;以了解地震或其他振动事件对结构物或地基的影响。振弦传感器具有高精度、快速响应、易于安装和低成本等优…