tiechui_lesson05_内核小文件拷贝

news/2024/10/18 14:21:12/

主要学习在内核中的文件操作,包括文件的打开,创建,读取,写入,查询文件属性等。

涉及的API和宏函数

  • ZwOpenFile
  • ZwCreateFile
  • ZwQueryInformationFile
  • ZwReadFile
  • ZwWriteFile
  • ZwClose
  • InitializeObjectAttributes

1.文件的打开

ZwOpenFile

/************************************************************************
* 函数名称:ZwOpenFile
* 功能描述:打开文件
* 参数列表:FileHandle:返回打开的文件句柄DesiredAccess:打开的权限,一般设为GENERIC_ALLObjectAttributes:objectAttributes结构IoStatusBlock:指向一个结构体的指针。该结构体指明打开文件的状态ShareAccess:共享的权限。可以是FILE_SHARE_READ或者FILE_SHARE_WRITEOpenOptions:打开选项,一般设为FILE_SYNCHRONOUS_IO_NONALERT
* 返回 值:指明文件是否被成功打开
*************************************************************************/
NTSTATUS ZwOpenFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN ULONG ShareAccess,IN ULONG OpenOptions);

 使用示例:

OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;
UNICODE_STRING logFileUnicodeString;//初始化UNICODE_STRING字符串
RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log");
//或者写成 \\Device\\HarddiskVolume1\\1.log//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,&logFileUnicodeString,OBJ_CASE_INSENSITIVE,NULL,NULL);//创建文件
NTSTATUS ntStatus = ZwOpenFile(&hfile,GENERIC_ALL,&objectAttributes,&iostatus,FILE_SHARE_READ || FILE_SHARE_WRITE,FILE_SYNCHRONOUS_IO_NONALERT);
if( NT_SUCCESS(ntStatus) )
{KdPrint(("Create FILE successfully!\n"));
}
else
{KdPrint(("Create FILE unsuccessfully!\n"));
}//文件操作
//..........//关闭文件句柄
ZwClose(hfile);

2.文件的创建

ZwCreateFile

/************************************************************************
* 函数名称:ZwCreateFile
* 功能描述:文件的创建
* 参数列表:FileHandle:返回打开文件的句柄DesiredAccess:对打开文件操作的描述,读,写或是其他。一般指定为GENERIC_READ 或 GENERIC_WRITEObjectAttributes:是OBJECT_ATTRIBUTES结构的地址,该结构包含要打开的文件名IoStatusBlock:指向一个IO_STATUS_BLOCK结构,该结构接收ZwCreateFile操作的结果状态AllocationSize:是一个指针,指向一个64位整数,该数指定文件初始分配时的大小该参数仅关系到创建或重写文件操作,如果忽略它,那么文件长度从0开始病随着写入而增长FileAttributes:0或FILE_ATTRIBUTE_NORMAL,指定新创建文件的属性ShareAccess:FILE_SHARE_READ或0,指定文件的共享方式。如果为写数据而打开文件,可能不希望其他线程访问该文件CreateDisposition:FILE_OPEN或FILE_OVERWRITE_IF,表明当指定文件存在或不存在时应如何处理CreateOptions:FILE_SYNCHARONOUS_IO_NONALERT,指定控制打开操作和句柄使用的附加标志位EaBuffer:一个指针,指向可选的扩展属性区EaLength:扩展属性区的长度
* 返回 值:    NTSTATUS
*************************************************************************/
NTSTATUS ZwCreateFile(OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition,IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength);/*
*备注:
* 1、CreateDisposition参数。
*     如果想打开文件,CreateDisposition参数设置成FILE_OPEN. 
*     如果想创建文件,CreateDisposition参数设置成FILE_OVERWRITE_IF
*        此时,无论文件是否存在,都会创建新文件
* 2、文件名是通过第三个参数ObjectAttributes
*     这个参数是一个OBJECT_ATTRIBUTES结构体
*     通过InitializeObjectAttributes初始化
*/

InitializeObjectAttributes

这实际是一个宏,用来初始化属性变量的内容:

