文件操作之前,必须先要打开文件,一般的想法是,把文件的路径传进去,但是,内核中并不直接接受一个字符串,必须先要填写一个OBJECT_ATTRIBUTES结构,这个结构里面的成员我们不知道是什么,因为微软没有公开它,使用这个结构的时候我们要调用InitializeObjectAttributes来初始化这个结构。

VOID InitializeObjectAttributes(

  [out] POBJECT_ATTRIBUTES InitializedAttributes,

  [in] PUNICODE_STRING ObjectName,

  [in] ULONG Attributes,

  [in] HANDLE RootDirectory,

  [in, optional] PSECURITY_DESCRIPTOR SecurityDescriptor

);

需要注意的是,第一个参数InitializedAtteributes是要初始化的对象,第二个参数objectName则是对象名字的字符串,这里也就是文件的路径,在内核中无论是打开文件,还是打开注册表,都要先初始化一个OBJECT_ATTRIBUTES

第三个参数attributes只要填写OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE即可,OBJ_KERNEL_HANDLE表明打开的是一个内核句柄

最后两个参数传NULL即可


初始化一个OBJECT_ATTRIBUTES后,调用ZwCreateFile即可打开文件,函数原型如下

NTSTATUS ZwCreateFile(  
  _Out_    PHANDLE            FileHandle,  
  _In_     ACCESS_MASK        DesiredAccess,  
  _In_     POBJECT_ATTRIBUTES ObjectAttributes,  
  _Out_    PIO_STATUS_BLOCK   IoStatusBlock,  
  _In_opt_ PLARGE_INTEGER     AllocationSize,  
  _In_     ULONG              FileAttributes,  
  _In_     ULONG              ShareAccess,  
  _In_     ULONG              CreateDisposition,  
  _In_     ULONG              CreateOptions,  
  _In_opt_ PVOID              EaBuffer,  
  _In_     ULONG              EaLength  
);  

这个函数参数异常的复杂,建议查MSDN了解详情

第一个参数是一个返回出来的文件句柄,

第二个参数表示申请的文件权限GENERIC_ALL代表所有权限,一般使用GENERIC_READ GENERIC_WRITE也可以几个值用或运算组合起来

第三个参数是OBJECT_ATTRIBUTES的对象,也就是我们最开始初始化那个,它里面包含了文件名

第四个参数是一个IO_STATUS_BLOCK结构的对象,在调用这个函数的时候,返回的结果会在这个对象的Status成员里

第五个参数是一个指向64位证书的指针,一般传NULL即可

第六个参数是文件的属性,一般传递FILE_ATTRIBUTE_NORMAL

第七个参数是共享的数学,比如,你打开文件以后运行别人共享打开(FILE_SHARE_READ)、共享删除(FILE_SHARE_DELETE)、共享写入(FILE_SHARE_WRITE)等,如果你设置的是FILE_SHARE_WRITE,那么你操作文件的时候 别人也可以写

第八个参数表示你打开的意图,可以是新建文件(FILE_CREATE)、打开文件(FILE_OPEN),等等 具体参考MSDN


文件打开一个,我们就有一个可用的HANDLE了,就可以对文件进行读写操作,文件读取用ZwReadFile,写用 ZwWriteFile 两个函数参数是一样的

NTSTATUS ZwReadFile(  
  _In_     HANDLE           FileHandle,  
  _In_opt_ HANDLE           Event,  
  _In_opt_ PIO_APC_ROUTINE  ApcRoutine,  
  _In_opt_ PVOID            ApcContext,  
  _Out_    PIO_STATUS_BLOCK IoStatusBlock,  
  _Out_    PVOID            Buffer,  
  _In_     ULONG            Length,  
  _In_opt_ PLARGE_INTEGER   ByteOffset,  
  _In_opt_ PULONG           Key  
);  

第一个参数是ZwCreateFile的句柄

第二个,第三个传null就行了

第四个参数跟上面的一样 是IO_STATUS_BLOCK的对象

第五个是缓冲区,如果是读文件的话,就是读到这个缓冲区,写文件的话,就是从这个缓冲区取内容去写

第六个参数是缓冲区的长度

第七个参数是要读取文件的偏移量,也就是要从文件什么位置读,一般不要设置NULL

第八个参数设置为NULL即可

当操作完了这个文件,记得用ZwClose关闭,参数是文件的句柄

我们看看具体的代码

HANDLE hFile = NULL;
    NTSTATUS status;
    ULONG uOffset;
    PVOID pBuff;
    CHAR *pBuff2 = "dbgpro.com";
    OBJECT_ATTRIBUTES object_attributes;
    UNICODE_STRING strFileName = RTL_CONSTANT_STRING(L"\\??\\c:\\a.txt");
    IO_STATUS_BLOCK ioStatus;
    pBuff = ExAllocatePool(NonPagedPool,10);
    InitializeObjectAttributes(&object_attributes,&strFileName,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
    status = ZwCreateFile(&hFile,GENERIC_READ|GENERIC_WRITE,&object_attributes,
    &ioStatus,NULL,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_READ,
    FILE_OPEN_IF,FILE_NON_DIRECTORY_FILE|FILE_RANDOM_ACCESS|FILE_SYNCHRONOUS_IO_NONALERT,
    NULL,NULL);
    
    ZwWriteFile(hFile,NULL,NULL,NULL,&ioStatus,pBuff2,8,NULL,NULL);
    if (status==STATUS_SUCCESS)  
    { 
        status=ZwReadFile(  
            hFile,  
            NULL,  
            NULL,  
            NULL,  
            &ioStatus,  
            pBuff,  
            10,  
            NULL,  
            NULL);  
        DbgPrint("%s\r\n",pBuff);  
    }

    ZwClose(hFile);

打赏