Windows内核编程之:文件操作

一:文件的创建
/*
*********************************************************************** * 函数名称:ZwCreateFile * 功能描述:文件的创建 * 参数列表: FileHandle:返回打开文件的句柄 DesiredAccess:对打开文件操作的描述,读,写或是其他。一般指定为GENERIC_READ 或 GENERIC_WRITE ObjectAttributes:是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
* 功能描述:初始化OBJECT_ATTRIBUTES结构体
* 参数列表:
        InitializedAttributes:返回的OBJECT_ATTRIBUTES结构体
        ObjectName:对象名称,用UNICODE_STRING描述,这里设置的是文件名
        Attributes:一般设置为OBJ_CASE_INSENSITIVE,对大小写敏感
        RootDirectory:一般设置为NULL
        SecurityDescriptor:一般设置为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"
*/

(1)创建文件

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 = ZwCreateFile(&hfile, //打开文件的句柄
    GENERIC_WRITE, //读,写
    &objectAttributes, //OBJECT_ATTRIBUTES结构的地址 包含文件名
    &iostatus,  //接收ZwCreateFile操作的结果状态
    NULL, //初始分配时的大小
    FILE_ATTRIBUTE_NORMAL, //新创建文件的属性
    FILE_SHARE_READ, //共享方式
    FILE_OPEN_IF, //当指定文件存在或不存在时应如何处理
    FILE_SYNCHRONOUS_IO_NONALERT, //指定控制打开操作和句柄使用的附加标志位
    NULL, //指向可选的扩展属性区
    0); //扩展属性区的长度

if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Create file successfully!\n"));
}
else
{
    KdPrint(("Create file unsuccessfully!\n"));
}

//文件操作
//......

//关闭文件句柄
ZwClose(hfile);

(2)打开文件

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 = ZwCreateFile(&hfile, //打开文件的句柄
    GENERIC_READ, //
    &objectAttributes, //OBJECT_ATTRIBUTES结构的地址 包含文件名
    &iostatus,  //接收ZwCreateFile操作的结果状态
    NULL, //初始分配时的大小
    FILE_ATTRIBUTE_NORMAL, //新创建文件的属性
    FILE_SHARE_READ, //共享方式
    FILE_OPEN, //打开文件,如果不存在,则返回错误
    FILE_SYNCHRONOUS_IO_NONALERT, //指定控制打开操作和句柄使用的附加标志位
    NULL, //指向可选的扩展属性区
    0); //扩展属性区的长度

if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Open file successfully!\n"));
}
else
{
    KdPrint(("Open file unsuccessfully!\n"));
}

//文件操作
//......

//关闭文件句柄
ZwClose(hfile);

二:文件的打开

/************************************************************************
* 函数名称:ZwOpenFile
* 功能描述:打开文件
* 参数列表:
        FileHandle:返回打开的文件句柄
        DesiredAccess:打开的权限,一般设为GENERIC_ALL
        ObjectAttributes:objectAttributes结构
        IoStatusBlock:指向一个结构体的指针。该结构体指明打开文件的状态
        ShareAccess:共享的权限。可以是FILE_SHARE_READ或者FILE_SHARE_WRITE
        OpenOptions:打开选项,一般设为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);

如何使用ZwOpenFile打开文件

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);

三:获取或修改文件属性

/************************************************************************
* 函数名称:ZwSetInformationFile
* 功能描述:设置文件属性
* 参数列表:
        FileHandle:文件句柄
        IoStatusBlock:返回设置的状态
        FileInformation:依据FileInformationClass不同而不同。作为输入信息
        Length:FileInformation数据的长度
        FileInformationClass:描述修改属性的类型
* 返回 值:设置属性是否成功
*************************************************************************/
NTSTATUS ZwSetInformationFile(
            IN HANDLE FileHandle,
            OUT PIO_STATUS_BLOCK IoStatusBlock,
            IN PVOID FileInformation,
            IN ULONG Length,
            IN FILE_INFORMATION_CLASS FileInformationClass);