/************************************************************************
* 函数名称:InitializeObjectAttributes
* 功能描述:初始化OBJECT_ATTRIBUTES结构体
* 参数列表:InitializedAttributes:返回的OBJECT_ATTRIBUTES结构体ObjectName:对象名称,用UNICODE_STRING描述,这里设置的是文件名Attributes:一般设置为OBJ_CASE_INSENSITIVE,对大小写敏感RootDirectory:一般设置为NULLSecurityDescriptor:一般设置为NULL
* 返回 值:相等的字节数不一致返回零        
*************************************************************************/
VOID InitializeObjectAttributes(OUT POBJECT_ATTRIBUTES InitializedAttributes,IN PUNICODE_STRING ObjectName,IN ULONG Attributes,IN HANDLE RootDirectory,IN PSECURITY_DESCRIPTOR SecurityDescriptor);/*
*备注:
* 1、文件名[必须]是符号链接或者是设备名
* 2、例如:盘符 "c:",就是一个符号链接
*        这里应该用 "\??\c:" 代替 
*        "c:\1.log" 要写成 "\??\c:\1.log"
* 3、其中 "\??\c:" 是符号链接,内核会将它转换成设备名 "\Device\HarddiskColume1"
*/

3.获取文件属性 

ZwQueryInformationFile

/************************************************************************
* 函数名称:ZwQueryInformationFile
* 功能描述:获取文件属性
* 参数列表:FileHandle:文件句柄IoStatusBlock:返回设置的状态FileInformation:依据FileInformationClass不同而不同。作为输出信息Length:FileInformation数据的长度FileInformationClass:描述修改属性的类型
* 返回 值:设置属性查询
*************************************************************************/
NTSTATUS ZwQueryInformationFile(IN HANDLE FileHandle,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID FileInformation,IN ULONG Length,IN FILE_INFORMATION_CLASS FileInformationClass);

4.文件的读取

ZwReadFile

/************************************************************************
* 函数名称:ZwReadFile
* 功能描述:文件的读操作
* 参数列表:FileHandle:文件打开的句柄Event:很少用到,一般设为NULLApcRoutine:很少用到,一般设为NULLApcContext:很少用到,一般设为NULLIoStatusBlock:记录些操作的状态。其中,IoStatusBlock.Infomation记录实际写了多少字节Buffer:从这个缓冲区开始开始从文件里读Length:准备读多少字节Byteoffset:从文件的多少偏移地址开始读Key:很少用到,一般设为NULL
* 返回 值:
*************************************************************************/
NTSTATUS ZwReadFile(IN HANDLE FileHandle,IN HANDLE Event OPTIONAL,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PVOID Buffer,IN ULONG Length,IN PLARGE_INTEGER Byteoffset OPTIONAL,IN PULONG Key OPTIONAL);

5.文件的写入

ZwWriteFile

/************************************************************************
* 函数名称:ZwWriteFile
* 功能描述:文件的写操作
* 参数列表:FileHandle:文件打开的句柄Event:很少用到,一般设为NULLApcRoutine:很少用到,一般设为NULLApcContext:很少用到,一般设为NULLIoStatusBlock:记录些操作的状态。其中,IoStatusBlock.Infomation记录实际写了多少字节Buffer:从这个缓冲区开始往文件里写Length:准备写多少字节Byteoffset:从文件的多少便宜地址开始写Key:很少用到,一般设为NULL
* 返回 值:
*************************************************************************/
NTSTATUS ZwWriteFile(IN HANDLE FileHandle,IN HANDLE Event OPTIONAL,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PVOID Buffer,IN ULONG Length,IN PLARGE_INTEGER Byteoffset OPTIONAL,IN PULONG Key OPTIONAL);

综合使用:实现文件拷贝

仅支持小文件,而且没有和应用层交互

