diff --git a/src/shared/ntdll_declarations.cpp b/src/shared/ntdll_declarations.cpp index c2ca05b..3ed0a06 100644 --- a/src/shared/ntdll_declarations.cpp +++ b/src/shared/ntdll_declarations.cpp @@ -27,6 +27,8 @@ NtQueryDirectoryFile_type NtQueryDirectoryFile; NtQueryDirectoryFileEx_type NtQueryDirectoryFileEx; NtQueryFullAttributesFile_type NtQueryFullAttributesFile; NtQueryAttributesFile_type NtQueryAttributesFile; +NtQueryObject_type NtQueryObject; +NtQueryInformationFile_type NtQueryInformationFile; NtOpenFile_type NtOpenFile; NtCreateFile_type NtCreateFile; NtClose_type NtClose; @@ -46,6 +48,8 @@ void ntdll_declarations_init() { LOAD_EXT(ntDLLMod, NtQueryDirectoryFileEx); LOAD_EXT(ntDLLMod, NtQueryFullAttributesFile); LOAD_EXT(ntDLLMod, NtQueryAttributesFile); + LOAD_EXT(ntDLLMod, NtQueryObject); + LOAD_EXT(ntDLLMod, NtQueryInformationFile); LOAD_EXT(ntDLLMod, NtCreateFile); LOAD_EXT(ntDLLMod, NtOpenFile); LOAD_EXT(ntDLLMod, NtClose); diff --git a/src/shared/ntdll_declarations.h b/src/shared/ntdll_declarations.h index 74ca5ec..981cb12 100644 --- a/src/shared/ntdll_declarations.h +++ b/src/shared/ntdll_declarations.h @@ -116,6 +116,24 @@ typedef struct _FILE_ID_BOTH_DIR_INFORMATION { WCHAR FileName[1]; } FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_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; + +typedef struct _FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + typedef struct _FILE_NAMES_INFORMATION { ULONG NextEntryOffset; ULONG FileIndex; @@ -123,6 +141,55 @@ typedef struct _FILE_NAMES_INFORMATION { WCHAR FileName[1]; } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; +typedef struct _FILE_INTERNAL_INFORMATION +{ + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION +{ + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION +{ + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_MODE_INFORMATION +{ + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION +{ + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION +{ + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + typedef struct _FILE_OBJECTID_INFORMATION { LONGLONG FileReference; UCHAR ObjectId[16]; @@ -158,13 +225,17 @@ typedef enum _FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, FileFullDirectoryInformation = 2, FileBothDirectoryInformation = 3, + FileStandardInformation = 5, + FileNameInformation = 9, + FileRenameInformation = 10, FileNamesInformation = 12, + FileAllInformation = 18, FileObjectIdInformation = 29, FileReparsePointInformation = 33, FileIdBothDirectoryInformation = 37, - FileIdFullDirectoryInformation = 38 -} FILE_INFORMATION_CLASS, - *PFILE_INFORMATION_CLASS; + FileIdFullDirectoryInformation = 38, + FileNormalizedNameInformation = 48, +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; typedef enum _MODE { KernelMode, UserMode, MaximumMode } MODE; @@ -253,6 +324,12 @@ typedef struct _OBJECT_HANDLE_INFORMATION { ACCESS_MASK GrantedAccess; } OBJECT_HANDLE_INFORMATION, *POBJECT_HANDLE_INFORMATION; +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation = 0, + ObjectTypeInformation = 2 +} OBJECT_INFORMATION_CLASS; + typedef struct _RTL_RELATIVE_NAME { UNICODE_STRING RelativeName; HANDLE ContainingDirectory; @@ -269,14 +346,6 @@ typedef struct _FILE_NETWORK_OPEN_INFORMATION { ULONG FileAttributes; } FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_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; - #define FILE_DIRECTORY_FILE 0x00000001 #define FILE_WRITE_THROUGH 0x00000002 #define FILE_SEQUENTIAL_ONLY 0x00000004 @@ -302,55 +371,62 @@ typedef struct _FILE_BASIC_INFORMATION { #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 #define FILE_CONTAINS_EXTENDED_CREATE_INFORMATION 0x10000000 -typedef NTSTATUS(WINAPI *NtQueryDirectoryFile_type)( +// Nt + +using NtQueryDirectoryFile_type = NTSTATUS(WINAPI *)( HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, BOOLEAN, PUNICODE_STRING, BOOLEAN); - -typedef NTSTATUS(WINAPI *NtQueryDirectoryFileEx_type)( +using NtQueryDirectoryFileEx_type = NTSTATUS(WINAPI *)( HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS, ULONG, PUNICODE_STRING); -typedef NTSTATUS(WINAPI *NtQueryFullAttributesFile_type)( +using NtQueryFullAttributesFile_type = NTSTATUS(WINAPI *)( POBJECT_ATTRIBUTES, PFILE_NETWORK_OPEN_INFORMATION); - -typedef NTSTATUS(WINAPI *NtQueryAttributesFile_type)(POBJECT_ATTRIBUTES, +using NtQueryAttributesFile_type = NTSTATUS(WINAPI *)(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION); -typedef NTSTATUS(WINAPI *NtOpenFile_type)(PHANDLE, ACCESS_MASK, +using NtQueryObject_type = NTSTATUS (WINAPI *)( + HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, + PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); +using NtQueryInformationFile_type = NTSTATUS(WINAPI*)( + HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + +using NtOpenFile_type = NTSTATUS(WINAPI *)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG); - -typedef NTSTATUS(WINAPI *NtCreateFile_type)(PHANDLE, ACCESS_MASK, +using NtCreateFile_type = NTSTATUS(WINAPI *)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, PLARGE_INTEGER, ULONG, ULONG, ULONG, ULONG, PVOID, ULONG); -typedef NTSTATUS(WINAPI *NtClose_type)(HANDLE); - -typedef NTSYSAPI BOOLEAN(NTAPI *RtlDoesFileExists_U_type)(PCWSTR); - -typedef NTSTATUS(NTAPI *RtlDosPathNameToRelativeNtPathName_U_WithStatus_type)( - PCWSTR DosFileName, PUNICODE_STRING NtFileName, PWSTR* FilePath, PRTL_RELATIVE_NAME RelativeName); +using NtClose_type = NTSTATUS(WINAPI *)(HANDLE); -typedef void (NTAPI *RtlReleaseRelativeName_type)(PRTL_RELATIVE_NAME RelativeName); +using NtTerminateProcess_type = NTSTATUS(WINAPI *)(HANDLE ProcessHandle, NTSTATUS ExitStatus); -typedef NTSTATUS (NTAPI *RtlGetVersion_type)(PRTL_OSVERSIONINFOW); +// Rtl -typedef NTSTATUS(WINAPI *NtTerminateProcess_type)(HANDLE ProcessHandle, NTSTATUS ExitStatus); +using RtlDoesFileExists_U_type = NTSYSAPI BOOLEAN(NTAPI *)(PCWSTR); +using RtlDosPathNameToRelativeNtPathName_U_WithStatus_type = NTSTATUS(NTAPI *)( + PCWSTR DosFileName, PUNICODE_STRING NtFileName, PWSTR* FilePath, PRTL_RELATIVE_NAME RelativeName); +using RtlReleaseRelativeName_type = void (NTAPI *)(PRTL_RELATIVE_NAME RelativeName); +using RtlGetVersion_type = NTSTATUS (NTAPI *)(PRTL_OSVERSIONINFOW); extern NtQueryDirectoryFile_type NtQueryDirectoryFile; extern NtQueryDirectoryFileEx_type NtQueryDirectoryFileEx; extern NtQueryFullAttributesFile_type NtQueryFullAttributesFile; extern NtQueryAttributesFile_type NtQueryAttributesFile; +extern NtQueryObject_type NtQueryObject; +extern NtQueryInformationFile_type NtQueryInformationFile; extern NtOpenFile_type NtOpenFile; extern NtCreateFile_type NtCreateFile; extern NtClose_type NtClose; +extern NtTerminateProcess_type NtTerminateProcess; extern RtlDoesFileExists_U_type RtlDoesFileExists_U; extern RtlDosPathNameToRelativeNtPathName_U_WithStatus_type RtlDosPathNameToRelativeNtPathName_U_WithStatus; extern RtlReleaseRelativeName_type RtlReleaseRelativeName; extern RtlGetVersion_type RtlGetVersion; -extern NtTerminateProcess_type NtTerminateProcess; // ensures ntdll functions have been initialized (only needed during static objects initialization) void ntdll_declarations_init(); diff --git a/src/usvfs_dll/hookmanager.cpp b/src/usvfs_dll/hookmanager.cpp index eccceea..ddf41b2 100644 --- a/src/usvfs_dll/hookmanager.cpp +++ b/src/usvfs_dll/hookmanager.cpp @@ -267,6 +267,8 @@ void HookManager::initHooks() installHook(ntdllMod, nullptr, "NtQueryAttributesFile", hook_NtQueryAttributesFile); installHook(ntdllMod, nullptr, "NtQueryDirectoryFile", hook_NtQueryDirectoryFile); installHook(ntdllMod, nullptr, "NtQueryDirectoryFileEx", hook_NtQueryDirectoryFileEx); + installHook(ntdllMod, nullptr, "NtQueryObject", hook_NtQueryObject); + installHook(ntdllMod, nullptr, "NtQueryInformationFile", hook_NtQueryInformationFile); installHook(ntdllMod, nullptr, "NtOpenFile", hook_NtOpenFile); installHook(ntdllMod, nullptr, "NtCreateFile", hook_NtCreateFile); installHook(ntdllMod, nullptr, "NtClose", hook_NtClose); diff --git a/src/usvfs_dll/hooks/ntdll.cpp b/src/usvfs_dll/hooks/ntdll.cpp index 5b7083d..ca69ccc 100644 --- a/src/usvfs_dll/hooks/ntdll.cpp +++ b/src/usvfs_dll/hooks/ntdll.cpp @@ -372,6 +372,10 @@ void SetInfoFilename(LPVOID address, FILE_INFORMATION_CLASS infoClass, const std::wstring &fileName) { switch (infoClass) { + case FileAllInformation: { + SetInfoFilenameImpl( + &reinterpret_cast(address)->NameInformation, fileName); + } break; case FileBothDirectoryInformation: { SetInfoFilenameImplSN( reinterpret_cast(address), fileName); @@ -380,9 +384,17 @@ void SetInfoFilename(LPVOID address, FILE_INFORMATION_CLASS infoClass, SetInfoFilenameImpl( reinterpret_cast(address), fileName); } break; + case FileNameInformation: { + SetInfoFilenameImpl( + reinterpret_cast(address), fileName); + } break; case FileNamesInformation: { - SetInfoFilenameImpl(reinterpret_cast(address), - fileName); + SetInfoFilenameImpl( + reinterpret_cast(address), fileName); + } break; + case FileNormalizedNameInformation: { + SetInfoFilenameImpl( + reinterpret_cast(address), fileName); } break; case FileIdFullDirectoryInformation: { SetInfoFilenameImpl( @@ -394,8 +406,7 @@ void SetInfoFilename(LPVOID address, FILE_INFORMATION_CLASS infoClass, } break; case FileIdBothDirectoryInformation: { SetInfoFilenameImplSN( - reinterpret_cast(address), - fileName); + reinterpret_cast(address), fileName); } break; default: { // NOP @@ -1040,6 +1051,83 @@ NTSTATUS WINAPI usvfs::hook_NtQueryDirectoryFileEx( return res; } +DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryObject( + HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, + PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + NTSTATUS res; + + HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) + if (!callContext.active()) { + return ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, + ObjectInformationLength, ReturnLength); + } + + PRE_REALCALL + res = ::NtQueryObject(Handle, ObjectInformationClass, ObjectInformation, + ObjectInformationLength, ReturnLength); + POST_REALCALL + + LOG_CALL() + .addParam("path", ntdllHandleTracker.lookup(Handle)) + .PARAM(ObjectInformationClass); + + HOOK_END + return res; +} + +DLLEXPORT NTSTATUS WINAPI usvfs::hook_NtQueryInformationFile( + HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + NTSTATUS res; + + HOOK_START_GROUP(MutExHookGroup::FILE_ATTRIBUTES) + if (!callContext.active()) { + return ::NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, + Length, FileInformationClass); + } + + PRE_REALCALL + res = ::NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, + FileInformationClass); + POST_REALCALL + + if (res == STATUS_SUCCESS && ( + FileInformationClass == FileNameInformation + || FileInformationClass == FileAllInformation + || FileInformationClass == FileNormalizedNameInformation)) { + + const auto trackerInfo = ntdllHandleTracker.lookup(FileHandle); + const auto redir = applyReroute(READ_CONTEXT(), callContext, trackerInfo); + + // TODO: difference between FileNameInformation and FileNormalizedNameInformation + + FILE_NAME_INFORMATION *info; + if (FileInformationClass == FileAllInformation) { + info = &reinterpret_cast(FileInformation)->NameInformation; + } else { + info = reinterpret_cast(FileInformation); + } + + if (redir.redirected) + { + SetInfoFilename(FileInformation, FileInformationClass, static_cast(redir.path)); + }; + + LOG_CALL() + .addParam("tracker_path", trackerInfo) + .PARAM(FileInformationClass) + .PARAM(redir.redirected) + .PARAM(redir.path) + .addParam("name_info", std::wstring{info->FileName, info->FileNameLength}); + + } + + HOOK_END + return res; +} + unique_ptr_deleter makeObjectAttributes(RedirectionInfo &redirInfo, POBJECT_ATTRIBUTES attributeTemplate) diff --git a/src/usvfs_dll/hooks/ntdll.h b/src/usvfs_dll/hooks/ntdll.h index befe7b1..9c22c96 100644 --- a/src/usvfs_dll/hooks/ntdll.h +++ b/src/usvfs_dll/hooks/ntdll.h @@ -40,6 +40,22 @@ hook_NtQueryDirectoryFileEx(HANDLE FileHandle, ULONG QueryFlags, PUNICODE_STRING FileName); +DLLEXPORT NTSTATUS WINAPI +hook_NtQueryObject( + HANDLE Handle, + OBJECT_INFORMATION_CLASS ObjectInformationClass, + PVOID ObjectInformation, + ULONG ObjectInformationLength, + PULONG ReturnLength); + +DLLEXPORT NTSTATUS WINAPI +hook_NtQueryInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + DLLEXPORT NTSTATUS WINAPI hook_NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, diff --git a/test/usvfs_global_test/usvfs_global_test.cpp b/test/usvfs_global_test/usvfs_global_test.cpp index 1cac40f..e934675 100644 --- a/test/usvfs_global_test/usvfs_global_test.cpp +++ b/test/usvfs_global_test/usvfs_global_test.cpp @@ -49,13 +49,13 @@ TEST(RedFileSystemTest, RedFileSystemTest) ASSERT_TRUE(exists(hudpainter_path / "DEFAULT.json")); + ASSERT_EQ(hudpainter_path / "TEST.json", + weakly_canonical(hudpainter_path / "TEST.json")); + { std::ofstream of{hudpainter_path / "TEST.json"}; of << "{}\n"; } - - // ASSERT_EQ(std::filesystem::path{}, weakly_canonical(hudpainter_path / - // "TEST.json")); } int main(int argc, char* argv[]) diff --git a/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp b/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp index 229f1e6..84964d8 100644 --- a/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp +++ b/test/usvfs_global_test_runner/usvfs_global_test_runner.cpp @@ -261,7 +261,7 @@ int usvfs_test_runner::run() const const auto data = m_temporary_folder / L"data"; // prepare usvfs and mapping - usvfs_guard guard; + usvfs_guard guard{"usvfs_test", true}; prepare_mapping(data, m_temporary_folder / L"mods", m_temporary_folder / L"overwrite"); @@ -271,6 +271,14 @@ int usvfs_test_runner::run() const {std::format(L"--gtest_filter={}.*", m_group), data.native()}); if (res != 0) { + const auto log_path = test::path_of_test_bin(m_group + L".log"); + std::ofstream os{log_path}; + std::string buffer(1024, '\0'); + std::cout << "process returned " << std::hex << res << ", usvfs logs dumped to " + << log_path.string() << '\n'; + while (usvfsGetLogMessages(buffer.data(), buffer.size(), false)) { + os << " " << buffer.c_str() << "\n"; + } return res; } @@ -323,5 +331,7 @@ int main(int argc, char* argv[]) testing::InitGoogleTest(&argc, argv); + usvfsInitLogging(false); + return RUN_ALL_TESTS(); }