Windows 内核编程并没有提供像 Ring3 层的 CopyFile 这样的 API,看了看书中的例子自己写了一份 MyCopyFile,以后用来备用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <ntddk.h>

#ifndef MEM_TAG
#define MEM_TAG 'MyTt'
#endif

NTSTATUS MyOpenFile(
HANDLE* handle,
IO_STATUS_BLOCK* io_status,
CONST PUNICODE_STRING file_path)
{
NTSTATUS status;
OBJECT_ATTRIBUTES object_attributes;

InitializeObjectAttributes(
&object_attributes,
file_path,
OBJ_CASE_INSENSITIVE OBJ_KERNEL_HANDLE,
NULL, NULL);

status = ZwCreateFile(
handle, // 文件句柄
GENERIC_READ GENERIC_WRITE, // 打开文件的权限
&object_attributes, // 文件对象的描述信息
io_status, // 操作结果结构体
NULL, // 文件创建后的初始大小
FILE_ATTRIBUTE_NORMAL, // 文件属性信息
FILE_SHARE_READ, // 其他文件打开时的属性
FILE_OPEN_IF, // 如果文件存在,则打开;如果不存在,则创建
FILE_NON_DIRECTORY_FILE FILE_RANDOM_ACCESS FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);

return status;
}

NTSTATUS MyCopyFile(PUNICODE_STRING target_path, PUNICODE_STRING source_path)
{
NTSTATUS status;
// 创建源文件和目标文件句柄
HANDLE target = NULL;
HANDLE source = NULL;

// buffer
PVOID buffer = NULL;
// offset
LARGE_INTEGER offset = { 0 };
// io_status
IO_STATUS_BLOCK io_status = { 0 };

#if DBG
_asm int 3
#endif

do
{
// 分别打开文件得到文件句柄
MyOpenFile(&source, &io_status, source_path);
MyOpenFile(&target, &io_status, target_path);

// 分配一个缓冲区用来存储每次读取的内容
buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, 4096, MEM_TAG);

// ZwReadFile 和 ZwWriteFile 所需的两个参数
IO_STATUS_BLOCK IoStatus = { 0 };
ULONG length = 4 * 1024;

while (1)
{
// 读取
status = ZwReadFile(source, NULL, NULL, NULL,
&IoStatus, buffer, length, &offset, NULL);
if (!NT_SUCCESS(status))
{
if (status == STATUS_END_OF_FILE)
{
status = STATUS_SUCCESS;
}
break;
}

// 获取实际读到的大小
length = IoStatus.Information;

// 根据读取到的实际大小写入到另外一个文件中
status = ZwWriteFile(target, NULL, NULL, NULL,
&IoStatus, buffer, length, &offset, NULL);
if (!NT_SUCCESS(status))
break;

// offset 后移
offset.QuadPart += IoStatus.Information;
}

} while (0);

if (target != NULL)
ZwClose(target);
if (source != NULL)
ZwClose(source);
if (buffer != NULL)
ExFreePool(buffer);

return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING src = RTL_CONSTANT_STRING(L"\\??\\C:\\1.txt");
UNICODE_STRING dst = RTL_CONSTANT_STRING(L"\\??\\C:\\2.txt");
MyCopyFile(&dst, &src);
return STATUS_UNSUCCESSFUL;
}