Joe1sn's Cabinet

windows内核驱动 3-文件操作

之前写过:windows内核驱动 1-环境搭建windows内核驱动 2-页表探索

但是内容确实有点衔接不上,这里根据【Win Pwn】HEVD-内核栈溢出(上)中展示的基础技巧来继续

项目结构优化

image-20240317165802241

之前写过的所有功能都在main.c中,新加入IoctlFuncs,这里来写所有的ioctl功能,那么就要重新设计MyControl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
ULONG ioCode = pStack->Parameters.DeviceIoControl.IoControlCode;
ULONG inLen = pStack->Parameters.DeviceIoControl.InputBufferLength;

ULONG ioInfo = 0;
switch (ioCode)
{
case IOCTL_MUL:
{
DWORDLONG inData = *(PDWORDLONG)pIrp->AssociatedIrp.SystemBuffer;
DbgPrint("Kernel Recive: %d, Len: %lld\n", inData, inLen);
inData *= 2;
DbgPrint("Kernel Data %d\n", inData);
*(PDWORDLONG)pIrp->AssociatedIrp.SystemBuffer = inData;
ioInfo = 4;
break;
}

default:
RET = STATUS_UNSUCCESSFUL;
ioInfo = 0;
break;
}

这里分析得到我们需要的函数,大概可以声明为

1
2
3
4
5
6
7
8
9
10
11
ULONG Mul(PIRP pIrp) {
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
ULONG inLen = pStack->Parameters.DeviceIoControl.InputBufferLength;
DWORDLONG inData = *(PDWORDLONG)pIrp->AssociatedIrp.SystemBuffer;
DbgPrint("Kernel Recive: %d, Len: %lld\n", inData, inLen);
inData *= 2;
DbgPrint("Kernel Data %d\n", inData);
*(PDWORDLONG)pIrp->AssociatedIrp.SystemBuffer = inData;
return (ULONG)inData;
//return 4;
}

注意新建的文件要以.c结尾

image-20240317171836424

文件操作

  • ZwXXXX -> 系统检查 -> NtXXXX
  • R3下都一样

文件删除

使用到的API是

1
2
3
NTSYSAPI NTSTATUS ZwDeleteFile(
[in] POBJECT_ATTRIBUTES ObjectAttributes
);

参数为

1
2
3
4
5
6
7
8
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;

初始化改参数的api

1
2
3
4
5
6
7
VOID InitializeObjectAttributes(
[out] POBJECT_ATTRIBUTES p,
[in] PUNICODE_STRING n,
[in] ULONG a,
[in] HANDLE r,
[in, optional] PSECURITY_DESCRIPTOR s
);

整个函数以及使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
NTSTATUS KernelDeleteFile(PWCHAR filePath) {
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING FilePath = { 0 };
RtlInitUnicodeString(&FilePath, filePath);
DbgPrint("[Kernel Delete File] The File Path is %wZ\n", FilePath);

OBJECT_ATTRIBUTES FileAttribute = { 0 };
InitializeObjectAttributes(&FileAttribute, &FilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwDeleteFile(&FileAttribute);
if (!NT_SUCCESS(status))
DbgPrint("Create Device Failed: %x\n", status);
return status;
}

NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
//.........
KernelDeleteFile(L"\\??\\C:\\exp.exe");

return Status;
}

image-20240317174745958

文件复制

