驱动学习:内核级占用修改文件

时间:2023-5-6    作者:123    分类: 博客文章


    学习内核近一个月的时间了,利用自己学到的那点知识做了个小玩意儿。

    简单说就是使用内核API函数ZwCreateFile ZwReadFile ZwWriteFile ZwClose 对文件进行操作。


    功能如下():

    1.打开文件(调用方法->需输入:\??\文件路径。打开后的文件会被驱动占用,占用时其他任何程序都无法查看,移动,复制)

    2.查看文件

    3.修改文件

    4.关闭文件(关闭文件后结束占用)

    0.退出系统


    占用效果图:

    06105539.png


    驱动代码:

    #include<ntddk.h>

    #define _DeviceName L"\\Device\\MyDeviceName"

    #define _DeviceSybLink L"\\??\\MyDeviceLink"

    #define USER_FILE_CREATE (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x810,METHOD_BUFFERED,FILE_READ_DATA)

    #define USER_FILE_SET (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x811,METHOD_BUFFERED,FILE_READ_DATA)

    #define USER_FILE_GET (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x812,METHOD_BUFFERED,FILE_READ_DATA)

    #define USER_FILE_CLOSE (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x813,METHOD_BUFFERED,FILE_READ_DATA)

    PUNICODE_STRING DeviceObject = { 0 };

    UNICODE_STRING DeviceName = { 0 };

    UNICODE_STRING DeviceSybLink = { 0 };

    

    HANDLE FileHandle = { 0 };

    

    NTSTATUS MyCallBack(PDEVICE_OBJECT _DeviceObject, PIRP Pirp) {

     ULONG Len = 4;

     NTSTATUS CallBackStatus = STATUS_SUCCESS;

     PIO_STACK_LOCATION Irp = IoGetCurrentIrpStackLocation(Pirp);

    

     NTSTATUS IoCreateFileStatus_ = { 0 };

    

     if (_DeviceObject == DeviceObject) {

     if (Irp->MajorFunction == IRP_MJ_CREATE) DbgPrint("驱动被调用了Create\n");

     if (Irp->MajorFunction == IRP_MJ_CLOSE) DbgPrint("驱动被调用了Close\n");

     if (Irp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {

     PVOID Buffer = Pirp->AssociatedIrp.SystemBuffer;

     ULONG InputLen = Irp->Parameters.DeviceIoControl.InputBufferLength;

     ULONG OutputLen = Irp->Parameters.DeviceIoControl.OutputBufferLength;

     switch (Irp->Parameters.DeviceIoControl.IoControlCode) {

     case USER_FILE_CREATE: {

     UNICODE_STRING FileName = { 0 };

     OBJECT_ATTRIBUTES ObjectAttributes;

     NTSTATUS IoCreateFileStatus = NULL;

     RtlInitUnicodeString(&FileName, Buffer);

     DbgPrint("Buffer:%wZ\n", &FileName);

     InitializeObjectAttributes(

     &ObjectAttributes,

     &FileName,

     OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,

     NULL,

     NULL

     );

     NTSTATUS IoCreateFileStatus_ = ZwCreateFile(

     &FileHandle,

     GENERIC_ALL,

     &ObjectAttributes,

     &IoCreateFileStatus,

     NULL,

     FILE_ATTRIBUTE_NORMAL,

     0,

     FILE_OPEN,

     FILE_SYNCHRONOUS_IO_NONALERT,

     NULL,

     0

     );

     if (IoCreateFileStatus_ == STATUS_SUCCESS) {

     char str[] = "执行成功打开文件";

     Len = sizeof(str);

     RtlCopyMemory(

     Buffer,

     &str,

     Len

     );

     DbgPrint("成功打开文件\n");

     }

     else {

     char str[] = "执行失败打开文件";

     Len = sizeof(str);

     RtlCopyMemory(

     Buffer,

     &str,

     Len

     );

     DbgPrint("失败打开文件,错误原因:0x%x\n",IoCreateFileStatus);

    

     }

     break;

     }

     case USER_FILE_GET: {

     NTSTATUS IoReadFileStatus = STATUS_SUCCESS;

     NTSTATUS IoReadFileStatus_ = STATUS_SUCCESS;

     char RetReadValue[128] = { 0 };

     LARGE_INTEGER FileStart = { 0 };

     FileStart.QuadPart = 0;

     IoReadFileStatus_ = ZwReadFile(

     FileHandle,

     NULL,

     NULL,

     NULL,

     &IoReadFileStatus,

     &RetReadValue,

     sizeof(RetReadValue),

     &FileStart,

     NULL

     );

     if (IoReadFileStatus_ == STATUS_SUCCESS) {

     Len = sizeof(RetReadValue);

     RtlCopyMemory(Buffer, &RetReadValue, Len);

     }

     else DbgPrint("读取失败,错误码:0x%x\n", IoReadFileStatus);

    

     break;

     }

     case USER_FILE_SET: {

     NTSTATUS IoWriteFileStatus_ = { 0 };

     NTSTATUS IoWriteFileStatus = { 0 };

     LARGE_INTEGER ByteOffset = { 0 };

     ByteOffset.QuadPart = 0;

     IoWriteFileStatus_ = ZwWriteFile(

     FileHandle,

     NULL,

     NULL,

     NULL,

     &IoWriteFileStatus,

     Buffer,

     strlen(Buffer), //因为取回的是字符串,Buffer又是个指针,必须用strlen取指针字符串长度

     &ByteOffset,

     NULL

     );

     if (IoWriteFileStatus_ == STATUS_SUCCESS) {

     Len = sizeof("文件修改成功");

     RtlCopyMemory(Buffer, "文件修改成功", Len);

    

     }

     else {

     Len = sizeof("文件修改失败");

     RtlCopyMemory(

     Buffer,

     "文件修改失败",

     Len

     );

     }

     break;

     }

     case USER_FILE_CLOSE: {

     if (FileHandle!=STATUS_SUCCESS) {

     ZwClose(FileHandle);

     FileHandle = NULL;

     RtlCopyMemory(Buffer, "文件已关闭", sizeof("文件已关闭"));

     Len = sizeof("文件已关闭");

     }

     else {

     RtlCopyMemory(Buffer, "没有文件开启", sizeof("没有文件开启"));

     Len = sizeof("没有文件开启");

     }

     break;

     }

    

     }

     }

     }

     else {

     DbgPrint("设备错误\n");

     CallBackStatus = STATUS_ACCESS_DENIED;

     }

    

     Pirp->IoStatus.Status = CallBackStatus;

     Pirp->IoStatus.Information = Len;

     IoCompleteRequest(Pirp, IO_NO_INCREMENT);

     return CallBackStatus;

    }

    

    VOID DriverUnload(PDRIVER_OBJECT DriverObject) {

     IoDeleteSymbolicLink(&DeviceSybLink);

     IoDeleteDevice(DeviceObject);

     DbgPrint("驱动卸载\n");

    }

    

    NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING Reg) {

     RtlInitUnicodeString(&DeviceName, _DeviceName);

     RtlInitUnicodeString(&DeviceSybLink, _DeviceSybLink);

     NTSTATUS IoCreateStatus=IoCreateDevice(

     DriverObject,

     0,

     &DeviceName,

     FILE_DEVICE_UNKNOWN,

     FILE_DEVICE_SECURE_OPEN,

     FALSE,

     &DeviceObject

     );

     if (IoCreateStatus == STATUS_SUCCESS) {

     DbgPrint("设备创建成功,设备对象:%p\n", DriverObject);

     NTSTATUS IoCreateSybStatus = IoCreateSymbolicLink(&DeviceSybLink, &DeviceName);

     if (IoCreateSybStatus == STATUS_SUCCESS) {

     DbgPrint("符号链接创建成功,链接名:%wZ\n", &DeviceSybLink);

     }

     }

     else DbgPrint("设备创建失败\n");

    

     DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCallBack;

     DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyCallBack;

     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyCallBack;

     DriverObject->DriverUnload = DriverUnload;

     return STATUS_SUCCESS;

    }


    可执行程序代码:

    #include <iostream>

    #include<windows.h>

    #define _DeviceSybLink L"\\\\.\\MyDeviceLink"

    #define USER_FILE_CREATE (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x810,METHOD_BUFFERED,FILE_READ_DATA)

    #define USER_FILE_SET (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x811,METHOD_BUFFERED,FILE_READ_DATA)

    #define USER_FILE_GET (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x812,METHOD_BUFFERED,FILE_READ_DATA)

    #define USER_FILE_CLOSE (ULONG)CTL_CODE(FILE_DEVICE_UNKNOWN,0x813,METHOD_BUFFERED,FILE_READ_DATA)

    HANDLE DeviceHandle = { 0 };

    

    int main();

    void createFile() {

        DWORD Ret = { 0 };

        WCHAR FileName[128] = { 0 };

        char retValue[128] = { 0 };

        //打开设备

        DeviceHandle = CreateFileW(

            _DeviceSybLink,

            GENERIC_READ | GENERIC_WRITE,

            0,

            0,

            OPEN_EXISTING,

            FILE_ATTRIBUTE_SYSTEM,

            0

        );

    

        printf("请输入文件名:");

        //传入字符串使用scanf_s时需传入第三个参数,也就是内存字节长度

        scanf_s("%ws", &FileName,sizeof(FileName));

    

        //使用控制码通信

        BOOL IoStatus = DeviceIoControl(

            DeviceHandle,

            USER_FILE_CREATE,

            &FileName,

            sizeof(FileName),

            &retValue,

            sizeof(retValue),

            &Ret,

            0

        );

        if (IoStatus == TRUE)printf("成功发送文件名\n");

        else printf("失败发送文件名\n");

    

        //内核向应用层传输字符串时,使用char类型吧,因为WCHAR宽字符类型的内核向应用传输还未掌握。

        printf("%s\n", &retValue);

    

        system("pause");

        main();

    }

    

    void readFile() {

        char RetFileValue[128] = { 0 };

        DWORD RetNum = { 0 };

        BOOL IoStatus = DeviceIoControl(

            DeviceHandle,

            USER_FILE_GET,

            NULL,

            0,

            &RetFileValue,

            sizeof(RetFileValue),

            &RetNum,

            0

        );

        if (IoStatus == TRUE) printf("成功,文件内容:%s\n",&RetFileValue);

        else printf("失败\n");

    

        system("pause");

        main();

    }

    

    void setFile() {

        char inputValue[128] = { 0 };

        char retValue[128] = { 0 };

        DWORD Ret = { 0 };

        printf("请输入要修改的值:");

        //如果应用层传入到内核层要修改的值是char类型的,

        //那么内核层传回修改后的内容也要是char类型的,

        //否则会显示错误

        scanf_s("%s", &inputValue, sizeof(inputValue));

        BOOL IoStatus = DeviceIoControl(

            DeviceHandle,

            USER_FILE_SET,

            &inputValue,

            sizeof(inputValue),

            &retValue,

            sizeof(retValue),

            &Ret,

            0

        );

        if (IoStatus == TRUE) printf("%s\n", &retValue);

        else printf("Io通信失败\n");

    

        system("pause");

        main();

    }

    

    void closeFile() {

        DWORD RetNum = { 0 };

        char retValue[128] = { 0 };

        BOOL IoStatus = DeviceIoControl(

            DeviceHandle,

            USER_FILE_CLOSE,

            NULL,

            0,

            &retValue,

            sizeof(retValue),

            &RetNum,

            0

        );

        printf("%s\n", &retValue);

    

        system("pause");

        main();

    }

    

    int main(){

        int ctl_code = -1;

        //while (1) {

            printf("1.打开文件\n");

            printf("2.查看文件\n");

            printf("3.修改文件\n");

            printf("4.关闭文件\n");

            printf("0.退出系统\n");

            scanf_s("%d", &ctl_code);

            switch (ctl_code) {

            case 1: {

                createFile();

                break;

            }

            case 2: {

                readFile();

                break;

            }

            case 3: {

                setFile();

                break;

            }

            case 4: {

                closeFile();

                break;

            }

            case 0:

                exit(0);

                break;

            }

            

    

        //}

        

    }