#include <ntifs.h>
#include <windef.h>	//使用DWORD等类型#define DEVICE_NAME L"\\Device\\MyFirstDeviceFilerw"		//设备名称
#define SYM_NAME	L"\\??\\MyFirstDeviceFilerw"			//符号链接//定义自定义控制码 (做一个减法)
#define IOCTL_MUL	CTL_CODE(FILE_DEVICE_UNKNOWN,0x855,METHOD_BUFFERED, FILE_ANY_ACCESS)//分发函数
NTSTATUS MyCreate(PDEVICE_OBJECT pdevice, PIRP pirp)
{UNREFERENCED_PARAMETER(pdevice);NTSTATUS status = STATUS_SUCCESS;DbgPrint("My Device has be opened!");pirp->IoStatus.Status = status;pirp->IoStatus.Information = 0;IoCompleteRequest(pirp, IO_NO_INCREMENT);return status;
}
NTSTATUS MyClearUp(PDEVICE_OBJECT pdevice, PIRP pirp)
{UNREFERENCED_PARAMETER(pdevice);NTSTATUS status = STATUS_SUCCESS;DbgPrint("My Device MyClearUp!");pirp->IoStatus.Status = status;pirp->IoStatus.Information = 0;IoCompleteRequest(pirp, IO_NO_INCREMENT);return status;
}
NTSTATUS MyClose(PDEVICE_OBJECT	pdevice, PIRP pirp)
{UNREFERENCED_PARAMETER(pdevice);NTSTATUS status = STATUS_SUCCESS;DbgPrint("My Device MyClose!");pirp->IoStatus.Status = status;pirp->IoStatus.Information = 0;IoCompleteRequest(pirp, IO_NO_INCREMENT);return status;
}
NTSTATUS MyRead(PDEVICE_OBJECT	pdevice, PIRP pirp)
{UNREFERENCED_PARAMETER(pdevice);NTSTATUS status = STATUS_SUCCESS;DbgPrint("My Device MyRead!");//获取当前IRP堆栈信息PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);//对应用户层的读请求ULONG readsize = pstack->Parameters.Read.Length;DbgPrint("用户请求读大小为%u\n", readsize);//对应用户层所分配的缓冲区的内存位置PCHAR readbuffer = pirp->AssociatedIrp.SystemBuffer;	// readbuffer的赋值实际上是对用户缓冲区的改变RtlCopyMemory(readbuffer,"This Message Come From Kernel.",strlen("This Message Come From Kernel."));pirp->IoStatus.Status = status;//对于Information的赋值是返回给用户程序实际读取的长度。pirp->IoStatus.Information = strlen("This Message Come From Kernel.");//输出下字符串的长度DbgPrint("Really Read Info Len is %lld\n", strlen("This Message Come From Kernel."));IoCompleteRequest(pirp, IO_NO_INCREMENT);return status;
}
NTSTATUS MyWrite(PDEVICE_OBJECT	pdevice, PIRP pirp)
{UNREFERENCED_PARAMETER(pdevice);NTSTATUS status = STATUS_SUCCESS;DbgPrint("My Device MyWrite!");//获取当前IRP堆栈信息PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);//对应用户层的写请求ULONG writesize = pstack->Parameters.Write.Length;DbgPrint("用户请求写大小为%u\n", writesize);//对应用户层所分配的缓冲区的内存位置PCHAR writebuffer = pirp->AssociatedIrp.SystemBuffer;// 写入扩展设备之前先进行清0操作RtlZeroMemory(pdevice->DeviceExtension, 200);// writebuffer的数据写入到设备扩展里边RtlCopyMemory(pdevice->DeviceExtension,writebuffer,writesize);DbgPrint("写缓冲区内存地址:%p,设备扩展内容%s\n", writebuffer,(PCHAR)pdevice->DeviceExtension);pirp->IoStatus.Status = status;pirp->IoStatus.Information = 13;IoCompleteRequest(pirp, IO_NO_INCREMENT);return status;
}
NTSTATUS MyControl(PDEVICE_OBJECT	pdevice, PIRP pirp)
{UNREFERENCED_PARAMETER(pdevice);NTSTATUS status = STATUS_SUCCESS;DbgPrint("My Device MyControl!");PIO_STACK_LOCATION pstack = IoGetCurrentIrpStackLocation(pirp);ULONG	iocode = pstack->Parameters.DeviceIoControl.IoControlCode;	// 获取控制码ULONG inlen = pstack->Parameters.DeviceIoControl.InputBufferLength;ULONG outlen = pstack->Parameters.DeviceIoControl.OutputBufferLength;ULONG ioinfo = 0;DbgPrint("InputBufferLength is %u\n", inlen);DbgPrint("OutputBufferLength is %u\n", outlen);switch (iocode){case IOCTL_MUL:{//做一个减法DWORD indata = *(PDWORD)pirp->AssociatedIrp.SystemBuffer;DbgPrint("--Kernel Indata %d \n", indata);indata = indata * 5;*(PDWORD)pirp->AssociatedIrp.SystemBuffer = indata;ioinfo = 50;//别忘记break!break;}default:status = STATUS_UNSUCCESSFUL;ioinfo = 0;break;}pirp->IoStatus.Status = status;pirp->IoStatus.Information = ioinfo;IoCompleteRequest(pirp, IO_NO_INCREMENT);return status;
}//内核文件拷贝
NTSTATUS KernelCopyFile(PWCHAR dstfile_path, PWCHAR sourcefile_path)
{NTSTATUS status = STATUS_SUCCESS;HANDLE hfile1 = NULL;UNICODE_STRING sourcefilepath = { 0 };OBJECT_ATTRIBUTES obja1 = { 0 };IO_STATUS_BLOCK iostack = { 0 };//初始化RtlInitUnicodeString(&sourcefilepath, sourcefile_path);InitializeObjectAttributes(&obja1, &sourcefilepath, OBJ_CASE_INSENSITIVE |OBJ_KERNEL_HANDLE, NULL, NULL);//打开文件句柄status = ZwOpenFile(&hfile1, GENERIC_ALL, &obja1,&iostack, FILE_SHARE_READ | FILE_SHARE_WRITE,FILE_SYNCHRONOUS_IO_NONALERT);if (!NT_SUCCESS(status)){DbgPrint("ZwOpenFile 文件打开失败 错误码 %x \n",status);return status; }//查询文件大小FILE_STANDARD_INFORMATION fsiFileInfo = { 0 };status = ZwQueryInformationFile(hfile1, &iostack,&fsiFileInfo,sizeof(FILE_STANDARD_INFORMATION),FileStandardInformation);if (!NT_SUCCESS(status)){DbgPrint("ZwQueryDirectoryFile 查询失败 错误码 %x \n", status);ZwClose(hfile1);return status;}//查询成功过后申请缓冲区放置查询内容PVOID filebuffer = NULL;filebuffer = ExAllocatePoolWithTag(NonPagedPool,fsiFileInfo.EndOfFile.QuadPart, '1212');if (!filebuffer){DbgPrint("filebuffer 缓冲区申请失败 错误码 %x \n", status);ZwClose(hfile1);return status;}RtlZeroMemory(filebuffer, fsiFileInfo.EndOfFile.QuadPart);//读文件LARGE_INTEGER readoffset = { 0 };readoffset.QuadPart = 0;	//从0开始读status = ZwReadFile(hfile1, NULL, NULL,NULL,&iostack,filebuffer,(ULONG)fsiFileInfo.EndOfFile.QuadPart, &readoffset,NULL);if (!NT_SUCCESS(status)){DbgPrint("读文件失败 错误码 %x \n", status);ZwClose(hfile1);ExFreePoolWithTag(filebuffer, '1212');return status;}DbgPrint("Ioinfo--- %lld", iostack.Information);ZwClose(hfile1);//创建新文件HANDLE hfile2 = NULL;UNICODE_STRING dstfilepath = { 0 };OBJECT_ATTRIBUTES obja2 = { 0 };IO_STATUS_BLOCK iostack2 = { 0 };RtlInitUnicodeString(&dstfilepath, dstfile_path);InitializeObjectAttributes(&obja2, &dstfilepath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);	//文件操作描述// 参数好多!status = ZwCreateFile(&hfile2, GENERIC_ALL, &obja2, &iostack2,NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE,FILE_SUPERSEDE,FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);if (!NT_SUCCESS(status)){DbgPrint("创建文件失败   错误码 %x \n", status);ExFreePoolWithTag(filebuffer, '1212');return status;}// 写入文件LARGE_INTEGER writeoffset = { 0 };writeoffset.QuadPart = 0;status = ZwWriteFile(hfile2, NULL, NULL, NULL,&iostack2,filebuffer, (ULONG)fsiFileInfo.EndOfFile.QuadPart, &writeoffset,NULL);if (!NT_SUCCESS(status)){DbgPrint("写入失败 错误码 %x \n", status);ExFreePoolWithTag(filebuffer, '1212');ZwClose(hfile2);return status;}DbgPrint("write length = %lld ", iostack2.Information);ExFreePoolWithTag(filebuffer, '1212');ZwClose(hfile2);return status;
}//卸载函数
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{DbgPrint("basedriver 卸载驱动\n");if (DriverObject->DeviceObject){IoDeleteDevice(DriverObject->DeviceObject);}UNICODE_STRING symLink = RTL_CONSTANT_STRING(SYM_NAME);IoDeleteSymbolicLink(&symLink);
}//入口函数
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath
)
{UNREFERENCED_PARAMETER(RegistryPath);//注册卸载函数DriverObject->DriverUnload = DriverUnload;NTSTATUS status = STATUS_SUCCESS;PDEVICE_OBJECT pdevice;		// 用来接收创建的设备对象UNICODE_STRING devicename = { 0 };RtlInitUnicodeString(&devicename, DEVICE_NAME);//创建设备对象status = IoCreateDevice(DriverObject, 200,	// 定义设备扩展的大小,用来存放写入的数据&devicename, FILE_DEVICE_UNKNOWN, 0, TRUE, &pdevice);if (!NT_SUCCESS(status)){KdPrint(("IoCreateDevice 虚拟设备打开失败 状态码 (0x%08X)\n",status));DbgPrint("IoCreateDevice 虚拟设备打开失败 状态码 (0x%08X)\n", status);}if (pdevice->Flags){//不要忘了设备对象的读写方式,否则会蓝屏pdevice->Flags |= DO_BUFFERED_IO;	// 缓冲区方式的读写}////创建成功,创建符号链接//UNICODE_STRING symname = { 0 };RtlInitUnicodeString(&symname, SYM_NAME);status = IoCreateSymbolicLink(&symname, &devicename);	// 符号链接名 设备名if (!NT_SUCCESS(status)){KdPrint(("IoCreateSymbolicLink 符号链接创建失败 状态码 (0x%08X)", status));DbgPrint("IoCreateSymbolicLink 符号链接创建失败 状态码 (0x%08X)", status);}//设置分发例程DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreate;DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MyClearUp;DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyClose;DriverObject->MajorFunction[IRP_MJ_READ] = MyRead;DriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite;DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyControl;KernelCopyFile(L"\\??\\C:\\888.exe", L"\\??\\C:\\567.exe");return 0;
}

