diff options
author | jmpoep <OriginalEntryPoint@qq.com> | 2023-12-07 16:51:07 +0800 |
---|---|---|
committer | jmpoep <OriginalEntryPoint@qq.com> | 2023-12-07 16:51:07 +0800 |
commit | 28008a746a31abb7909dd86cb0cd413ac8943b0b (patch) | |
tree | a30b74b8cad548048c3c1551d652828ab76fa9bd /runtime/file_manager.cc | |
download | vmprotect-3.5.1-master.tar vmprotect-3.5.1-master.tar.gz vmprotect-3.5.1-master.tar.bz2 vmprotect-3.5.1-master.zip |
Diffstat (limited to 'runtime/file_manager.cc')
-rw-r--r-- | runtime/file_manager.cc | 1189 |
1 files changed, 1189 insertions, 0 deletions
diff --git a/runtime/file_manager.cc b/runtime/file_manager.cc new file mode 100644 index 0000000..9dcfc29 --- /dev/null +++ b/runtime/file_manager.cc @@ -0,0 +1,1189 @@ +#ifdef WIN_DRIVER +#else +#include "common.h" +#include "objects.h" + +#include "crypto.h" +#include "core.h" +#include "file_manager.h" +#include "hook_manager.h" +#include "utils.h" +#include "registry_manager.h" + +/** + * hooked functions + */ + +NTSTATUS WINAPI HookedNtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryAttributesFile(ObjectAttributes, FileInformation); +} + +NTSTATUS WINAPI HookedNtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); +} + +NTSTATUS WINAPI HookedNtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); +} + +NTSTATUS WINAPI HookedNtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS WINAPI HookedNtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryVolumeInformationFile(FileHandle, IoStatusBlock, FsInformation, Length, FsInformationClass); +} + +NTSTATUS WINAPI HookedNtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtSetInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS WINAPI HookedNtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); +} + +NTSTATUS WINAPI HookedNtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtReadFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key); +} + +NTSTATUS WINAPI HookedNtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); +} + +NTSTATUS WINAPI HookedNtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQuerySection(SectionHandle, InformationClass, InformationBuffer, InformationBufferSize, ResultLength); +} + +NTSTATUS WINAPI HookedNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); +} + +NTSTATUS WINAPI HookedNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtUnmapViewOfSection(ProcessHandle, BaseAddress); +} + +NTSTATUS WINAPI HookedNtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength) +{ + FileManager *file_manager = Core::Instance()->file_manager(); + return file_manager->NtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); +} + +/** + * FileManager + */ + +FileManager::FileManager(const uint8_t *data, HMODULE instance, const uint8_t *key, VirtualObjectList *objects) + : instance_(instance) + , data_(data) + , objects_(objects) + , nt_query_attributes_file_(NULL) + , nt_create_file_(NULL) + , nt_open_file_(NULL) + , nt_read_file_(NULL) + , nt_query_information_file_(NULL) + , nt_query_volume_information_file_(NULL) + , nt_set_information_file_(NULL) + , nt_query_directory_file_(NULL) + , nt_close_(NULL) + , nt_create_section_(NULL) + , nt_query_section_(NULL) + , nt_map_view_of_section_(NULL) + , nt_unmap_view_of_section_(NULL) + , nt_query_virtual_memory_(NULL) +{ + wchar_t dos_path[MAX_PATH]; + wchar_t nt_path[MAX_PATH]; + + key_ = *(reinterpret_cast<const uint32_t *>(key)); + + if (GetModuleFileNameW(NULL, dos_path, _countof(dos_path))) { + wchar_t *name = wcsrchr(dos_path, L'\\'); + name = (name ? name + 1 : dos_path); + *name = 0; + } else { + dos_path[0] = 0; + } + + nt_path[0] = 0; + HANDLE dir = CreateFileW(dos_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (dir != INVALID_HANDLE_VALUE) { + typedef NTSTATUS (WINAPI tNtQueryObject)(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + tNtQueryObject *nt_query_object = static_cast<tNtQueryObject *>(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtQueryObject"))); + if (nt_query_object) { + DWORD size = 0x800; + OBJECT_NAME_INFORMATION *info = reinterpret_cast<OBJECT_NAME_INFORMATION *>(new uint8_t[size]); + if (NT_SUCCESS(nt_query_object(dir, ObjectNameInformation, info, size, NULL))) { + memcpy(nt_path, info->Name.Buffer, info->Name.Length); + size = info->Name.Length / sizeof(wchar_t); + nt_path[size] = '\\'; + nt_path[size + 1] = 0; + } + delete [] info; + } + CloseHandle(dir); + } + + wchar_t *dos_end = dos_path + wcslen(dos_path); + wchar_t *nt_end = nt_path + wcslen(nt_path); + while (dos_end > dos_path && nt_end > nt_path) { + if (_wcsnicmp(dos_end, nt_end, 1) != 0) + break; + dos_end--; + nt_end--; + } + dos_end++; + nt_end++; + if (*dos_end == '\\') { + dos_end++; + nt_end++; + } + dos_root_.append(dos_path, dos_end - dos_path); + nt_root_.append(nt_path, nt_end - nt_path); + + Path path(dos_end); + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + const OBJECT_ENTRY *entry_enc = reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1); + OBJECT_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfEntries; i++) { + OBJECT_ENTRY entry = DecryptEntry(&entry_enc[i]); + if (DecryptString(reinterpret_cast<LPCWSTR>(reinterpret_cast<uint8_t *>(instance_) + entry.NameOffset), dos_path, _countof(dos_path))) { + file_name_list_.push_back(path.Combine(dos_path)); + } else { + file_name_list_.push_back(UnicodeString()); + } + } +} + +void FileManager::HookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + HMODULE dll = GetModuleHandleA(VMProtectDecryptStringA("ntdll.dll")); + nt_query_attributes_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryAttributesFile"), &HookedNtQueryAttributesFile); + nt_create_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtCreateFile"), &HookedNtCreateFile); + nt_open_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtOpenFile"), &HookedNtOpenFile); + nt_read_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtReadFile"), &HookedNtReadFile); + nt_query_information_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryInformationFile"), &HookedNtQueryInformationFile); + nt_query_volume_information_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryVolumeInformationFile"), &HookedNtQueryVolumeInformationFile); + nt_set_information_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtSetInformationFile"), &HookedNtSetInformationFile); + nt_query_directory_file_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryDirectoryFile"), &HookedNtQueryDirectoryFile); + nt_create_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtCreateSection"), &HookedNtCreateSection); + nt_query_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQuerySection"), &HookedNtQuerySection); + nt_map_view_of_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtMapViewOfSection"), &HookedNtMapViewOfSection); + nt_unmap_view_of_section_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtUnmapViewOfSection"), &HookedNtUnmapViewOfSection); + nt_query_virtual_memory_ = hook_manager.HookAPI(dll, VMProtectDecryptStringA("NtQueryVirtualMemory"), &HookedNtQueryVirtualMemory); + hook_manager.End(); +} + +void FileManager::UnhookAPIs(HookManager &hook_manager) +{ + hook_manager.Begin(); + hook_manager.UnhookAPI(nt_query_attributes_file_); + hook_manager.UnhookAPI(nt_create_file_); + hook_manager.UnhookAPI(nt_open_file_); + hook_manager.UnhookAPI(nt_read_file_); + hook_manager.UnhookAPI(nt_query_information_file_); + hook_manager.UnhookAPI(nt_query_volume_information_file_); + hook_manager.UnhookAPI(nt_set_information_file_); + hook_manager.UnhookAPI(nt_query_directory_file_); + hook_manager.UnhookAPI(nt_create_section_); + hook_manager.UnhookAPI(nt_query_section_); + hook_manager.UnhookAPI(nt_map_view_of_section_); + hook_manager.UnhookAPI(nt_unmap_view_of_section_); + hook_manager.UnhookAPI(nt_query_virtual_memory_); + hook_manager.End(); +} + +bool FileManager::DecryptString(LPCWSTR str_enc, LPWSTR str, size_t count) const +{ + for (size_t i = 0; i < count; i++) { + str[i] = static_cast<wchar_t>(str_enc[i] ^ (_rotl32(key_, static_cast<int>(i)) + i)); + if (!str[i]) + return true; + } + // source string is too long + return false; +} + +bool FileManager::OpenFiles(RegistryManager ®istry_manager) +{ + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + const OBJECT_ENTRY *entry_enc = reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1); + + wchar_t file_name[MAX_PATH]; + OBJECT_DIRECTORY directory = DecryptDirectory(directory_enc); + for (size_t i = 0; i < directory.NumberOfEntries; i++) { + OBJECT_ENTRY entry = DecryptEntry(&entry_enc[i]); + if ((entry.Options & (FILE_LOAD | FILE_REGISTER | FILE_INSTALL)) == 0) + continue; + + if (!DecryptString(reinterpret_cast<LPCWSTR>(reinterpret_cast<uint8_t *>(instance_) + entry.NameOffset), file_name, _countof(file_name))) + return false; + + HMODULE h = LoadLibraryW(file_name); + if (h) { + for (size_t j = 0; j < 2; j++) { + size_t mask = (j == 0) ? FILE_REGISTER : FILE_INSTALL; + if (entry.Options & mask) { + VMP_CHAR error[MAX_PATH + 100]; + error[0] = 0; + void *proc = InternalGetProcAddress(h, (j == 0) ? "DllRegisterServer" : "DllInstall"); + if (proc) { + HRESULT res = S_OK; + registry_manager.BeginRegisterServer(); + try { + if (j == 0) { + typedef HRESULT (WINAPI tRegisterServer)(void); + tRegisterServer *register_server = reinterpret_cast<tRegisterServer *>(proc); + res = register_server(); + } else { + typedef HRESULT (WINAPI tInstallServer)(BOOL, LPCWSTR); + tInstallServer *install_server = reinterpret_cast<tInstallServer *>(proc); + res = install_server(TRUE, L""); + } + } catch(...) { + res = 0xC0000005; + } + registry_manager.EndRegisterServer(); + if (res != S_OK) + swprintf_s(error, L"Cannot %s server %s\nError: 0x%X", (j == 0) ? L"register" : L"install", file_name, res); + } else { + swprintf_s(error, L"The procedure entry point %s could not be located in the module %s", (j == 0) ? L"DllRegisterServer" : L"DllInstall", file_name); + } + if (error[0]) { + FreeLibrary(h); + ShowMessage(error); + return false; + } + } + } + if ((entry.Options & FILE_LOAD) == 0) + FreeLibrary(h); + } else { + VMP_CHAR error[MAX_PATH + 100]; + swprintf_s(error, L"Cannot load file %s\nError: %d", file_name, GetLastError()); + ShowMessage(error); + return false; + } + } + return true; +} + +NTSTATUS __forceinline FileManager::TrueNtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) +{ + typedef NTSTATUS (WINAPI tNtQueryAttributesFile)(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation); + return reinterpret_cast<tNtQueryAttributesFile *>(nt_query_attributes_file_)(ObjectAttributes, FileInformation); +} + +NTSTATUS __forceinline FileManager::TrueNtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) +{ + typedef NTSTATUS (WINAPI tNtCreateFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); + return reinterpret_cast<tNtCreateFile *>(nt_create_file_)(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); +} + +NTSTATUS __forceinline FileManager::TrueNtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) +{ + typedef NTSTATUS (WINAPI tNtOpenFile)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions); + return reinterpret_cast<tNtOpenFile *>(nt_open_file_)(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + typedef NTSTATUS (WINAPI tNtQueryInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + return reinterpret_cast<tNtQueryInformationFile *>(nt_query_information_file_)(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass) +{ + typedef NTSTATUS (WINAPI tNtQueryVolumeInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass); + return reinterpret_cast<tNtQueryVolumeInformationFile *>(nt_query_volume_information_file_)(FileHandle, IoStatusBlock, FsInformation, Length, FsInformationClass); +} + +NTSTATUS __forceinline FileManager::TrueNtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + typedef NTSTATUS (WINAPI tNtSetInformationFile)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + return reinterpret_cast<tNtSetInformationFile *>(nt_set_information_file_)(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) +{ + typedef NTSTATUS(WINAPI tNtQueryDirectoryFile)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan); + return reinterpret_cast<tNtQueryDirectoryFile *>(nt_query_directory_file_)(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); +} + +NTSTATUS __forceinline FileManager::TrueNtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) +{ + typedef NTSTATUS (WINAPI tNtReadFile)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); + return reinterpret_cast<tNtReadFile *>(nt_read_file_)(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key); +} + +NTSTATUS __forceinline FileManager::TrueNtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) +{ + typedef NTSTATUS (WINAPI tNtCreateSection)(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle); + return reinterpret_cast<tNtCreateSection *>(nt_create_section_)(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); +} + +NTSTATUS __forceinline FileManager::TrueNtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtQuerySection)(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength); + return reinterpret_cast<tNtQuerySection *>(nt_query_section_)(SectionHandle, InformationClass, InformationBuffer, InformationBufferSize, ResultLength); +} + +NTSTATUS __forceinline FileManager::TrueNtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + typedef NTSTATUS (WINAPI tNtMapViewOfSection)(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect); + return reinterpret_cast<tNtMapViewOfSection *>(nt_map_view_of_section_)(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); +} + +NTSTATUS __forceinline FileManager::TrueNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) +{ + typedef NTSTATUS (WINAPI tNtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress); + return reinterpret_cast<tNtUnmapViewOfSection *>(nt_unmap_view_of_section_)(ProcessHandle, BaseAddress); +} + +NTSTATUS __forceinline FileManager::TrueNtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength) +{ + typedef NTSTATUS (WINAPI tNtQueryVirtualMemory)(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength); + return reinterpret_cast<tNtQueryVirtualMemory *>(nt_query_virtual_memory_)(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); +} + +OBJECT_DIRECTORY FileManager::DecryptDirectory(const OBJECT_DIRECTORY *directory_enc) const +{ + OBJECT_DIRECTORY res; + res.NumberOfEntries = directory_enc->NumberOfEntries ^ key_; + return res; +} + +OBJECT_ENTRY FileManager::DecryptEntry(const OBJECT_ENTRY *entry_enc) const +{ + OBJECT_ENTRY res; + res.NameOffset = entry_enc->NameOffset ^ key_; + res.OffsetToData = entry_enc->OffsetToData ^ key_; + res.Size = entry_enc->Size ^ key_; + res.Options = entry_enc->Options ^ key_; + return res; +} + +NTSTATUS __forceinline FileManager::TrueNtQueryObject(HANDLE Handle, OBJECT_INFORMATION_CLASS ObjectInformationClass, PVOID ObjectInformation, ULONG ObjectInformationLength, PULONG ReturnLength) +{ + return Core::Instance()->TrueNtQueryObject(Handle, ObjectInformationClass, ObjectInformation, ObjectInformationLength, ReturnLength); +} + +const OBJECT_ENTRY *FileManager::FindEntry(HANDLE directory, PUNICODE_STRING object_name) +{ + UnicodeString file_name; + bool check_root = true; + if (directory) { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(directory); + if (object) { + check_root = false; + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + for (size_t i = 0; i < file_name_list_.size(); i++) { + if (object->ref() == reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1) + i) { + file_name = file_name_list_[i].c_str(); + break; + } + } + } else { + DWORD size = 0x800; + OBJECT_NAME_INFORMATION *info = reinterpret_cast<OBJECT_NAME_INFORMATION *>(new uint8_t[size]); + if (NT_SUCCESS(TrueNtQueryObject(directory, ObjectNameInformation, info, size, NULL))) + file_name.append(info->Name.Buffer, info->Name.Length / sizeof(wchar_t)); + delete[] info; + } + if (file_name.size()) + file_name.append(L"\\"); + } + file_name.append(object_name->Buffer, object_name->Length / sizeof(wchar_t)); + + LPCWSTR name = file_name.c_str(); + if (check_root) { + LPCWSTR path; + if (name[0] == '\\' && name[1] == '?' && name[2] == '?' && name[3] == '\\') { + path = dos_root_.c_str(); + name += 4; + if (name[0] == 'U' && name[1] == 'N' && name[2] == 'C' && name[3] == '\\') { + name += 3; + if (path[0] == '\\' && path[1] == '\\') + path++; + } + } + else { + path = nt_root_.c_str(); + } + + size_t len = wcslen(path); + if (_wcsnicmp(name, path, len) != 0) + return NULL; + name += len; + } + + const OBJECT_DIRECTORY *directory_enc = reinterpret_cast<const OBJECT_DIRECTORY *>(data_); + for (size_t i = 0; i < file_name_list_.size(); i++) { + UnicodeString *file_name = &file_name_list_[i]; + size_t len = file_name->size(); + if (_wcsnicmp(file_name->c_str(), name, len) == 0) { + const OBJECT_ENTRY *entry_enc = reinterpret_cast<const OBJECT_ENTRY *>(directory_enc + 1) + i; + if (name[len]) { + OBJECT_ENTRY entry = DecryptEntry(entry_enc); + if (entry.OffsetToData || name[len] != '\\' || name[len + 1]) + continue; + } + return entry_enc; + } + } + + return NULL; +} + +__declspec(noinline) bool FileManager::ReadFile(const OBJECT_ENTRY *entry, uint64_t offset, void *dst, size_t size) const +{ + if (entry->Size < offset + size) + return false; + + uint8_t *source = reinterpret_cast<uint8_t *>(instance_) + entry->OffsetToData; + uint8_t *address = reinterpret_cast<uint8_t *>(dst); + for (size_t p = 0; p < size; p++) { + uint64_t i = offset + p; + address[p] = source[i] ^ static_cast<uint8_t>(_rotl32(key_, static_cast<int>(i)) + i); + } + return true; +} + +NTSTATUS FileManager::ReadImageHeader(const OBJECT_ENTRY *entry, IMAGE_NT_HEADERS *header) const +{ + IMAGE_DOS_HEADER dos_header; + if (ReadFile(entry, 0, &dos_header, sizeof(dos_header)) && dos_header.e_magic == IMAGE_DOS_SIGNATURE && dos_header.e_lfanew) { + IMAGE_NT_HEADERS nt_header; + if (ReadFile(entry, dos_header.e_lfanew, &nt_header, sizeof(nt_header))) { + if (nt_header.Signature == IMAGE_NT_SIGNATURE && (nt_header.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0) { +#ifdef _WIN64 + if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC && nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) +#else + if (nt_header.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC && (nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I386 || nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I486 || nt_header.FileHeader.Machine == IMAGE_FILE_MACHINE_I586)) +#endif + *header = nt_header; + return STATUS_SUCCESS; + } + } + } + return STATUS_INVALID_IMAGE_FORMAT; +} + +NTSTATUS FileManager::ReadImage(const OBJECT_ENTRY *entry, void *base) const +{ + IMAGE_NT_HEADERS tmp_header; + NTSTATUS status = ReadImageHeader(entry, &tmp_header); + if (status != STATUS_SUCCESS) + return status; + + uint8_t *image_base = reinterpret_cast<uint8_t *>(base); + if (!ReadFile(entry, 0, image_base, tmp_header.OptionalHeader.SizeOfHeaders)) + return STATUS_INVALID_IMAGE_FORMAT; + + IMAGE_DOS_HEADER *dos_header = reinterpret_cast<IMAGE_DOS_HEADER *>(image_base); + IMAGE_NT_HEADERS *nt_header = reinterpret_cast<IMAGE_NT_HEADERS *>(image_base + dos_header->e_lfanew); + IMAGE_SECTION_HEADER *sections = reinterpret_cast<IMAGE_SECTION_HEADER *>(reinterpret_cast<uint8_t *>(&nt_header->OptionalHeader) + nt_header->FileHeader.SizeOfOptionalHeader); + + // copy sections + for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { + IMAGE_SECTION_HEADER *section = sections + i; + + uint32_t virtual_size = section->Misc.VirtualSize; + uint32_t physical_size = section->SizeOfRawData; + + uint8_t *address = image_base + section->VirtualAddress; + ::ZeroMemory(address, virtual_size); + + if (!ReadFile(entry, section->PointerToRawData, address, std::min(physical_size, virtual_size))) + return STATUS_INVALID_IMAGE_FORMAT; + } + + // setup relocs + ptrdiff_t delta_base = image_base - reinterpret_cast<uint8_t *>(nt_header->OptionalHeader.ImageBase); + if (delta_base) { + IMAGE_DATA_DIRECTORY *reloc_directory = &nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if (reloc_directory->VirtualAddress && reloc_directory->Size && (nt_header->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) { + size_t processed = 0; + while (processed < reloc_directory->Size) { + IMAGE_BASE_RELOCATION *reloc = reinterpret_cast<IMAGE_BASE_RELOCATION *>(image_base + reloc_directory->VirtualAddress + processed); + if (!reloc->SizeOfBlock) + break; + + if (reloc->SizeOfBlock <= sizeof(IMAGE_BASE_RELOCATION) || (reloc->SizeOfBlock & 1) != 0) + return STATUS_INVALID_IMAGE_FORMAT; + + size_t c = (reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; + for (size_t i = 0; i < c; i++) { + uint16_t type_offset = reinterpret_cast<uint16_t *>(reloc + 1)[i]; + uint8_t *address = image_base + reloc->VirtualAddress + (type_offset & 0xfff); + switch (type_offset >> 12) { + case IMAGE_REL_BASED_HIGHLOW: + *(reinterpret_cast<uint32_t *>(address)) += static_cast<uint32_t>(delta_base); + break; + case IMAGE_REL_BASED_HIGH: + *(reinterpret_cast<uint16_t *>(address)) += static_cast<uint16_t>(delta_base >> 16); + break; + case IMAGE_REL_BASED_LOW: + *(reinterpret_cast<uint16_t *>(address)) += static_cast<uint16_t>(delta_base); + break; + case IMAGE_REL_BASED_DIR64: + *(reinterpret_cast<uint64_t *>(address)) += delta_base; + break; + } + } + processed += reloc->SizeOfBlock; + } + } + nt_header->OptionalHeader.ImageBase = reinterpret_cast<size_t>(image_base); + } + + // setup pages protection + DWORD old_protect; + if (!VirtualProtect(image_base, nt_header->OptionalHeader.SizeOfHeaders, PAGE_READONLY, &old_protect)) + return STATUS_INVALID_PAGE_PROTECTION; + + for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) { + IMAGE_SECTION_HEADER *section = sections + i; + + ULONG protection = 0; + if ((section->Characteristics & IMAGE_SCN_MEM_NOT_CACHED) != 0) + protection |= PAGE_NOCACHE; + if ((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) { + protection |= PAGE_EXECUTE_READWRITE; + } else if ((section->Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)) == (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)) { + protection |= PAGE_EXECUTE_READ; + } else if ((section->Characteristics & (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) { + protection |= PAGE_READWRITE; + } else if ((section->Characteristics & IMAGE_SCN_MEM_WRITE) != 0) { + protection |= PAGE_WRITECOPY; + } else if ((section->Characteristics & IMAGE_SCN_MEM_READ) != 0) { + protection |= PAGE_READONLY; + } else { + protection |= PAGE_NOACCESS; + } + if (!VirtualProtect(image_base + section->VirtualAddress, section->Misc.VirtualSize, protection, &old_protect)) + return STATUS_INVALID_PAGE_PROTECTION; + } + return STATUS_SUCCESS; +} + +NTSTATUS FileManager::NtQueryAttributesFile(POBJECT_ATTRIBUTES ObjectAttributes, PFILE_BASIC_INFORMATION FileInformation) +{ + const OBJECT_ENTRY *entry = FindEntry(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName); + if (entry) { + try { + FileInformation->CreationTime.QuadPart = 0; + FileInformation->LastAccessTime.QuadPart = 0; + FileInformation->LastWriteTime.QuadPart = 0; + FileInformation->ChangeTime.QuadPart = 0; + FileInformation->FileAttributes = FILE_ATTRIBUTE_READONLY; + return STATUS_SUCCESS; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtQueryAttributesFile(ObjectAttributes, FileInformation); +} + +NTSTATUS FileManager::NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength) +{ + const OBJECT_ENTRY *entry = FindEntry(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName); + if (entry) { + try { + NTSTATUS status; + switch (CreateDisposition) { + case FILE_OPEN: + case FILE_OPEN_IF: + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->Add(OBJECT_FILE, const_cast<OBJECT_ENTRY *>(entry), ::CreateEventA(NULL, false, false, NULL), DesiredAccess); + *FileHandle = object->handle(); + } + IoStatusBlock->Information = FILE_OPENED; + status = STATUS_SUCCESS; + break; + case FILE_SUPERSEDE: + case FILE_CREATE: + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + IoStatusBlock->Information = FILE_EXISTS; + status = STATUS_ACCESS_DENIED; + break; + default: + IoStatusBlock->Information = FILE_EXISTS; + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtCreateFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength); +} + +NTSTATUS FileManager::NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) +{ + const OBJECT_ENTRY *entry = FindEntry(ObjectAttributes->RootDirectory, ObjectAttributes->ObjectName); + if (entry) { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->Add(OBJECT_FILE, const_cast<OBJECT_ENTRY *>(entry), ::CreateEventA(NULL, false, false, NULL), DesiredAccess); + try { + *FileHandle = object->handle(); + NTSTATUS status = STATUS_SUCCESS; + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); +} + +NTSTATUS FileManager::NtQueryInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY*>(object->ref())); + try { + NTSTATUS status; + switch (FileInformationClass) { + case FileBasicInformation: + { + if (Length < sizeof(FILE_BASIC_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_BASIC_INFORMATION *info = reinterpret_cast<FILE_BASIC_INFORMATION *>(FileInformation); + info->CreationTime.QuadPart = 0; + info->LastAccessTime.QuadPart = 0; + info->LastWriteTime.QuadPart = 0; + info->ChangeTime.QuadPart = 0; + info->FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + } + status = STATUS_SUCCESS; + break; + case FilePositionInformation: + { + if (Length < sizeof(FILE_POSITION_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_POSITION_INFORMATION *info = reinterpret_cast<FILE_POSITION_INFORMATION *>(FileInformation); + info->CurrentByteOffset.QuadPart = object->file_position(); + } + status = STATUS_SUCCESS; + break; + case FileStandardInformation: + { + if (Length < sizeof(FILE_STANDARD_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_STANDARD_INFORMATION *info = reinterpret_cast<FILE_STANDARD_INFORMATION *>(FileInformation); + info->AllocationSize.QuadPart = 0; + info->EndOfFile.QuadPart = entry.Size; + info->NumberOfLinks = 0; + info->DeletePending = FALSE; + info->Directory = entry.OffsetToData ? FALSE : TRUE; + } + status = STATUS_SUCCESS; + break; + case FileAllInformation: + { + if (Length < sizeof(FILE_ALL_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_ALL_INFORMATION *info = reinterpret_cast<FILE_ALL_INFORMATION *>(FileInformation); + info->BasicInformation.CreationTime.QuadPart = 0; + info->BasicInformation.LastAccessTime.QuadPart = 0; + info->BasicInformation.LastWriteTime.QuadPart = 0; + info->BasicInformation.ChangeTime.QuadPart = 0; + info->BasicInformation.FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + info->StandardInformation.AllocationSize.QuadPart = 0; + info->StandardInformation.EndOfFile.QuadPart = entry.Size; + info->StandardInformation.NumberOfLinks = 0; + info->StandardInformation.DeletePending = FALSE; + info->StandardInformation.Directory = entry.OffsetToData ? FALSE : TRUE; + info->InternalInformation.IndexNumber.QuadPart = 0; + info->EaInformation.EaSize = 0; + info->AccessInformation.AccessFlags = object->access(); + info->PositionInformation.CurrentByteOffset.QuadPart = object->file_position(); + info->ModeInformation.Mode = 0; + info->AlignmentInformation.AlignmentRequirement = 0; + info->NameInformation.FileNameLength = 0; + info->NameInformation.FileName[0] = 0; + } + status = STATUS_SUCCESS; + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtQueryInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS FileManager::NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + try { + NTSTATUS status = STATUS_SUCCESS; + switch (FsInformationClass) { + case FileFsVolumeInformation: + { + if (Length < sizeof(FILE_FS_VOLUME_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_FS_VOLUME_INFORMATION *info = reinterpret_cast<FILE_FS_VOLUME_INFORMATION *>(FsInformation); + info->VolumeCreationTime.QuadPart = 0; + info->VolumeSerialNumber = 0; + info->VolumeLabelLength = 0; + info->SupportsObjects = FALSE; + info->VolumeLabel[0] = 0; + } + break; + case FileFsDeviceInformation: + { + if (Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_FS_DEVICE_INFORMATION *info = reinterpret_cast<FILE_FS_DEVICE_INFORMATION *>(FsInformation); + info->DeviceType = FILE_DEVICE_DISK; + info->Characteristics = 0; + } + break; + case FileFsAttributeInformation: + { + if (Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_FS_ATTRIBUTE_INFORMATION *info = reinterpret_cast<FILE_FS_ATTRIBUTE_INFORMATION *>(FsInformation); + info->FileSystemAttributes = FILE_READ_ONLY_VOLUME; + info->MaximumComponentNameLength = MAX_PATH; + info->FileSystemNameLength = 0; + info->FileSystemName[0] = 0; + } + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtQueryVolumeInformationFile(FileHandle, IoStatusBlock, FsInformation, Length, FsInformationClass); +} + +NTSTATUS FileManager::NtSetInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + try { + NTSTATUS status; + switch (FileInformationClass) { + case FilePositionInformation: + { + if (Length < sizeof(FILE_POSITION_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_POSITION_INFORMATION *info = reinterpret_cast<FILE_POSITION_INFORMATION *>(FileInformation); + if (info->CurrentByteOffset.HighPart) + info->CurrentByteOffset.LowPart = -1; + object->set_file_position(info->CurrentByteOffset.LowPart); + + status = STATUS_SUCCESS; + break; + } + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + IoStatusBlock->Status = status; + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtSetInformationFile(FileHandle, IoStatusBlock, FileInformation, Length, FileInformationClass); +} + +NTSTATUS FileManager::NtQueryDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, + ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan) +{ + if (FileName) { + try { + bool wildcard_found = false; + for (size_t i = 0; i < FileName->Length / sizeof(WCHAR); i++) { + wchar_t c = FileName->Buffer[i]; + if (c == '*' || c == '?') { + wildcard_found = true; + break; + } + } + if (!wildcard_found) { + const OBJECT_ENTRY *enc_entry = FindEntry(FileHandle, FileName); + if (enc_entry) { + OBJECT_ENTRY entry = DecryptEntry(enc_entry); + NTSTATUS status; + switch (FileInformationClass) { + case FileBothDirectoryInformation: + { + if (Length < sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + FileName->Length) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_BOTH_DIR_INFORMATION *info = reinterpret_cast<FILE_BOTH_DIR_INFORMATION *>(FileInformation); + info->NextEntryOffset = 0; + info->FileIndex = 0; + info->CreationTime.QuadPart = 0; + info->LastAccessTime.QuadPart = 0; + info->LastWriteTime.QuadPart = 0; + info->ChangeTime.QuadPart = 0; + info->EndOfFile.QuadPart = entry.Size; + info->AllocationSize.QuadPart = entry.Size; + info->FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + info->FileNameLength = FileName->Length; + info->ShortNameLength = 0; + info->ShortName[0] = 0; + memcpy(info->FileName, FileName->Buffer, FileName->Length); + + IoStatusBlock->Information = sizeof(FILE_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + info->FileNameLength; + IoStatusBlock->Status = STATUS_SUCCESS; + status = STATUS_SUCCESS; + } + break; + case FileIdBothDirectoryInformation: + { + if (Length < sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + FileName->Length) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + FILE_ID_BOTH_DIR_INFORMATION *info = reinterpret_cast<FILE_ID_BOTH_DIR_INFORMATION *>(FileInformation); + info->NextEntryOffset = 0; + info->FileIndex = 0; + info->CreationTime.QuadPart = 0; + info->LastAccessTime.QuadPart = 0; + info->LastWriteTime.QuadPart = 0; + info->ChangeTime.QuadPart = 0; + info->EndOfFile.QuadPart = entry.Size; + info->AllocationSize.QuadPart = entry.Size; + info->FileAttributes = entry.OffsetToData ? FILE_ATTRIBUTE_READONLY : FILE_ATTRIBUTE_DIRECTORY; + info->FileNameLength = FileName->Length; + info->ShortNameLength = 0; + info->ShortName[0] = 0; + info->FileId.QuadPart = 0; + memcpy(info->FileName, FileName->Buffer, FileName->Length); + + IoStatusBlock->Information = sizeof(FILE_ID_BOTH_DIR_INFORMATION) - sizeof(WCHAR) + info->FileNameLength; + IoStatusBlock->Status = STATUS_SUCCESS; + status = STATUS_SUCCESS; + } + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + return status; + } + } + } + catch (...) { + return STATUS_ACCESS_VIOLATION; + } + } + + return TrueNtQueryDirectoryFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, FileInformation, Length, FileInformationClass, ReturnSingleEntry, FileName, RestartScan); +} + +NTSTATUS FileManager::NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + if (!entry.OffsetToData) + return STATUS_INVALID_DEVICE_REQUEST; + + try { + uint64_t file_position; + if (!ByteOffset || (ByteOffset->HighPart == -1 && ByteOffset->LowPart == FILE_USE_FILE_POINTER_POSITION)) + file_position = object->file_position(); + else + file_position = ByteOffset->QuadPart; + + if (file_position + Length > entry.Size) + Length = (file_position < entry.Size) ? entry.Size - static_cast<uint32_t>(file_position) : 0; + + if (ReadFile(&entry, file_position, Buffer, Length)) + object->set_file_position(file_position + Length); + else + Length = 0; + IoStatusBlock->Information = Length; + IoStatusBlock->Status = STATUS_SUCCESS; + return STATUS_SUCCESS; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + + return TrueNtReadFile(FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key); +} + +NTSTATUS FileManager::NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PLARGE_INTEGER MaximumSize, ULONG SectionPageProtection, ULONG AllocationAttributes, HANDLE FileHandle) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetFile(FileHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + if (!entry.OffsetToData) + return STATUS_INVALID_FILE_FOR_SECTION; + + NTSTATUS status; + LARGE_INTEGER image_size; + if (AllocationAttributes & SEC_IMAGE) { + IMAGE_NT_HEADERS nt_header; + status = ReadImageHeader(&entry, &nt_header); + if (status != STATUS_SUCCESS) + return status; + image_size.QuadPart = nt_header.OptionalHeader.SizeOfImage; + } else { + image_size.QuadPart = entry.Size; + } + status = TrueNtCreateSection(SectionHandle, DesiredAccess | SECTION_MAP_WRITE, ObjectAttributes, &image_size, (AllocationAttributes & SEC_IMAGE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, SEC_COMMIT, NULL); + if (NT_SUCCESS(status)) { + VirtualObject *section = objects_->Add(OBJECT_SECTION, object->ref(), *SectionHandle, DesiredAccess); + section->set_attributes(AllocationAttributes); + } + return status; + } + } + + return TrueNtCreateSection(SectionHandle, DesiredAccess, ObjectAttributes, MaximumSize, SectionPageProtection, AllocationAttributes, FileHandle); +} + +NTSTATUS FileManager::NtQuerySection(HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass, PVOID InformationBuffer, ULONG InformationBufferSize, PULONG ResultLength) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetSection(SectionHandle); + if (object && (object->attributes() & SEC_IMAGE)) { + IMAGE_NT_HEADERS nt_header; + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + NTSTATUS status = ReadImageHeader(&entry, &nt_header); + if (NT_SUCCESS(status)) { + try { + switch (InformationClass) { + case SectionBasicInformation: + { + if (InformationBufferSize < sizeof(SECTION_BASIC_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + SECTION_BASIC_INFORMATION *info = reinterpret_cast<SECTION_BASIC_INFORMATION *>(InformationBuffer); + memset(info, 0, sizeof(*info)); + info->Attributes = SEC_IMAGE; + info->Size.QuadPart = nt_header.OptionalHeader.SizeOfImage; + if (ResultLength) + *ResultLength = sizeof(SECTION_BASIC_INFORMATION); + } + status = STATUS_SUCCESS; + break; + case SectionImageInformation: + { + if (InformationBufferSize < sizeof(SECTION_IMAGE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + SECTION_IMAGE_INFORMATION *info = reinterpret_cast<SECTION_IMAGE_INFORMATION *>(InformationBuffer); + memset(info, 0, sizeof(*info)); + info->ImageCharacteristics = nt_header.OptionalHeader.DllCharacteristics; + info->ImageMachineType = nt_header.FileHeader.Machine; + info->ImageSubsystem = nt_header.OptionalHeader.Subsystem; + info->StackCommit = static_cast<ULONG>(nt_header.OptionalHeader.SizeOfStackCommit); + info->StackReserved = static_cast<ULONG>(nt_header.OptionalHeader.SizeOfStackReserve); + info->StackZeroBits = 0; + info->SubSystemVersionHigh = nt_header.OptionalHeader.MajorSubsystemVersion; + info->SubSystemVersionLow = nt_header.OptionalHeader.MinorSubsystemVersion; + if (ResultLength) + *ResultLength = sizeof(SECTION_IMAGE_INFORMATION); + } + status = STATUS_SUCCESS; + break; + case SectionRelocationInformation: + { + if (InformationBufferSize < sizeof(ULONG_PTR)) { + status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + *reinterpret_cast<ULONG_PTR *>(InformationBuffer) = 0; + if (ResultLength) + *ResultLength = sizeof(ULONG_PTR); + } + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + return status; + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + } + } + + return TrueNtQuerySection(SectionHandle, InformationClass, InformationBuffer, InformationBufferSize, ResultLength); +} + +NTSTATUS FileManager::NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, SIZE_T CommitSize, PLARGE_INTEGER SectionOffset, PSIZE_T ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, ULONG Win32Protect) +{ + { + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetSection(SectionHandle); + if (object) { + OBJECT_ENTRY entry = DecryptEntry(static_cast<const OBJECT_ENTRY *>(object->ref())); + NTSTATUS status = TrueNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, 0, (object->attributes() & SEC_IMAGE) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); + if (NT_SUCCESS(status)) { + try { + uint64_t offset = (SectionOffset && SectionOffset->QuadPart) ? SectionOffset->QuadPart : 0; + if (object->attributes() & SEC_IMAGE) { + if (offset) + return STATUS_NOT_IMPLEMENTED; + status = ReadImage(&entry, *BaseAddress); + } else { + size_t size = *ViewSize; + if (offset + size > entry.Size) + size = (offset < entry.Size) ? entry.Size - static_cast<uint32_t>(offset) : 0; + ReadFile(&entry, offset, *BaseAddress, size); + if (Win32Protect != PAGE_READWRITE) { + ULONG old_protect; + if (!VirtualProtect(*BaseAddress, *ViewSize, Win32Protect, &old_protect)) + status = STATUS_INVALID_PAGE_PROTECTION; + } + } + if (NT_SUCCESS(status)) { + /*VirtualObject *map = */objects_->Add(OBJECT_MAP, *BaseAddress, ProcessHandle, 0); + } else { + TrueNtUnmapViewOfSection(ProcessHandle, *BaseAddress); + } + } catch(...) { + return STATUS_ACCESS_VIOLATION; + } + } + return status; + } + } + + return TrueNtMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, AllocationType, Win32Protect); +} + +NTSTATUS FileManager::NtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) +{ + { + CriticalSection cs(objects_->critical_section()); + + objects_->DeleteRef(BaseAddress, ProcessHandle); + } + + return TrueNtUnmapViewOfSection(ProcessHandle, BaseAddress); +} + +NTSTATUS FileManager::NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID Buffer, ULONG Length, PULONG ResultLength) +{ + if (MemoryInformationClass == MemoryBasicInformation) { + NTSTATUS status = TrueNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); + if (NT_SUCCESS(status)) { + MEMORY_BASIC_INFORMATION *info = reinterpret_cast<MEMORY_BASIC_INFORMATION *>(Buffer); + CriticalSection cs(objects_->critical_section()); + + VirtualObject *object = objects_->GetMap(ProcessHandle, info->AllocationBase); + if (object && (object->attributes() & SEC_IMAGE)) + info->Type = MEM_IMAGE; + } + return status; + } + + return TrueNtQueryVirtualMemory(ProcessHandle, BaseAddress, MemoryInformationClass, Buffer, Length, ResultLength); +} + +#endif // WIN_DRIVER
\ No newline at end of file |