#pragma once #include "../ProcessCore.h" #include "../ProcessMemory.h" #include "../Threads/Thread.h" #include "../../Include/Macro.h" namespace blackbone { /// /// Remote function context during hook breakpoint. /// class RemoteContext { public: BLACKBONE_API RemoteContext( ProcessMemory& memory, Thread& thd, _CONTEXT64& ctx, ptr_t frame_ptr, BOOL x64, int wordSize ) : _memory( memory ) , _thd( thd ) , _ctx( ctx ) , _x64Target( x64 ) , _wordSize( wordSize ) , _frame_ptr( frame_ptr != 0 ? frame_ptr : ctx.Rsp ) { } BLACKBONE_API ~RemoteContext() { } // Native context BLACKBONE_API inline _CONTEXT64& native() { return _ctx; } /// /// Get current process thread where exception occurred /// /// Thread BLACKBONE_API inline Thread& getThread() { return _thd; } /// /// /// /// Return address BLACKBONE_API inline const ptr_t returnAddress() const { ptr_t val = 0; _memory.Read( _frame_ptr, _wordSize, &val ); return val; } /// /// Set return address of current frame /// /// New return address /// true on success BLACKBONE_API inline bool returnAddress( ptr_t val ) const { return (_memory.Write( _frame_ptr, _wordSize, &val ) == STATUS_SUCCESS); } /// /// Set new integer return value. Has no effect on FPU. /// Has effect only if called in return callback /// /// New return value BLACKBONE_API inline void setReturnValue( ptr_t val ) const { memcpy( &_ctx.Rax, &val, _wordSize ); } /// /// Raise exception on function return /// /// Masked return address BLACKBONE_API ptr_t hookReturn() { ptr_t val = returnAddress(); SET_BIT( val, (_wordSize * 8 - 1) ); if (returnAddress( val ) == false) return 0; return val; } /// /// Remove exception on return /// /// Return address BLACKBONE_API ptr_t unhookReturn() { auto val = returnAddress(); RESET_BIT( val, (_wordSize * 8 - 1) ); if (!returnAddress( val )) return 0; return val; } /// /// Get argument value. /// Argument index is 0 based. /// For x86 function works only with stack arguments /// For x64 only integer arguments can be retrieved /// /// 0-based argument index /// Argument value BLACKBONE_API DWORD64 getArg( int index ) { if(_x64Target) { switch (index) { case 0: return _ctx.Rcx; case 1: return _ctx.Rdx; case 2: return _ctx.R8; case 3: return _ctx.R9; default: return _memory.Read( _ctx.Rsp + 0x28 + (index - 4) * _wordSize ).result( 0 ); } } else { DWORD64 val = 0; _memory.Read( _ctx.Rsp + 4 + index * _wordSize, _wordSize, &val ); return val; } } /// /// Set argument value. /// For x86 function works only with stack arguments. /// For x64 only integer arguments can be set /// /// 0-based argument index /// New argument value /// true on success BLACKBONE_API bool setArg( int index, DWORD64 val ) { if (_x64Target) { switch (index) { case 0: _ctx.Rcx = val; break; case 1: _ctx.Rdx = val; break; case 2: _ctx.R8 = val; break; case 3: _ctx.R9 = val; break; default: return (_memory.Write( _ctx.Rsp + 0x28 + (index - 4) * _wordSize, val ) == STATUS_SUCCESS); } return true; } else { return (_memory.Write( _ctx.Rsp + 4 + index * _wordSize, _wordSize, &val ) == STATUS_SUCCESS); } } /// /// Get last thread error code /// /// Last error code, -1 if function failed BLACKBONE_API DWORD lastError() { ptr_t pteb = 0; LONG offset = 0; if( _x64Target ) { pteb = _thd.teb( (_TEB64*)nullptr ); offset = FIELD_OFFSET( _TEB64, LastErrorValue ); } else { pteb = _thd.teb( (_TEB32*)nullptr ); offset = FIELD_OFFSET( _TEB32, LastErrorValue ); } if (pteb) return _memory.Read( pteb + offset ).result( 0xFFFFFFFF ); return 0xFFFFFFFF; } /// /// Set last thread error code /// /// Last error code, -1 if function failed BLACKBONE_API DWORD lastError( DWORD newError ) { ptr_t pteb = 0; LONG offset = 0; if (_x64Target) { pteb = _thd.teb( (_TEB64*)nullptr ); offset = FIELD_OFFSET( _TEB64, LastErrorValue ); } else { pteb = _thd.teb( (_TEB32*)nullptr ); offset = FIELD_OFFSET( _TEB32, LastErrorValue ); } if (!pteb) return 0xFFFFFFFF; return _memory.Write( pteb + offset, newError ); } /// /// Get arbitrary thread data /// /// Data value BLACKBONE_API ptr_t getUserContext() { auto pteb = _thd.teb( (_TEB64*)nullptr ); if (!pteb) return 0; return _memory.Read( pteb + FIELD_OFFSET( _NT_TIB_T, ArbitraryUserPointer ) ).result( 0 ); } /// /// Set arbitrary thread data /// /// true on success BLACKBONE_API bool setUserContext( ptr_t context ) { auto pteb = _thd.teb( (_TEB64*)nullptr ); if(pteb) { if (_memory.Write( pteb + FIELD_OFFSET( _NT_TIB_T, ArbitraryUserPointer ), context ) == STATUS_SUCCESS) return true; } return false; } private: RemoteContext( const RemoteContext& ) = delete; RemoteContext& operator = ( const RemoteContext& ) = delete; private: ProcessMemory& _memory; // Process memory routines Thread& _thd; // Current thread _CONTEXT64& _ctx; // Current thread context BOOL _x64Target = FALSE; // Target process is 64 bit int _wordSize = 4; // 4 for x86, 8 for x64 ptr_t _frame_ptr = 0; // Top stack frame pointer }; }