效果:

小结

这节课主要是使用内核API了做些处理,对于文件来说还是和应用层类似,注意文件句柄的创建和销毁,还有对文件操作的时的权限设置要符合需求。

另外还可以拓展,通过设定一个临时长度循环读写来拷贝大文件,还有和应用层进行应用交互文件地址等。看完系列课程有时间再做😉😉😉


http://www.ppmy.cn/news/64566.html

相关文章

springboot整合jave2实现音频格式转换

java中处理音频的常用框架 首先了解FFmpeg FFmpeg是一款开源软件&#xff0c;用于生成处理多媒体数据的各类库和程序。FFmpeg可以转码、处理视频和图片&#xff08;调整视频、图片大小&#xff0c;去噪等&#xff09;、打包、传输及播放视频。作为最受欢迎的视频和图像处理软…

vector、deque、list相关知识点

vector erase返回迭代器指向删除元素后的元素insert返回迭代器指插入的元素reserve只给容器底层开指定大小内存空间&#xff0c;并不添加新元素 deque 底层数据结构 动态开辟的二维数组&#xff0c;一维数组从2开始&#xff0c;以2倍方式扩容&#xff0c;每次扩容和&#x…

Windows服务搭建web网站,使用cpolar内网穿透实现公网访问

文章目录 概述1. 搭建一个静态Web站点2. 本地浏览测试站点是否正常3. 本地站点发布公网可访问3.1 安装cpolar内网穿透3.2 创建隧道映射公网地址3.3 获取公网URL地址 4. 公网远程访问内网web站点5. 配置固定二级子域名5.1 保留二级子域名5.2 配置二级子域名 6. 测试访问二级子域…

