#pragma once #include "../../Config.h" #include "RemoteContext.hpp" #include "../../Include/Winheaders.h" #include "../../Include/Macro.h" #include "../../Misc/Utils.h" #include "../Threads/Threads.h" #include #include #include namespace blackbone { class RemoteHook { public: // Hook type enum eHookType { int3 = 0, // Default int 3 breakpoint hwbp // Hardware breakpoint }; enum eHookFlags { none = 0, // No flags returnHook = 1, // Hook function return }; // Hook callback prototype using fnCallback = void( *)(RemoteContext& context); using fnClassCallback = void( __thiscall* )(const void* __this, RemoteContext& context); /// /// Hook descriptor /// struct HookData { // Callback pointer union callback { struct _classFn { fnClassCallback ptr; // Class member function pointer const void* classPtr; // Class instance }; fnCallback freeFn; // Free function pointer _classFn classFn; // Class member pointer }; callback onExecute; // Callback called upon address breakpoint callback onReturn; // Callback called upon function return eHookType type; // int 3 or HWBP eHookFlags flags; // Some hooking flags uint8_t oldByte; // Original byte in case of int 3 hook DWORD threadID; // Thread id for HWBP (0 means global hook for all threads) int hwbp_idx; // Index of HWBP if applied to one thread only _CONTEXT64 entryCtx; // Thread context on function entry (used in function return hook) }; using mapHook = std::map; using mapAddress = std::map; using setAddresses = std::map; public: BLACKBONE_API RemoteHook( class ProcessMemory& memory ); BLACKBONE_API ~RemoteHook(); /// /// Hook specified address /// /// Hook type /// Address /// Callback /// Thread to hook. Valid only for HWBP /// true on success BLACKBONE_API inline NTSTATUS Apply( eHookType type, uint64_t ptr, fnCallback newFn, ThreadPtr pThread = nullptr ) { return ApplyP( type, ptr, newFn, nullptr, pThread ); } /// /// Hook function return /// This hook will only work if function is hooked normally /// /// Hooked function address /// Callback /// true on success BLACKBONE_API inline NTSTATUS AddReturnHook( uint64_t ptr, fnCallback newFn ) { return AddReturnHookP( ptr, newFn, nullptr ); } // FIXME: Alternative for MinGW #ifdef COMPILER_MSVC /// /// Hook specified address /// /// /// Hook type /// Address /// Callback /// Class reference. /// Thread to hook. Valid only for HWBP /// true on success template inline NTSTATUS Apply( eHookType type, uint64_t ptr, void(C::* newFn)(RemoteContext& ctx), const C& classRef, ThreadPtr pThread = nullptr ) { return ApplyP( type, ptr, brutal_cast(newFn), &classRef, pThread ); } /// /// Hook function return /// This hook will only work if function is hooked normally /// /// Hooked function address /// Callback /// Class reference. /// true on success template inline NTSTATUS AddReturnHook( uint64_t ptr, void(C::* newFn)(RemoteContext& ctx), const C& classRef ) { return AddReturnHookP( ptr, brutal_cast(newFn), &classRef ); } #endif // COMPILER_MSVC /// /// Remove existing hook /// /// Hooked address BLACKBONE_API void Remove( uint64_t ptr ); /// /// Stop debug and remove all hooks /// BLACKBONE_API void reset(); private: /// /// Hook specified address /// /// Hook type /// Address /// Callback /// Class reference. /// Thread to hook. Valid only for HWBP /// true on success BLACKBONE_API NTSTATUS ApplyP( eHookType type, uint64_t ptr, fnCallback newFn, const void* pClass = nullptr, ThreadPtr pThread = nullptr ); /// /// Hook function return /// This hook will only work if function is hooked normally /// /// Hooked function address /// Callback /// Class reference. /// true on success BLACKBONE_API NTSTATUS AddReturnHookP( uint64_t ptr, fnCallback newFn, const void* pClass = nullptr ); /// /// Restore hooked function /// /// Hook data /// Hooked address BLACKBONE_API void Restore( const HookData &hook, uint64_t ptr ); /// /// Debug selected process /// /// true on success NTSTATUS EnsureDebug(); /// /// Stop process debug /// void EndDebug(); /// /// Wrapper for debug event thread /// /// RemoteHook pointer /// Error code static DWORD __stdcall EventThreadWrap( LPVOID lpParam ); /// /// Debug thread /// /// Error code DWORD EventThread(); /// /// Debug event handler /// /// Debug event data /// Status DWORD OnDebugEvent( const DEBUG_EVENT& DebugEv ); /// /// Int 3 handler /// /// Debug event data /// Status DWORD OnBreakpoint( const DEBUG_EVENT& DebugEv ); /// /// Trace and hardware breakpoints handler /// /// Debug event data /// Status DWORD OnSinglestep( const DEBUG_EVENT& DebugEv ); /// /// Access violation handler /// Used when hooking function return /// /// Debug event data /// Status DWORD OnAccessViolation( const DEBUG_EVENT& DebugEv ); /// /// Walk stack frames /// /// Thread instruction pointer /// >Thread stack pointer /// Stack owner /// Stack frames /// Max frame count /// Frame count DWORD StackBacktrace( ptr_t ip, ptr_t sp, Thread& thd, std::vector>& results, int depth = 100 ); RemoteHook( const RemoteHook& ) = delete; RemoteHook& operator =( const RemoteHook& ) = delete; private: class ProcessMemory& _memory; class ProcessCore& _core; CriticalSection _lock; // Hook lock DWORD _debugPID = 0; // PID of process being debugged HANDLE _hEventThd = NULL; // Debug Event thread BOOL _x64Target = FALSE; // Target is x64 process int _wordSize = 4; // 4 or 8 bytes bool _active = false; // Event thread activity flag mapHook _hooks; // Hooked callbacks setAddresses _repatch; // Pending repatch addresses mapAddress _retHooks; // Hooked return addresses }; ENUM_OPS( RemoteHook::eHookFlags ) }