在本节,我们将学习在内核模式下操作文件,包括:创建,打开,读取,修改,文件属性读取与修改。
相关的API有:ZwCreateFile, ZwOpenFile, ZwReadFile, ZwWriteFile, ZwQueryInformationFile,ZwSetInformationFile, 它们对应的应用程的API就是去掉前面的Zw.
内核模式操作文件都需要先初始化一个OBJECT_ATTRIBUTES结构如OBJECT_ATTRIBUTES objectAttributes;具体将在下面的源码中看到。
创建文件方法:
VOID CreateFileTest() { NTSTATUS ntStatus; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING SymbolFileName; KdPrint(("\n-----------------创建文件测试 --------------------!\n")); //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&SymbolFileName,L"\\Device\\HarddiskVolume1\\CreateFileTest.txt"); //RtlInitUnicodeString( &SymbolFileName, L"\\??\\C:\\\CreateFileTest.txt");//可用此行替换上一行 //初始化objectAttributes InitializeObjectAttributes( &objectAttributes, //指定一个需要OBJECT_ATTRIBUTES结构地址 &SymbolFileName,//是一个UNICODE_STRING字串地址,指定需要操作对象名(在这里可以是符号链接名,或者设备名) OBJ_CASE_INSENSITIVE, //指定此值表示 不区分大小写。 NULL, NULL ); //创建文件 ntStatus = ZwCreateFile( &hfile, //PHANDLE类型指针 用于返回打开文件的句柄 GENERIC_WRITE, //ACCESS_MASK类型 此值用于描述打开文件操作(读,写,或者其它) &objectAttributes, //此值是OBJECT_ATTRIBUTES结构的地址,该结构包含要打开的文件名 需要用InitializeObjectAttributes进行初始化 &iostatus, //指向一个IO_STATUS_BLOCK结构,返回值之一 用于存放ZwCreateFile操作的结果状态 NULL, //PLARGE_INTEGER 类型(64位整数指针)该数指定文件初始分配时的大小。该参数如果为NULL,那么文件长度将从0开始,随着写入而增长 FILE_ATTRIBUTE_NORMAL, //此参数在驱动下指定为0或者FILE_ATTRIBUTE_NORMAL,如果文件不是被创建和覆盖写入 则此参数将被忽略 FILE_SHARE_READ, //指定共享模式 有共享读FILE_SHARE_READ,写FILE_SHARE_WRITE,删除FILE_SHARE_DELETE这几中模式 FILE_OPEN_IF, //此值表示 文件存在则打开 不存在则创建一个新的文件 FILE_SYNCHRONOUS_IO_NONALERT, //指定文件创建或者打开的附加标志 FILE_SYNCHRONOUS_IO_NONALERT表示在文件中的所有操作均同步,并没有警报 NULL, //对于设备和中间驱动程序,此参数必须是NULL 0 ); //对于设备和中间驱动程序,此参数必须是0 if ( NT_SUCCESS(ntStatus)) { KdPrint(("创建文件成功!\n")); }else { KdPrint(("创建文件失败!\n")); } //文件操作 //....... //关闭文件句柄 ZwClose(hfile); }
打开文件方法有几种:可以用ZwCreateFile,可以用ZwOpenFile,在这儿我们用ZwCreateFile, 在完整源码中两种方法都有。
VOID OpenFileTest() { NTSTATUS ntStatus; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING SymbolFileName; KdPrint(("\n-----------------打开文件测试OpenFileTest --------------------!\n")); //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&SymbolFileName,L"\\Device\\HarddiskVolume1\\CreateFileTest.txt"); //RtlInitUnicodeString( &SymbolFileName, L"\\??\\C:\\\CreateFileTest.txt");//可用此行替换上一行 //初始化objectAttributes InitializeObjectAttributes( &objectAttributes, //指定一个需要OBJECT_ATTRIBUTES结构地址 &SymbolFileName,//是一个UNICODE_STRING字串地址,指定需要操作对象名(在这里可以是符号链接名,或者设备名) OBJ_CASE_INSENSITIVE, //指定此值表示 不区分大小写。 NULL, NULL ); //创建文件 ntStatus = ZwCreateFile( &hfile, //PHANDLE类型指针 用于返回打开文件的句柄 GENERIC_WRITE, //ACCESS_MASK类型 此值用于描述打开文件操作(读,写,或者其它) &objectAttributes, //此值是OBJECT_ATTRIBUTES结构的地址,该结构包含要打开的文件名 需要用InitializeObjectAttributes进行初始化 &iostatus, //指向一个IO_STATUS_BLOCK结构,返回值之一 用于存放ZwCreateFile操作的结果状态 NULL, //PLARGE_INTEGER 类型(64位整数指针)该数指定文件初始分配时的大小。该参数如果为NULL,那么文件长度将从0开始,随着写入而增长 FILE_ATTRIBUTE_NORMAL, //此参数在驱动下指定为0或者FILE_ATTRIBUTE_NORMAL,如果文件不是被创建和覆盖写入 则此参数将被忽略 FILE_SHARE_READ, //指定共享模式 有共享读FILE_SHARE_READ,写FILE_SHARE_WRITE,删除FILE_SHARE_DELETE这几中模式 FILE_OPEN, //此值表示 文件存在则打开 不存在则创建一个新的文件 FILE_SYNCHRONOUS_IO_NONALERT, //指定文件创建或者打开的附加标志 FILE_SYNCHRONOUS_IO_NONALERT表示在文件中的所有操作均同步,并没有警报 NULL, //对于设备和中间驱动程序,此参数必须是NULL 0 ); //对于设备和中间驱动程序,此参数必须是0 if ( NT_SUCCESS(ntStatus)) { KdPrint(("打开文件成功!hfile=%x\n",hfile)); }else { KdPrint(("打开文件失败!hfile=%x\n",hfile)); } //文件操作 //....... //关闭文件句柄 ZwClose(hfile); KdPrint(("\n-----------------打开文件测试OpenFileTest end --------------------!\n")); }
读取文件:
VOID ReadFileTest() { KdPrint(("\n---------------------ZwReadFile写文件测试--------------------\n")); OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING SymbolFileName; //初始化UNICODE_STRING字符串 RtlInitUnicodeString( &SymbolFileName, L"\\Device\\HarddiskVolume1\\CreateFileTest.txt"); //RtlInitUnicodeString( &SymbolFileName, L"\\??\\C:\\1.txt"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &SymbolFileName, OBJ_CASE_INSENSITIVE,//对大小写敏感 NULL, NULL ); //创建文件 NTSTATUS ntStatus = ZwCreateFile( &hfile, GENERIC_READ, &objectAttributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, //常规属性 FILE_SHARE_READ,//共享读 FILE_OPEN,//有文件存在则打开,不存在则报错 FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS(ntStatus)) { KdPrint(("文件不存在!\n")); return; } FILE_STANDARD_INFORMATION fsi; //读取文件长度 ntStatus = ZwQueryInformationFile(hfile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); KdPrint(("共读取 %d 字节\n",fsi.EndOfFile.QuadPart)); //为读取的文件分配缓冲区 PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, (LONG)fsi.EndOfFile.QuadPart); //读取文件 ZwReadFile(hfile,NULL, NULL,NULL, &iostatus, pBuffer, (LONG)fsi.EndOfFile.QuadPart, NULL,NULL); KdPrint(("实际读取 %d 字节\n",iostatus.Information)); //显示实际读取内容 KdPrint(("\n 成功读取内容为:%s \n",pBuffer)); //关闭文件句柄 ZwClose(hfile); //释放缓冲区 ExFreePool(pBuffer); }
修改文件:
VOID WriteFileTest() { KdPrint(("\n---------------------ZwWriteFile写文件测试--------------------\n")); OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING SymbolFileName; //初始化UNICODE_STRING字符串 RtlInitUnicodeString( &SymbolFileName, L"\\Device\\HarddiskVolume1\\CreateFileTest.txt"); //RtlInitUnicodeString( &SymbolFileName, L"\\??\\C:\\1.txt"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &SymbolFileName, OBJ_CASE_INSENSITIVE,//对大小写敏感 NULL, NULL ); //创建文件 NTSTATUS ntStatus = ZwCreateFile( &hfile, GENERIC_WRITE, &objectAttributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN_IF,//即使存在该文件,也创建 FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); #define BUFFER_SIZE 30 PCHAR pBuffer = (PCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE); //构造要填充的数据 RtlFillMemory(pBuffer,BUFFER_SIZE,'s');//www.yjxsoft.comssssssssssssxxxxxx //strcpy(pBuffer,"www.yjxsoft.com"); RtlCopyMemory(pBuffer,"www.yjxsoft.com",15); KdPrint(("即将写入 %d 字节\n",BUFFER_SIZE)); //写文件ZwQueryInfomationfile LARGE_INTEGER sl; sl.QuadPart=0i64; ZwWriteFile(hfile,NULL,NULL,NULL,&iostatus,pBuffer,30,&sl,NULL); KdPrint(("成功写入 %d 字节\n",iostatus.Information)); //构造要填充的数据 RtlFillMemory(pBuffer,BUFFER_SIZE,'x'); KdPrint(("成功写入 %d 字节\n",BUFFER_SIZE)); //追加数据 LARGE_INTEGER number; number.QuadPart =30i64;//设置文件指针 //对文件进行附加写 ZwWriteFile(hfile,NULL,NULL,NULL,&iostatus,pBuffer,BUFFER_SIZE,&number,NULL); KdPrint(("追加写入 %d 字节\n",iostatus.Information)); //关闭文件句柄 ZwClose(hfile); ExFreePool(pBuffer); }
文件属性读取与修改:
VOID FileAttributeTest() { KdPrint(("\n-----------------ZwQueryInformationFile ZwSetInformationFile 测试 ---------------------!\n")); OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING SymbolFileName; //初始化UNICODE_STRING字符串 //RtlInitUnicodeString( &SymbolFileName, L"\\Device\\HarddiskVolume1\\1.txt"); RtlInitUnicodeString( &SymbolFileName, L"\\??\\C:\\CreateFileTest.txt"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &SymbolFileName, OBJ_CASE_INSENSITIVE,//对大小写敏感 NULL, NULL ); //创建文件 NTSTATUS ntStatus = ZwCreateFile( &hfile, GENERIC_ALL, &objectAttributes, &iostatus, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN_IF,//对文件打开,如果不存在则返回错误 FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("打开文件成功.\n")); } FILE_STANDARD_INFORMATION fsi; //读取文件长度 ntStatus = ZwQueryInformationFile(hfile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (NT_SUCCESS(ntStatus)) { KdPrint(("文件长度 :%u\n",fsi.EndOfFile.QuadPart)); } //读出文件属性 FILE_BASIC_INFORMATION fbi; ZwQueryInformationFile(hfile, &iostatus, &fbi, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); //修改文件属性 fbi.FileAttributes=FILE_ATTRIBUTE_READONLY;//|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_NORMAL; ntStatus = ZwSetInformationFile(hfile, &iostatus, &fbi, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (NT_SUCCESS(ntStatus)) { KdPrint(("设置文件 属性成功.\n")); } else { KdPrint(("设置文件 属性失败ntStatus=%x\n",ntStatus)); } //关闭文件句柄 ZwClose(hfile); }
具体请参看完整源码。