属于是把大象装进冰箱分几步

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
NTSTATUS KernelCopyFile(PWCHAR dstFile, PWCHAR srcFile) {
// 1-Declear Related Variable
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING DstFilePath = { 0 };
UNICODE_STRING SrcFilePath = { 0 };
RtlInitUnicodeString(&DstFilePath, dstFile);
RtlInitUnicodeString(&SrcFilePath, srcFile);
IO_STATUS_BLOCK IoBlock = { 0 };
HANDLE hSrcFile = NULL;
HANDLE hDstFile = NULL;
//----------------------

// 2-Init Related Variable
OBJECT_ATTRIBUTES DstFileAttribute = { 0 };
OBJECT_ATTRIBUTES SrcFileAttribute = { 0 };
InitializeObjectAttributes(&DstFileAttribute, &DstFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
InitializeObjectAttributes(&SrcFileAttribute, &SrcFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);

// 3-Open File
status = ZwOpenFile(&hSrcFile, GENERIC_ALL, &SrcFileAttribute, &IoBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(status)) {
DbgPrint("Open File %wZ Failed, status: %x\n", SrcFilePath, status);
return status;
}

// 4-Get Source File Size & Allocate Transfer Buffer
FILE_STANDARD_INFORMATION StdFileInfo = { 0 };
status = ZwQueryInformationFile(hSrcFile, &IoBlock, &StdFileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(status)) {
DbgPrint("Query File %wZ Failed, status: %x\n", SrcFilePath, status);
ZwClose(hSrcFile);
return status;
}
DbgPrint("IoBlock size %d\n", IoBlock.Information);
DbgPrint("StdFileInfo size %d\n", StdFileInfo.EndOfFile.QuadPart);

PVOID Transfer = ExAllocatePool2(POOL_FLAG_NON_PAGED, StdFileInfo.EndOfFile.QuadPart, 'ymym');
if (Transfer == NULL) {
DbgPrint("ExAllocatePool Transfer Buffer Failed, status: %x\n", status);
ZwClose(hSrcFile);
return status;
}
RtlZeroMemory(Transfer, StdFileInfo.EndOfFile.QuadPart);

// 5-Read Source File To Buffer
LARGE_INTEGER TempReadCount = { 0 };
status = ZwReadFile(hSrcFile, NULL, NULL, NULL, &IoBlock, Transfer, (ULONG)StdFileInfo.EndOfFile.QuadPart, &TempReadCount, NULL);
if (!NT_SUCCESS(status)) {
DbgPrint("Read to Transfer Buffer Failed, status: %x\n", status);
ExFreePool(Transfer);
return status;
}
DbgPrint("Io info: %d", IoBlock.Information);
ZwClose(hSrcFile);

// 6-Create New File
status = ZwCreateFile(&hDstFile, GENERIC_ALL, &DstFileAttribute, &IoBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status)) {
DbgPrint("Create File Failed, status: %x\n", status);
ExFreePool(Transfer);
return status;
}

// 7-Write to New File
status = ZwWriteFile(hDstFile, NULL, NULL, NULL, &IoBlock, Transfer, (ULONG)StdFileInfo.EndOfFile.QuadPart, &TempReadCount, NULL);
if (!NT_SUCCESS(status)) {
DbgPrint("Write File Failed, status: %x\n", status);
ExFreePool(Transfer);
ZwClose(hDstFile);
return status;
}
ZwClose(hDstFile);
DbgPrint("Write %d\n", IoBlock.Information);
DbgPrint("Created New File %wZ\n", DstFilePath);
return status;
}

image-20240317193310825

优化到IOCTL

文件删除

