#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(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(InternalGetProcAddress(dll, VMProtectDecryptStringA("NtQueryObject"))); if (nt_query_object) { DWORD size = 0x800; OBJECT_NAME_INFORMATION *info = reinterpret_cast(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(data_); const OBJECT_ENTRY *entry_enc = reinterpret_cast(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(reinterpret_cast(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(str_enc[i] ^ (_rotl32(key_, static_cast(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(data_); const OBJECT_ENTRY *entry_enc = reinterpret_cast(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(reinterpret_cast(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(proc); res = register_server(); } else { typedef HRESULT (WINAPI tInstallServer)(BOOL, LPCWSTR); tInstallServer *install_server = reinterpret_cast(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(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(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(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(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(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(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(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(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(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(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(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(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(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(data_); for (size_t i = 0; i < file_name_list_.size(); i++) { if (object->ref() == reinterpret_cast(directory_enc + 1) + i) { file_name = file_name_list_[i].c_str(); break; } } } else { DWORD size = 0x800; OBJECT_NAME_INFORMATION *info = reinterpret_cast(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(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(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(instance_) + entry->OffsetToData; uint8_t *address = reinterpret_cast(dst); for (size_t p = 0; p < size; p++) { uint64_t i = offset + p; address[p] = source[i] ^ static_cast(_rotl32(key_, static_cast(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(base); if (!ReadFile(entry, 0, image_base, tmp_header.OptionalHeader.SizeOfHeaders)) return STATUS_INVALID_IMAGE_FORMAT; IMAGE_DOS_HEADER *dos_header = reinterpret_cast(image_base); IMAGE_NT_HEADERS *nt_header = reinterpret_cast(image_base + dos_header->e_lfanew); IMAGE_SECTION_HEADER *sections = reinterpret_cast(reinterpret_cast(&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(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 + 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(reloc + 1)[i]; uint8_t *address = image_base + reloc->VirtualAddress + (type_offset & 0xfff); switch (type_offset >> 12) { case IMAGE_REL_BASED_HIGHLOW: *(reinterpret_cast(address)) += static_cast(delta_base); break; case IMAGE_REL_BASED_HIGH: *(reinterpret_cast(address)) += static_cast(delta_base >> 16); break; case IMAGE_REL_BASED_LOW: *(reinterpret_cast(address)) += static_cast(delta_base); break; case IMAGE_REL_BASED_DIR64: *(reinterpret_cast(address)) += delta_base; break; } } processed += reloc->SizeOfBlock; } } nt_header->OptionalHeader.ImageBase = reinterpret_cast(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(nt_header.OptionalHeader.SizeOfStackCommit); info->StackReserved = static_cast(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(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(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(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(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