文件 注册表 多线程
1、文件操作
文件操作,内核模式下打开、创建、拷贝文件
#include <ntddk.h>
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
KdPrint(("驱动成功卸载\n"));
}
void MyCopyFile(HANDLE source, HANDLE dest)
{
NTSTATUS status;
PVOID buffer = NULL;
LARGE_INTEGER offset = { 0 };
IO_STATUS_BLOCK io_status = { 0 };
buffer = ExAllocatePool(PagedPool, 4*1024*sizeof(char));
if (buffer == NULL)
{
KdPrint(("分配读写buffer空间失败"));
return;
}
int length = 1024 * 4;
do
{
while (1)
{
status = ZwReadFile(source, NULL, NULL, NULL, &io_status, buffer, length, &offset, NULL);
if (!NT_SUCCESS(status))
{
if (status == STATUS_END_OF_FILE)
status = STATUS_SUCCESS;
break;
}
length = io_status.Information;
status = ZwWriteFile(dest, NULL, NULL, NULL, &io_status,buffer, length, &offset, NULL);
if (!NT_SUCCESS(status))
break;
offset.QuadPart += length;
}
} while (0);
if (buffer != NULL)
ExFreePool(buffer);
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING reg_path)
{
NTSTATUS status;
KdPrint(("%wZ",reg_path));
UNICODE_STRING unicSourceName, unicDestName;
RtlInitUnicodeString(&unicSourceName, L"\\??\\c:\\test\\sql.txt");
KdPrint(("source file is: %wZ", &unicSourceName));
RtlInitUnicodeString(&unicDestName, L"\\??\\c:\\test\\sqltest.txt");
KdPrint(("dest file is: %wZ", &unicDestName));
HANDLE hSourceHandle = NULL;
HANDLE hDestHandle = NULL;
OBJECT_ATTRIBUTES object_attributes1, object_attributes2;
IO_STATUS_BLOCK iostatus;
//初始化文件属性
InitializeObjectAttributes(
&object_attributes1,
&unicSourceName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
InitializeObjectAttributes(
&object_attributes2,
&unicDestName,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
);
status = ZwCreateFile(
&hSourceHandle,
GENERIC_READ | GENERIC_WRITE,
&object_attributes1,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(status))
{
KdPrint(("文件打开失败"));
KdPrint(("失败原因:%d", iostatus.Information));
}
status = ZwCreateFile(
&hDestHandle,
GENERIC_READ | GENERIC_WRITE,
&object_attributes2,
&iostatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (!NT_SUCCESS(status))
{
KdPrint(("创建文件失败"));
KdPrint(("失败原因:%d", iostatus.Information));
}
MyCopyFile(hSourceHandle, hDestHandle);
ZwClose(hDestHandle);
ZwClose(hSourceHandle);
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
2、注册表操作
内核程序读写注册表跟应用程序API大致相似,应用程序根子键句柄与内核注册表路径对应表如下:
应用程序对应的子键 | 驱动编程中的路径写法 |
---|---|
HKEY_LOCAL_MACHINE | \Registry\Machine |
KEY_USERS | \Registry\User |
HEY_CLASSES_ROOT | 没有对应的路径 |
HKEY_CURRENT_USER | 没有对应的路径,但是可以求得 |
内核程序读写注册表步骤为:InitilizeObjectAttributes初始化OBJECT_ATTRIBUTES,ZwCreateKey或者ZwOpenKey打开注册表键获取句柄,ZwQueryValueKey第一次调用获取注册表键值需要存储的空间大小,ZwQueryValueKey第二次调用会把注册表键值信息(类型、值数据)保存在KEY_VALUE_PARTIAL_INFORMATION结构中。根据该结构中的Type分类解析数据,REG_DWORD、REG_SZ,常用的是双字节和字符串型,如何取值参考完整代码,写入注册表值使用ZwSetValueKey,关闭注册表句柄ZwClose,API参数如下:
InitializeObjectAttributes参数初始化OBJECT_ATTRIBUTES
VOID
InitializeObjectAttributes(
OUT POBJECT_ATTRIBUTES InitializedAttributes ,
IN PUNICODE_STRING ObjectName ,
IN ULONG Attributes ,
IN HANDLE RootDirectory ,
IN PSECURITY_DESCRIPTOR SecurityDescriptor
);
ZwCreateKey以创建的方式打开注册表
NTSYSAPI NTSTATUS ZwCreateKey(
PHANDLE KeyHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
ULONG TitleIndex,
PUNICODE_STRING Class,
ULONG CreateOptions,
PULONG Disposition
);
ZwOpenKey打开注册表
NTSYSAPI NTSTATUS ZwOpenKey(
PHANDLE KeyHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
);
ZwQueryValueKey查询注册表路径下的项值
NTSYSAPI NTSTATUS ZwQueryValueKey(
HANDLE KeyHandle,
PUNICODE_STRING ValueName,
KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
PVOID KeyValueInformation,
ULONG Length,
PULONG ResultLength
);
ZwSetValueKey写注册表值
NTSYSAPI NTSTATUS ZwSetValueKey(
HANDLE KeyHandle,
PUNICODE_STRING ValueName,
ULONG TitleIndex,
ULONG Type,
PVOID Data,
ULONG DataSize
);
ZwClose注册表操作完后关闭注册表句柄
NTSTATUS
NTAPI
ZwClose(
_In_ HANDLE Handle
);
完整操作注册表的函数如下
void GetKeyValue(PKEY_VALUE_PARTIAL_INFORMATION pKeyValue_infor, PUNICODE_STRING unicString, PULONG ulVaule)
{
switch (pKeyValue_infor->Type)
{
case REG_BINARY:
{
break;
}
case REG_DWORD:
{
*ulVaule = *(PULONG)(pKeyValue_infor->Data);
break;
}
case REG_DWORD_BIG_ENDIAN:
{
break;
}
case REG_EXPAND_SZ:
{
break;
}
case REG_MULTI_SZ:
{
break;
}
case REG_SZ:
{
RtlInitUnicodeString(unicString, (PCWSTR)(pKeyValue_infor->Data));
break;
}
default:
{
break;
}
}
}
void RegReadWrite()
{
HANDLE my_key = NULL;
NTSTATUS status;
//注册表路径
UNICODE_STRING my_key_path = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
//UNICODE_STRING my_key_newPath = RTL_CONSTANT_STRING(L"")
OBJECT_ATTRIBUTES my_object_attr = {0};
InitializeObjectAttributes(&my_object_attr, &my_key_path, OBJ_CASE_INSENSITIVE,NULL,NULL);
//打开key
status = ZwOpenKey(&my_key, GENERIC_ALL, &my_object_attr);
if (!NT_SUCCESS(status))
{
KdPrint(("打开注册表项失败"));
}
UNICODE_STRING my_key_name = RTL_CONSTANT_STRING(L"UBR");
KEY_VALUE_PARTIAL_INFORMATION key_infor; //试探需要的空间
PKEY_VALUE_PARTIAL_INFORMATION ac_key_infor; //重新分配的空间
ULONG ac_length; //实际返回的字节长度
status = ZwQueryValueKey(
my_key,
&my_key_name,
KeyValuePartialInformation,
&key_infor,
sizeof(KEY_VALUE_PARTIAL_INFORMATION),
&ac_length
);
if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
{
//错误处理
ZwClose(my_key);
return;
}
ac_key_infor = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, ac_length, 'TEST');
if (ac_key_infor == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
//错误处理
ZwClose(my_key);
return;
}
status = ZwQueryValueKey(
my_key,
&my_key_name,
KeyValuePartialInformation,
ac_key_infor,
ac_length,
&ac_length
);
if (!NT_SUCCESS(status))
{
KdPrint(("Get key error"));
//错误处理
ZwClose(my_key);
return;
}
UNICODE_STRING keyString;
ULONG lKeyValue;
//解析值
GetKeyValue(ac_key_infor, &keyString, &lKeyValue);
if (ac_key_infor->Type == REG_DWORD)
KdPrint(("DWORD %d",lKeyValue ));
else if (ac_key_infor->Type == REG_SZ)
KdPrint(("UNICODE STRING %wZ", &keyString));
//写注册表数据
UNICODE_STRING writeRegName1, writeRegName2;
RtlInitUnicodeString(&writeRegName1, L"test1");
RtlInitUnicodeString(&writeRegName2, L"test2");
PWCHAR pData1 = { L"test set value" };
status = ZwSetValueKey(my_key, &writeRegName1, 0, REG_SZ, pData1, (wcslen(pData1)+1)*sizeof(WCHAR));
if (!NT_SUCCESS(status))
{
KdPrint(("set key value1 error"));
ZwClose(my_key);
return;
}
ULONG ulValue = 0x1008;
status = ZwSetValueKey(my_key, &writeRegName2, 0, REG_DWORD, &ulValue, sizeof(ulValue));
if (!NT_SUCCESS(status))
{
KdPrint(("set key value2 error"));
ZwClose(my_key);
return;
}
ZwClose(my_key);
}
运行截图
4、线程使用
内核模式下创建线程跟应用程序类似,创建线程函数,传参数,同步事件等,下面是一个例子可以传结构体参数,同步等待事件
线程函数部分
static KEVENT event;
typedef struct addParam
{
ULONG param1;
ULONG param2;
}ADD_PARAM;
void MyThread(PVOID param)
{
ADD_PARAM * stParam = (ADD_PARAM*)param;
ULONG ulRet;
ulRet = stParam->param1 + stParam->param2;
KdPrint(("%d + %d = %d", stParam->param1, stParam->param2, ulRet));
KeSetEvent(&event, 0, TRUE);
PsTerminateSystemThread(STATUS_SUCCESS);
}
线程创建代码
//创建线程
HANDLE hThread = NULL;
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
ADD_PARAM stThreadData = {1,5};
status = PsCreateSystemThread(&hThread, 0, NULL, NULL, NULL, MyThread, (PVOID)&stThreadData);
if (!NT_SUCCESS(status))
{
KdPrint(("创建系统线程失败"));
}
ZwClose(hThread);
KeWaitForSingleObject(&event, Executive, KernelMode, 0, 0);