今天想看看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。。。