#pragma once #include "../../Config.h" #include "../../DriverControl/DriverControl.h" #include #include namespace blackbone { class RemoteMemory { public: #ifdef USE64 struct HookData { uint8_t original_code[24]; // Original 5 bytes + jmp uint8_t jump_buf[12]; // Trampoline uint8_t hook_code[384]; // Hook function }; #else struct HookData { uint8_t original_code[10]; // Original 5 bytes + jmp uint8_t jump_buf[5]; // Trampoline uint8_t hook_code[384]; // Hook function }; #endif enum OperationType { MemVirtualAlloc = 0, // MemVirtualAlloc MemVirtualFree, // MemVirtualFree MemMapSection, // MemMapSection MemUnmapSection, // MemUnmapSection }; struct OperationData { ptr_t allocAddress; // Allocated region base uint32_t allocSize; // Allocated region size OperationType allocType; // Operation type }; struct PageContext { HookData hkVirtualAlloc; // NtAllocateVirtualMemory context HookData hkVirtualFree; // NtFreeVirtualMemory context HookData hkMapSection; // NtMapViewOfSection context HookData hkUnmapSection; // NtUnmapViewOfSection context CRITICAL_SECTION csLock; // Lock to sync multi-threaded mappings }; public: BLACKBONE_API RemoteMemory( class Process* process ); BLACKBONE_API ~RemoteMemory(); /// /// Map entire process address space /// /// Set to true to map section objects. They are converted to private pages before locking /// Status code BLACKBONE_API NTSTATUS Map( bool mapSections ); /// /// Map specific memory region /// /// Region base /// Region size /// Status code BLACKBONE_API NTSTATUS Map( ptr_t base, uint32_t size ); /// /// Unmap process address space from current process /// /// Status code BLACKBONE_API NTSTATUS Unmap(); /// /// Unmap specific memory region from current process /// /// Region base /// Region size /// Status code BLACKBONE_API NTSTATUS Unmap( ptr_t base, uint32_t size ); /// /// Translate target address accordingly to current address space /// /// Address to translate /// If set to true, routine will try to map non-existing region upon translation failure /// Translated address BLACKBONE_API ptr_t TranslateAddress( ptr_t address, bool resolveFault = true ); /// /// Setup one of the 4 possible memory hooks: /// /// /// Type of hook to install /// MemVirtualAlloc - hook NtAllocateVirtualMemory /// MemVirtualFree - hook NtFreeVirtualMemory /// MemMapSection - hook NtMapViewOfSection /// MemUnmapSection - hook NtUnmapViewOfSection /// /// true on success BLACKBONE_API NTSTATUS SetupHook( OperationType hkType ); /// /// Restore previously hooked function /// /// Hook type. For more info see SetupHook /// true on success BLACKBONE_API bool RestoreHook( OperationType hkType ); /// /// Unmap any mapped memory, restore hooks and free resources /// BLACKBONE_API void reset(); private: /// /// Hook thread wrapper /// /// RemoteMemory instance /// 0 static DWORD CALLBACK HookThreadWrap( LPVOID lpParam ); /// /// Thread responsible for mapping and unmapping regions intercepted by remote hooks /// void HookThread(); /// /// Build remote hook function /// /// Hooked function void BuildGenericHookFn( OperationType opType ); /// /// Build hook trampoline /// /// Hooked function type /// Original function ptr /// Original function address in local address space void BuildTrampoline( OperationType opType, uintptr_t pOriginal, uint8_t* pOriginalLocal ); private: class Process* _process = nullptr; // Target process mapMemoryMap _mapDatabase; // Region map std::wstring _pipeName; // Pipe name used to gather hook data Handle _hPipe; // Hook pipe handle HANDLE _targetPipe = NULL; // Hook pipe handle in target process HANDLE _hThread = NULL; // Hook thread listener PageContext* _pSharedData = nullptr; // Hook related data, shared between processes ptr_t _targetShare = 0; // Address of shared in data in target process bool _active = false; // Hook thread activity flag bool _hooked[4] = { 0 }; // Hook state }; }