aboutsummaryrefslogtreecommitdiff
path: root/runtime/file_manager.cc
diff options
context:
space:
mode:
authorjmpoep <OriginalEntryPoint@qq.com>2023-12-07 16:51:07 +0800
committerjmpoep <OriginalEntryPoint@qq.com>2023-12-07 16:51:07 +0800
commit28008a746a31abb7909dd86cb0cd413ac8943b0b (patch)
treea30b74b8cad548048c3c1551d652828ab76fa9bd /runtime/file_manager.cc
downloadvmprotect-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
first commitHEADmaster
Diffstat (limited to 'runtime/file_manager.cc')
-rw-r--r--runtime/file_manager.cc1189
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 &registry_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