一篇文章带您区分GNSS欺骗模拟测试的两种方式

写在前面 注意&#xff1a;提供的设备与案例、使用指南等指导性文件是为了在测试环境中对接收机的抗干扰能力进行验证&#xff0c;而非出于欺骗或干扰真实环境中的GNSS信号的目的&#xff01;请确保通过线缆连接应用或暗室应用&#xff0c;若因为违规使用产生的任何法律后果和…

1703_LibreOffice常用功能使用体验

全部学习汇总&#xff1a; GreyZhang/windows_skills: some skills when using windows system. (github.com) 首先需要说明的是我不是一个重度Office用户&#xff0c;甚至算不上一个重度的Office用户。我使用的Office软件最多的功能就是文档编辑&#xff0c;绝大多数时候还是文…

VUE 学习笔记(三) Vue 渲染流程详解

在 Vue 里渲染一块内容&#xff0c;会有以下步骤及流程&#xff1a; 第一步&#xff0c;解析语法&#xff0c;生成AST 第二步&#xff0c;根据AST结果&#xff0c;完成data数据初始化 第三步&#xff0c;根据AST结果和DATA数据绑定情况&#xff0c;生成虚拟DOM 第四步&…

5个PPT素材、模板网站,免费下载,赶紧马住了~

推荐几个可以免费下载PPT素材的网站&#xff0c;建议收藏&#xff01; 1、菜鸟图库 https://www.sucai999.com/search/ppt/0_0_0_1.html?vNTYwNDUx 菜鸟图库网有非常丰富的免费素材&#xff0c;像设计类、办公类、自媒体类等素材都很丰富。PPT模板种类很多&#xff0c;全部都…

操作系统第二章——进程与线程(下)

东风夜放花千树&#xff0c;更吹落&#xff0c;星如雨 文章目录 2.3.1 进程同步&#xff0c;进程互斥知识总览什么是进程同步什么是进程互斥知识回顾 2.3.2 进程互斥的软件实现方法知识总览如果没有进程互斥单标志法双标志先检查法双标志后检查法Peterson算法知识回顾 2.3.3进程…