Есть минифильтр, нужно при создании файла получить его short name(8.3). FltGetFileNameInformation/FltGetFileNameInformationUnsafe c FLT_FILE_NAME_SHORT не подходят, создавать short name в post callback'е тоже нельзя(туда приходит уже новое имя и путь). Есть ли способы получить short name без написания данной ф-ции самому? Напомню что файла не существует и из-за этого отпадают ZwQueryDirectoryFile и иже с ними, генерацию коротких имен отключать тоже нелья. Буду рад любым идеям.
Вобщем средствами минифильтра мою задачу решить нельзя, пришлось писать велосипед (через RtlGenerate8dot3Name).
На днях заморочился с обратной задачей - узнать NT-полный-путь к файлу, который был открыт через 8.3-имя, например, через CreateFile("C:\\Docume~1\\user\\Applic~1\\Longlo~1\\text.txt"); Вообщем, как выяснилось, в системе вообще не хранится раскрытый реальный путь, а везде хранится только 8.3, никакие запрашивания пути ни возвращали раскрытый. Видел вроде не один такой тред на васме, поэтому вотчо я написал: Код (Text): // // ucsrchr() - wcsrchr/strrchr for UNICODE_STRING // // Buffer of DestString will not allocated; SourceString buffer used; // static BOOLEAN ucsrchr(IN PCUNICODE_STRING SourceString,OUT PUNICODE_STRING DestString,IN WCHAR SearchFor) { // // skip zero-length and misalignment strings // if (!SourceString->Length || (SourceString->Length % sizeof(WCHAR)) != 0) return FALSE; USHORT i; for (i=SourceString->Length/sizeof(WCHAR)-1; ; i--) { if (SourceString->Buffer[i] == SearchFor) { // // character found; copy rests string to user buffer and return // DestString->Length = SourceString->Length - i*sizeof(WCHAR); DestString->MaximumLength = SourceString->MaximumLength - i*sizeof(WCHAR); DestString->Buffer = &SourceString->Buffer[i]; return TRUE; } // // no chars left ? // if (!i) break; } // // character was not found // return FALSE; } // // ShiftUnicodeString() // static BOOLEAN ShiftUnicodeString(IN OUT PUNICODE_STRING StringToShift,IN USHORT CharsCount) { // // skip zero-length and misalignment strings // if (!StringToShift->Length || StringToShift->Length % sizeof(WCHAR) != 0) return FALSE; USHORT OriginalCharsCount = StringToShift->Length / sizeof(WCHAR); // // overflow check // if (CharsCount > OriginalCharsCount) return FALSE; // // shift Buffer and decrease length // StringToShift->Buffer = &StringToShift->Buffer[CharsCount]; StringToShift->Length -= CharsCount * sizeof(WCHAR); return TRUE; } // // DividePath() // // (!) if functions succeeds (TRUE returned), // (!) DirectoryPath string must be destroyed with RtlFreeUnicodeString INSTEAD of FileName string // static NTSTATUS DividePath(IN PCUNICODE_STRING FullPath,OUT PUNICODE_STRING DirectoryPath,OUT PUNICODE_STRING FileName) { // // find last slash ('\') // if (ucsrchr(FullPath,FileName,L'\\')) { // // skip slash // if (!ShiftUnicodeString(FileName,1)) return STATUS_OBJECT_PATH_SYNTAX_BAD; if (!FileName->Length) return STATUS_NO_MORE_ENTRIES; // done // // calculate directory path length // DirectoryPath->Length = FullPath->Length - FileName->Length - sizeof(WCHAR); // // calculate ending slashes if present // while (FullPath->Buffer[DirectoryPath->Length/sizeof(WCHAR)] == '\\' && DirectoryPath->Length > 0) DirectoryPath->Length -= sizeof(WCHAR); DirectoryPath->Length += sizeof(WCHAR); // // allocate and copy directory path skipping ending slashes // DirectoryPath->MaximumLength = DirectoryPath->Length + sizeof(WCHAR); if (DirectoryPath->Buffer = (PWSTR)ExAllocatePool(PagedPool,DirectoryPath->MaximumLength)) { RtlCopyMemory(DirectoryPath->Buffer,FullPath->Buffer,DirectoryPath->Length); return STATUS_SUCCESS; } else { KdPrint((__FUNCTION__"(): Unable to allocate %d (%08x) bytes for DirectoryPath.Buffer\n",DirectoryPath->MaximumLength,DirectoryPath->MaximumLength)); return STATUS_NO_MEMORY; } } // // slash was not found // return STATUS_OBJECT_PATH_SYNTAX_BAD; } // // DupUnicodeString() // static BOOLEAN DupUnicodeString(OUT PUNICODE_STRING DestinationString, IN PCUNICODE_STRING SourceString) { DestinationString->Buffer = (PWSTR)ExAllocatePool(PagedPool,SourceString->Length); if (!DestinationString->Buffer) return FALSE; DestinationString->Length = SourceString->Length; DestinationString->MaximumLength = SourceString->MaximumLength; RtlCopyMemory(DestinationString->Buffer,SourceString->Buffer,SourceString->Length); return TRUE; } // helpers for ZwQueryDirectoryFile call stack #define RETURN_SINGLE_ENTRY TRUE #define RESTART_SCAN TRUE #if (DBG == 1) static VOID DumpFileBotDirInfo(IN const PFILE_BOTH_DIR_INFORMATION Info) { WCHAR wszShortName[12+1], *pwszFileName; RtlZeroMemory(wszShortName,sizeof(wszShortName)); RtlCopyMemory(wszShortName,Info->ShortName,Info->ShortNameLength); pwszFileName = (WCHAR*)ExAllocatePool(PagedPool,Info->FileNameLength+sizeof(WCHAR)); if (!pwszFileName) { KdPrint((__FUNCTION__"(): ExAllocatePool() failed\n")); return; } RtlCopyMemory(pwszFileName,Info->FileName,Info->FileNameLength); pwszFileName[Info->FileNameLength/sizeof(WCHAR)] = L'\0'; KdPrint(("-------[" __FUNCTION__ "]-------\n")); KdPrint(("Info at %p:\n",Info)); KdPrint((".NextEntryOffset = %08x\n",Info->NextEntryOffset)); KdPrint((".FileIndex = %08x (%d)\n",Info->FileIndex,Info->FileIndex)); KdPrint((".CreationTime = %I64u\n",Info->CreationTime)); KdPrint((".LastAccessTime = %I64u\n",Info->LastAccessTime)); KdPrint((".LastWriteTime = %I64u\n",Info->LastWriteTime)); KdPrint((".ChangeTime = %I64u\n",Info->ChangeTime)); KdPrint((".EndOfFile = %I64u\n",Info->EndOfFile)); KdPrint((".AllocationSize = %I64u\n",Info->AllocationSize)); KdPrint((".FileAttributes = %08x\n",Info->FileAttributes)); KdPrint((".EaSize = %08x\n",Info->EaSize)); KdPrint((".FileNameLength = %08x (%d)\n",Info->FileNameLength,Info->FileNameLength)); KdPrint((".ShortNameLength = %08x (%d)\n",Info->ShortNameLength,Info->ShortNameLength)); KdPrint((".ShortName(%d) = '%S'\n",Info->ShortNameLength,wszShortName)); KdPrint((".FileName(%d) = '%S'\n",Info->FileNameLength,pwszFileName)); KdPrint(("--------------------------------\n\n")); ExFreePool(pwszFileName); } #endif // DBG == 1 #define UCS_LAST_CHAR(us) (us->Buffer[us->Length/sizeof(WCHAR)]) // // QueryNtPath() // static NTSTATUS QueryNtPath(IN PCUNICODE_STRING RootDir,IN PCUNICODE_STRING FileName,OUT PUNICODE_STRING NtFileName) { NTSTATUS st; OBJECT_ATTRIBUTES Oa; IO_STATUS_BLOCK IoSb; HANDLE RootDirHandle; UNICODE_STRING usRootDirNew; // // add slash if needed // usRootDirNew.MaximumLength = RootDir->MaximumLength+sizeof(WCHAR); usRootDirNew.Length = RootDir->Length; usRootDirNew.Buffer = (PWSTR)ExAllocatePool(PagedPool,usRootDirNew.MaximumLength); RtlCopyMemory(usRootDirNew.Buffer,RootDir->Buffer,usRootDirNew.Length); if (UCS_LAST_CHAR(RootDir) != '\\') { RtlAppendUnicodeToString(&usRootDirNew,L"\\"); } // // open root directory to find specified file and get it's long NT name // InitializeObjectAttributes(&Oa,&usRootDirNew,OBJ_CASE_INSENSITIVE,NULL,NULL); st = ZwCreateFile( &RootDirHandle, FILE_LIST_DIRECTORY|SYNCHRONIZE, &Oa, &IoSb, NULL, FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, NULL, NULL ); RtlFreeUnicodeString(&usRootDirNew); if (NT_SUCCESS(st)) { PFILE_BOTH_DIR_INFORMATION DirInfo; ULONG DirInfoLength; // // allocate directory info buffer for ZwQueryDirectoryFile() // DirInfoLength = 1024; if (DirInfo = (PFILE_BOTH_DIR_INFORMATION)ExAllocatePool(PagedPool,DirInfoLength)) { // // okay, directory opened, try to get information about specified file // st = ZwQueryDirectoryFile( RootDirHandle, // FileHandle NULL, // Event NULL, // ApcRoutine NULL, // ApcContext &IoSb, // IoStatusBlock DirInfo, // FileInformation DirInfoLength, // Length FileBothDirectoryInformation, // FileInformationClass RETURN_SINGLE_ENTRY, // ReturnSingleEntry (PUNICODE_STRING)FileName, // FileName RESTART_SCAN // RestartScan ); if (NT_SUCCESS(st)) { #if (DBG == 1) //DumpFileBotDirInfo(DirInfo); #endif // DBG == 1 // // got it, copy to user buffer // NtFileName->Length = (USHORT)DirInfo->FileNameLength; NtFileName->MaximumLength = NtFileName->Length + sizeof(WCHAR); if (NtFileName->Buffer = (PWSTR)ExAllocatePool(PagedPool,NtFileName->MaximumLength)) { RtlCopyMemory(NtFileName->Buffer,DirInfo->FileName,NtFileName->Length); st = STATUS_SUCCESS; } else { KdPrint((__FUNCTION__"(): Unable to allocate %d (%08x) bytes for NtFileName->Buffer\n",NtFileName->MaximumLength,NtFileName->MaximumLength)); } } else { KdPrint((__FUNCTION__"(): ZwQueryDirectoryFile(RootDirHandle=%08x,'%wZ') failed with status %08x\n",RootDirHandle,FileName,st)); } ExFreePool(DirInfo); } else { KdPrint((__FUNCTION__"(): Unable to allocate %d (%08x) bytes for DirInfo\n",DirInfoLength,DirInfoLength)); st = STATUS_NO_MEMORY; } ZwClose(RootDirHandle); } else { //KdPrint((__FUNCTION__"(): ZwCreateFile(&RootDirHandle=%p,'%wZ') failed with status %08x\n",&RootDirHandle,Oa.ObjectName,st)); // // unable to open dir; return 'as is' // st = DupUnicodeString(NtFileName,FileName) ? STATUS_SUCCESS : STATUS_NO_MEMORY; } return st; } // // wcsrcat() // static BOOLEAN wcsrcat(OUT PWCHAR Buffer,IN ULONG BufferCount,IN PCUNICODE_STRING StringToAppend,IN PULONG NewSourceLength OPTIONAL) { if (StringToAppend->Length < sizeof(WCHAR)) return TRUE; // nothing to append ULONG CurrentLength = wcslen(Buffer); if (StringToAppend->Length + CurrentLength*sizeof(WCHAR) >= BufferCount*sizeof(WCHAR)) return FALSE; // no free space in buffer register ULONG i, c; for (i=StringToAppend->Length/sizeof(WCHAR)-1, c = CurrentLength; ; i--) { Buffer[c++] = StringToAppend->Buffer[i]; if (!i) break; } Buffer[c] = L'\0'; if (NewSourceLength) *NewSourceLength = c; return TRUE; } // // SwapWchars() // static VOID SwapWchars(PWCHAR Ptr1,PWCHAR Ptr2) { WCHAR t = *Ptr1; *Ptr1 = *Ptr2; *Ptr2 = t; } // // wcs_reverse() // static VOID wcs_reverse(IN OUT PWCHAR Buffer) { ULONG Len = wcslen(Buffer); if (!Len) return; for (ULONG i=0; i<Len/2; i++) { // // swap chars // SwapWchars(&Buffer[i],&Buffer[Len-i-1]); } } // // TranslateDosToNtPathName() // static NTSTATUS NTAPI TranslateDosToNtPathName(IN PCUNICODE_STRING DosPathName,OUT PUNICODE_STRING NtPathName) { NTSTATUS st; UNICODE_STRING usCurrentPath, usTargetRoot, usTargetFileName, usNtFileName; PWCHAR PathBuffer; ULONG PathBufferLength = MAX_PATH*sizeof(WCHAR); // // path buffer used as MAX_PATH-sized buffer that contains wchar-s of // output NT path in reversed order // this buffer will be reversed before return if routine succeeded // PathBuffer = (PWCHAR)ExAllocatePool(PagedPool,PathBufferLength); if (!PathBuffer) { KdPrint((__FUNCTION__"(): Unable to allocate %d (%08x) bytes for PathBuffer\n",PathBufferLength,PathBufferLength)); return STATUS_NO_MEMORY; } // // begin from path specified and walk to root directory // usCurrentPath = *DosPathName; usTargetRoot.Buffer = NULL; // // process all '\...\' parts of specified DOS (can be 8.3 with '~', etc.) path name // for (;;) { // // split original full path to directory path and file name // st = DividePath(&usCurrentPath,&usTargetRoot,&usTargetFileName); if (!NT_SUCCESS(st)) { if (st == STATUS_NO_MEMORY) { // // fatal error, return // KdPrint((__FUNCTION__"(): DividePath() failed; no memory; returning ...\n")); } else { // // no slashes left, break the loop // st = STATUS_SUCCESS; } break; } // // path splitted, continue; // get NT name for this file in directory // st = QueryNtPath(&usTargetRoot,&usTargetFileName,&usNtFileName); if (NT_SUCCESS(st)) { // // ok, got NT path for this file/dir element, save it // ULONG NewPathLen; if (wcsrcat(PathBuffer,PathBufferLength/sizeof(WCHAR),&usNtFileName,&NewPathLen)) { if (NewPathLen*sizeof(WCHAR) >= PathBufferLength-sizeof(WCHAR)) { RtlFreeUnicodeString(&usNtFileName); break; } wcscat(PathBuffer,L"\\"); } RtlFreeUnicodeString(&usNtFileName); } // // pass to parent directory // free usCurrentPath contains previous usTargetRoot that need to free after DividePath() // but not first time when it contains user-specified DosPath string // if (usCurrentPath.Buffer != DosPathName->Buffer) RtlFreeUnicodeString(&usCurrentPath); // pass to parent usCurrentPath = usTargetRoot; } // end for (;;) // // free last usTargetRoot // if (usTargetRoot.Buffer != NULL) RtlFreeUnicodeString(&usTargetRoot); if (NT_SUCCESS(st)) { // // ok, save reversed string we generated to user buffer // wcs_reverse(PathBuffer); RtlInitUnicodeString(NtPathName,PathBuffer); } else { ExFreePool(PathBuffer); } return st; } /////// static VOID TestMyFuckingStuff() { UNICODE_STRING usDosPath, usNTPath; RtlInitUnicodeString(&usDosPath,L"\\??\\C:\\DOCUME~1\\ALLUSE~1\\APPLIC~1\\Acronis\\DiskDi~1\\Logs\\test.txt"); NTSTATUS st = TranslateDosToNtPathName(&usDosPath,&usNTPath); if (NT_SUCCESS(st)) { KdPrint(("SOURCE: %wZ\n",&usDosPath)); KdPrint(("CONVERTED TO: %wZ\n",&usNTPath)); if (usNTPath.Buffer != usDosPath.Buffer) RtlFreeUnicodeString(&usNTPath); } else { KdPrint((__FUNCTION__"(): FAILED, status %08x\n",st)); } } =)