今天想看看CreateFile的内部实现,不过网上没有想要的资料,都只是对参数分析了一下。找了找WRK源码,找到CreateFile的源码自己来分析一下。

  

  1 HANDLE WINAPI CreateFileW (    
  2 LPCWSTR        lpFileName,
  3                 DWORD            dwDesiredAccess,
  4                 DWORD            dwShareMode,
  5                 LPSECURITY_ATTRIBUTES    lpSecurityAttributes,
  6                 DWORD            dwCreationDisposition,
  7                 DWORD            dwFlagsAndAttributes,
  8                 HANDLE        hTemplateFile)
  9 {
 10    OBJECT_ATTRIBUTES ObjectAttributes;
 11    IO_STATUS_BLOCK IoStatusBlock;
 12    UNICODE_STRING NtPathU;
 13    HANDLE FileHandle;
 14    NTSTATUS Status;
 15    ULONG FileAttributes, Flags = 0;
 16    PVOID EaBuffer = NULL;
 17    ULONG EaLength = 0;
 18    switch (dwCreationDisposition)
 19    {
 20      case CREATE_NEW://强制创建一个文件(原文件不能存在)
 21     dwCreationDisposition = FILE_CREATE;
 22     break;
 23      case CREATE_ALWAYS://原文件存在就覆盖
 24     dwCreationDisposition = FILE_OVERWRITE_IF;
 25     break;
 26      case OPEN_EXISTING://原文件必须存在
 27     dwCreationDisposition = FILE_OPEN;
 28     break;
 29      case OPEN_ALWAYS://原文件不存在就创建
 30     dwCreationDisposition = FILE_OPEN_IF;
 31     break;
 32      case TRUNCATE_EXISTING://原文件存在就清空内容
 33     dwCreationDisposition = FILE_OVERWRITE;
 34         break;
 35    }
 36    if (0 == _wcsicmp(L"CONOUT$", lpFileName)|| 0 == _wcsicmp(L"CONIN$", lpFileName))
 37    {
 38       return OpenConsoleW(lpFileName,dwDesiredAccess, 
 39                           lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE,
 40                           FILE_SHARE_READ | FILE_SHARE_WRITE);
 41    }
 42    if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
 43       Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
 44    if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
 45       Flags |= FILE_WRITE_THROUGH;
 46    if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
 47       Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
 48    if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
 49       Flags |= FILE_RANDOM_ACCESS;
 50    if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
 51       Flags |= FILE_SEQUENTIAL_ONLY;
 52    if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
 53       Flags |= FILE_DELETE_ON_CLOSE;
 54    if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
 55    if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
 56       Flags |= FILE_OPEN_REPARSE_POINT;
 57    if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
 58       Flags |= FILE_OPEN_NO_RECALL;
 59    FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
 60    dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
 61    if (!RtlDosPathNameToNtPathName_U (lpFileName,&NtPathU,NULL,NULL))
 62    {
 63      SetLastError(ERROR_PATH_NOT_FOUND);
 64      return INVALID_HANDLE_VALUE;
 65    }
 66    if (hTemplateFile != NULL) 
 67    {
 68       FILE_EA_INFORMATION EaInformation;
 69 
 70       for (;;)
 71       {
 72          Status = NtQueryInformationFile(hTemplateFile,&IoStatusBlock,&EaInformation,
 73                                          sizeof(FILE_EA_INFORMATION),FileEaInformation);
 74          if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
 75          {
 76             EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),0,EaInformation.EaSize);
 77             Status = NtQueryEaFile(hTemplateFile,&IoStatusBlock,EaBuffer,
 78                                    EaInformation.EaSize,FALSE,NULL,0,NULL,TRUE);
 79             if (NT_SUCCESS(Status))
 80             {
 81                EaLength = EaInformation.EaSize;
 82                break;
 83             }
 84             Else
 85          }
 86          else
 87             break;
 88       }
 89    }
 90 
 91    InitializeObjectAttributes(&ObjectAttributes,&NtPathU,0,NULL,NULL);
 92    if (lpSecurityAttributes)
 93    {
 94       if(lpSecurityAttributes->bInheritHandle)
 95          ObjectAttributes.Attributes |= OBJ_INHERIT;
 96       ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
 97    }
 98 
 99    if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
100     ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
101 
102    Status = NtCreateFile (&FileHandle,
103 dwDesiredAccess,
104               &ObjectAttributes,
105               &IoStatusBlock,NULL,
106               FileAttributes,
107               dwShareMode,
108               dwCreationDisposition,
109               Flags,
110               EaBuffer,
111               EaLength);
112    if (!NT_SUCCESS(Status))
113    {
114       if (Status == STATUS_OBJECT_NAME_COLLISION && dwCreationDisposition == FILE_CREATE)
115          SetLastError( ERROR_FILE_EXISTS );
116       else
117          SetLastErrorByStatus (Status);
118       return INVALID_HANDLE_VALUE;
119    }
120   if (dwCreationDisposition == FILE_OPEN_IF)
121     SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
122   else if (dwCreationDisposition == FILE_OVERWRITE_IF)
123     SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
124   return FileHandle;//返回的文件句柄就是文件对象的句柄
125 }

都知道函数CreateFile返回值是文件句柄,我们发现返回的文件句柄其实是函数内部声明的一个传入系统服务NTCreateFile的句柄。接下来,我们一步步跟进, NTCreateFile只是调用了IO管理器的IoCreateFile函数。

IoCreateFile函数的实现也比较简单,就不贴代码了。首先将参数复制到内核空间,构造打开请求包OpenPacket(这个结构体写驱动好像不是很常用?),接下来调用IopParseDevice解析文件路径,这个函数比较关键,会在这里创建文件对象和IRP请求包。最后就是打开文件对象,再返回Status就Ok啦。

IopParseDevice函数我直接定位到自己最感兴趣的地方:

InitializeObjectAttributes(&ObjectAttributes,NULL,Attributes,NULL,NULL);
        Status = ObCreateObject(KernelMode,IoFileObjectType,
                                &ObjectAttributes,AccessMode,NULL,
                                sizeof(FILE_OBJECT)
                                0,0, (PVOID*)&FileObject);
        RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
        if (OpenPacket->CreateOptions &
            (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
        {
            FileObject->Flags |= FO_SYNCHRONOUS_IO;
            if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
                FileObject->Flags |= FO_ALERTABLE_IO;
        }
        if (FileObject->Flags & FO_SYNCHRONOUS_IO)
            KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
        if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
            FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
        if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
            FileObject->Flags |= FO_WRITE_THROUGH;
        if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
            FileObject->Flags |= FO_SEQUENTIAL_ONLY;
        if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
            FileObject->Flags |= FO_RANDOM_ACCESS;

在判断完操作类型之后终于开始ObCreateObject创建对象(注意,仅仅是查询、删除命令的话不需要创建对象,使用内部预先的公共的文件对象就ok),接下来就是发送IRP,等待完成。

  简单的分析一下,很多细节没有仔细的看,了解一下底层实现。    说真的,这个函数名字取得真心不好,这函数能打开创建的那么多,只叫CreateFile。。。

 

posted on 2017-02-28 00:37  Beawesome  阅读(2347)  评论(2编辑  收藏  举报