驱动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
NTSTATUS KernelDeleteFile(PIRP pIrp) {
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
ULONG filePathLen = pStack->Parameters.DeviceIoControl.InputBufferLength;

WCHAR filePath[0x1000] = { 0 };// = pIrp->AssociatedIrp.SystemBuffer;
if (filePathLen >= 0x1000) {
DbgPrint("Size of file path is too big\n");
return status;
}
UNICODE_STRING FilePath = { 0 };
RtlZeroMemory(filePath, 0x1000);
RtlCopyMemory(filePath, pIrp->AssociatedIrp.SystemBuffer, filePathLen);
RtlInitUnicodeString(&FilePath, filePath);

DbgPrint("Now Delete File %wZ\n", FilePath);

OBJECT_ATTRIBUTES FileAttribute = { 0 };
InitializeObjectAttributes(&FileAttribute, &FilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwDeleteFile(&FileAttribute);
if (!NT_SUCCESS(status))
DbgPrint("Delete Device Failed: %x\n", status);
return status;
}

客户端

1
2
3
4
5
6
7
void KDeleteFile(HANDLE hDevice, const wchar_t filepath[]) {
DWORD info = 0;
std::wstring prefix = L"\\??\\";
std::wstring r3path = filepath;
r3path = prefix + r3path;
DeviceIoControl(hDevice, IOCTL_DELETE_FILE, (LPVOID)r3path.c_str(), (r3path.size()) * 2 - 1, NULL, 0, &info, NULL);
}

文件复制

驱动

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
NTSTATUS KernelCopyFile(PIRP pIrp) {

// 0-Get Param
ParamKernelCopyFile Param = { 0 };
WCHAR dstFile[0x1000] = { 0 };
WCHAR srcFile[0x1000] = { 0 };
RtlZeroMemory(dstFile, 0x1000);
RtlZeroMemory(srcFile, 0x1000);

RtlCopyMemory((PVOID)&Param, pIrp->AssociatedIrp.SystemBuffer, sizeof(ParamKernelCopyFile));
RtlCopyMemory((PVOID)dstFile, Param.dstFile, Param.dstFileLen);
RtlCopyMemory((PVOID)srcFile, Param.srcFile, Param.srcFileLen);

//DbgPrint("")


// 1-Declear Related Variable
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING DstFilePath = { 0 };
UNICODE_STRING SrcFilePath = { 0 };
RtlInitUnicodeString(&DstFilePath, dstFile);
RtlInitUnicodeString(&SrcFilePath, srcFile);
IO_STATUS_BLOCK IoBlock = { 0 };
HANDLE hSrcFile = NULL;
HANDLE hDstFile = NULL;
//----------------------

// 2-Init Related Variable
OBJECT_ATTRIBUTES DstFileAttribute = { 0 };
OBJECT_ATTRIBUTES SrcFileAttribute = { 0 };
InitializeObjectAttributes(&DstFileAttribute, &DstFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);
InitializeObjectAttributes(&SrcFileAttribute, &SrcFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL);

// 3-Open File
status = ZwOpenFile(&hSrcFile, GENERIC_ALL, &SrcFileAttribute, &IoBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(status)) {
DbgPrint("Open File %wZ Failed, status: %x\n", SrcFilePath, status);
return status;
}

// 4-Get Source File Size & Allocate Transfer Buffer
FILE_STANDARD_INFORMATION StdFileInfo = { 0 };
status = ZwQueryInformationFile(hSrcFile, &IoBlock, &StdFileInfo, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
if (!NT_SUCCESS(status)) {
DbgPrint("Query File %wZ Failed, status: %x\n", SrcFilePath, status);
ZwClose(hSrcFile);
return status;
}

PVOID Transfer = ExAllocatePool2(POOL_FLAG_NON_PAGED, StdFileInfo.EndOfFile.QuadPart, 'ymym');
if (Transfer == NULL) {
DbgPrint("ExAllocatePool Transfer Buffer Failed, status: %x\n", status);
ZwClose(hSrcFile);
return status;
}
RtlZeroMemory(Transfer, StdFileInfo.EndOfFile.QuadPart);

// 5-Read Source File To Buffer
LARGE_INTEGER TempReadCount = { 0 };
status = ZwReadFile(hSrcFile, NULL, NULL, NULL, &IoBlock, Transfer, (ULONG)StdFileInfo.EndOfFile.QuadPart, &TempReadCount, NULL);
if (!NT_SUCCESS(status)) {
DbgPrint("Read to Transfer Buffer Failed, status: %x\n", status);
ExFreePool(Transfer);
return status;
}
ZwClose(hSrcFile);

// 6-Create New File
status = ZwCreateFile(&hDstFile, GENERIC_ALL, &DstFileAttribute, &IoBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
if (!NT_SUCCESS(status)) {
DbgPrint("Create File Failed, status: %x\n", status);
ExFreePool(Transfer);
return status;
}

// 7-Write to New File
status = ZwWriteFile(hDstFile, NULL, NULL, NULL, &IoBlock, Transfer, (ULONG)StdFileInfo.EndOfFile.QuadPart, &TempReadCount, NULL);
if (!NT_SUCCESS(status)) {
DbgPrint("Write File Failed, status: %x\n", status);
ExFreePool(Transfer);
ZwClose(hDstFile);
return status;
}
ZwClose(hDstFile);
DbgPrint("Created New File %wZ\n", DstFilePath);
return status;
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void KCopyFile(HANDLE hDevice, const wchar_t srcpath[], const wchar_t dstpath[]) {
ParamKernelCopyFile param = { 0 };
DWORD info = 0;
std::wstring prefix = L"\\??\\";
std::wstring SRC = srcpath;
std::wstring DST = dstpath;
SRC = prefix + SRC;
DST = prefix + DST;

param.dstFile = (PWCHAR)DST.c_str();
param.srcFile = (PWCHAR)SRC.c_str();
param.dstFileLen = DST.size() * 2 - 1;
param.srcFileLen = SRC.size() * 2 - 1;

std::wcout << L"SRC Path " << param.srcFile << std::endl;
std::wcout << L"DST Path " << param.dstFile << std::endl;
DeviceIoControl(hDevice, IOCTL_COPY_FILE, (LPVOID)&param, sizeof(param), NULL, 0, &info, NULL);

}

更好的文件复制

复制的时候使用内存大小,但是内核内存还是得节省着用,而且大文件可能会整数溢出

写个write的循环就行了

但是想了想涉及到文件追加啥的,我是懒狗