/************************************************************************
* 函数名称: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);

(1)当FileInformationClass是FileStandardInformation时,
输入和输出的数据时FILE_STANDARD_INFORMATION结构体,描述文件的基本信息

typedef struct FILE_STANDARD_INFORMATION(
        LARGE_INTEGER AllocationSize;//为文件分配的大小[注意:不是文件大小,而是占用蔟所需要的大小]
        LARGE_INTEGER EndOfFile; //距离文件结尾还有多少字节
        ULONG NumberOfLinks; //有多少个链接文件
        BOOLEAN DeletePending; //是否准备删除
        BOOLEAN Directory; //是否为目录
        )FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;

(2)当FileInformationClass是FileBasicInformation时,
输入和输出的数据时FILE_BASIC_INFORMATION结构体,描述文件的基本信息

    typedef struct FILE_BASIC_INFORMATION(
        LARGE_INTEGER CreationTime, //文件创建时间
        LARGE_INTEGER LastAccessTime, //最后访问时间
        LARGE_INTEGER LastWriteTime, //最后写时间
        LARGE_INTEGER ChangeTime, //修改修改时间
        ULONG FileAttributes;    //文件属性 
        )FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
//其中,时间参数是从一个LARGE_INTEGER的整数,该整数代表从1601年经过多少个100ns(纳秒)
//FileAttributes描述文件属性。
    //FILE_ATTRIBUTE_NORMAL描述一般文件
    //FILE_ATTRIBUTE_DIRECTORY描述是目录
    //FILE_ATTRIBUTE_READONLY描述是只读
    //FILE_ATTRIBUTE_SYSTEM代表系统文件

(3)当FileInformationClass是FileNameInformation时,
输入和输出的数据时FILE_NAME_INFORMATION结构体,描述文件的基本信息

    typedef struct _FILE_NAME_INFORMATION(
            ULONG FileNameLength; //文件名长度
            WCHAR Filename; //文件名
        )FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
//注意:文件名的字符串是宽字符集字符串

(4)当FileInformationClass是FilePositionInformation时,
输入和输出的数据时FILE_POSITION_INFORMATION结构体,描述文件的基本信息

    typedef struct FILE_POSITION_INFORMATION(
            LARGE_INTEGER CurrentByteOffset; //代表当前文件指针位置
        )FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;

使用ZwQueryInformationFile函数查询、修改文件属性

OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;
UNICODE_STRING logFileUnicodeString;

//初始化UNICODE_STRING字符串
RtlInitUnicodeString(&logFileUnicodeString,
                     L"\\??\\C:\\1.log");
//或者写成 "\\Device\\HarddisVolume1\\1.log"

//初始化objectAttributes
InitializeObjectAttributes(&objectAttributes,
                           &logFileUnicodeString,
                           OBJ_CASE_INSENSITIVE, //对大小写敏感
                           NULL,
                           NULL);

//创建文件
NTSTATUS  ntStatus = ZwCreateFile(&hfile,
                                  GENERIC_READ,
                                  &objectAttributes,
                                  &iostatus,
                                  NULL,
                                  FILE_ATTRIBUTE_NORMAL,
                                  0,
                                  FILE_OPEN, //打开文件,如果不存在则返回错误
                                  FILE_SYNCHRONOUS_IO_NONALERT,
                                  NULL,
                                  0);
if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Open FILE successFully!\n"));
}
else
{
    KdPrint(("Open FILE unsuccessFully!\n"));
}

FILE_STANDARD_INFORMATION fsi;
//读取文件长度
ntStatus = ZwQueryInformationFile(hfile,
                                  &iostatus,
                                  &fsi,
                                  sizeof(FILE_STANDARD_INFORMATION).
                                  FileStandardInformation);

if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("FILE length:%u\n", fsi.EndOfFile.QuadPart));
}

//修改当前文件指针
FILE_POSITION_INFORMATION fpi;
fpi.CurrentByteOffset.QuadPart = 100i64;
ntStatus = ZwSetInformationFile(hfile,
                                &iostatus,
                                &fpi,
                                sizeof(FILE_POSITION_INFORMATION),
                                FilePositionInformation);
if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("update the FILE pointer successfully.\n"));
}

//关闭文件句柄
ZwClose(hfile);

四:文件的写操作

/************************************************************************
* 函数名称:ZwWriteFile
* 功能描述:文件的写操作
* 参数列表:
        FileHandle:文件打开的句柄
        Event:很少用到,一般设为NULL
        ApcRoutine:很少用到,一般设为NULL
        ApcContext:很少用到,一般设为NULL
        IoStatusBlock:记录些操作的状态。其中,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);

演示如何对文件进行写操作

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 = ZwCreateFile(&hfile,
    GENERIC_WRITE,
    &objectAttributes,
    &iostatus,
    NULL,
    FILE_ATTRIBUTE_NORMAL,
    FILE_SHARE_WRITE,
    FILE_OPEN_IF, //即使存在该文件, 也创建
    FILE_SYNCHRONOUS_IO_NONALERT,
    NULL,
    0);
if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Create file successfully!\n"));
}
else
{
    KdPrint(("Create file unsuccessfully!\n"));
}

#define BUFFER_SIZE 1024

PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, BUFFER_SIZE);
//构造要填充的数据
RtlFillMemory(pBuffer, BUFFER_SIZE, 0xAA);

KdPrint(("Thr program will write %d bytes\n", BUFFER_SIZE));

//写文件
NTSTATUS ntStatus = ZwWriteFile(hfile,
    NULL,
    NULL,
    NULL,
    &iostatus,
    pBuffer,
    BUFFER_SIZE,
    NULL,
    NULL);

if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Write file successfully!\n"));
}
else
{
    KdPrint(("Write file unsuccessfully!\n"));
}

//构造要填充的数据
RtlFillMemory(pBuffer, BUFFER_SIZE, 0xBB);
KdPrint(("The program will append %d bytes\n", BUFFER_SIZE));

//追加数据
LARGE_INTEGER number;
number.QuadPart = 1024i64; //设置文件指针
//对文件进行附加写
NTSTATUS ntStatus = ZwWriteFile(hfile,
    NULL,
    NULL,
    NULL,
    &iostatus,
    pBuffer,
    BUFFER_SIZE,
    &number,
    NULL);

if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Write file successfully!\n"));
}
else
{
    KdPrint(("Write file unsuccessfully!\n"));
}

KdPrint(("The program really appended %d bytes\n", iostatus.Information));

//关闭文件句柄
ZwClose(hfile);

ExFreePool(pBuffer);

五:文件的读操作

/************************************************************************
* 函数名称:ZwReadFile
* 功能描述:文件的读操作
* 参数列表:
        FileHandle:文件打开的句柄
        Event:很少用到,一般设为NULL
        ApcRoutine:很少用到,一般设为NULL
        ApcContext:很少用到,一般设为NULL
        IoStatusBlock:记录些操作的状态。其中,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);

演示如何对文件进行读操作

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 = ZwCreateFile(&hfile,
    GENERIC_WRITE,
    &objectAttributes,
    &iostatus,
    NULL,
    FILE_ATTRIBUTE_NORMAL,
    FILE_SHARE_WRITE,
    FILE_OPEN,
    FILE_SYNCHRONOUS_IO_NONALERT,
    NULL,
    0);
if( !NT_SUCCESS(ntStatus) )
{
    KdPrint(("The file is nor exist!\n"));
    return;
}

FILE_STANDARD_INFORMATION fsi;

//读取文件长度
ntStatus = ZwQueryInformationFile(hfile,
    &iostatus,
    &fsi,
    sizeof(FILE_STANDARD_INFORMATION),
    FileStandardInformation);

KdPrint(("Thr program want to read %d bytes\n", fsi.EndOfFile.QuadPart));

//为读取的文件分配缓冲区
PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, (LONG)fsi.EndOfFile.QuadPart);

//读文件
NTSTATUS ntStatus = ZwReadFile(hfile,
    NULL,
    NULL,
    NULL,
    &iostatus,
    pBuffer,
    BUFFER_SIZE,
    (LONG)fsi.EndOfFile.QuadPart,
    NULL);

if( NT_SUCCESS(ntStatus) )
{
    KdPrint(("Read file successfully!\n"));
}
else
{
    KdPrint(("Read file unsuccessfully!\n"));
}

KdPrint(("The program really read %d bytes\n", iostatus.Information));

//关闭文件句柄
ZwClose(hfile);

//释放缓冲区
ExFreePool(pBuffer);
原文地址:https://www.cnblogs.com/qintangtao/p/3067240.html