Windows 内核实现复制文件

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

#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;
}

说说你的想法