#pragma once #include "../Include/Winheaders.h" #include "../Include/Macro.h" #include "../Include/Types.h" #include "../Include/CallResult.h" #include #include namespace blackbone { /// /// Get rid of EXECUTABLE flag if DEP isn't enabled /// /// Memory protection flags /// DEP flag /// New protection flags inline DWORD CastProtection( DWORD prot, bool bDEP ) { if (bDEP == true) { return prot; } else { if (prot == PAGE_EXECUTE_READ) return PAGE_READONLY; else if (prot == PAGE_EXECUTE_READWRITE) return PAGE_READWRITE; else if (prot == PAGE_EXECUTE_WRITECOPY) return PAGE_WRITECOPY; else return prot; } } class MemBlock { public: class MemBlockImpl { friend class MemBlock; public: MemBlockImpl() = default; /// /// MemBlock_p ctor /// /// Process memory routines /// Memory address /// Block size /// Memory protection /// true if caller will be responsible for block deallocation MemBlockImpl( class ProcessMemory* mem, ptr_t ptr, size_t size, DWORD prot, bool own = true, bool physical = false ); ~MemBlockImpl() { if (_own) Free(); } /// /// Free memory /// /// Size of memory chunk to free. If 0 - whole block is freed NTSTATUS Free( size_t size = 0 ); private: ptr_t _ptr = 0; // Raw memory pointer size_t _size = 0; // Region size DWORD _protection = 0; // Region protection bool _own = true; // Memory will be freed in destructor bool _physical = false; // Memory allocated as direct physical class ProcessMemory* _memory; // Target process routines }; public: /// /// MemBlock ctor /// BLACKBONE_API MemBlock() = default; /// /// MemBlock ctor /// /// Process memory routines /// Memory address /// true if caller will be responsible for block deallocation BLACKBONE_API MemBlock( class ProcessMemory* mem, ptr_t ptr, bool own = true ); /// /// MemBlock ctor /// /// Process memory routines /// Memory address /// Block size /// Memory protection /// true if caller will be responsible for block deallocation BLACKBONE_API MemBlock( class ProcessMemory* mem, ptr_t ptr, size_t size, DWORD prot, bool own = true, bool physical = false ); /// /// Move ctor /// /// Move from BLACKBONE_API MemBlock( MemBlock&& rhs ) { _pImpl.swap( rhs._pImpl ); } BLACKBONE_API MemBlock& operator = ( MemBlock&& rhs ) { // Self assign if (_pImpl == rhs._pImpl) return *this; _pImpl.swap( rhs._pImpl ); return *this; } /// /// Allocate new memory block /// /// Process memory routines /// Block size /// Desired base address of new block /// Win32 Memory protection flags /// false if caller will be responsible for block deallocation /// Memory block. If failed - returned block will be invalid BLACKBONE_API static call_result_t Allocate( class ProcessMemory& process, size_t size, ptr_t desired = 0, DWORD protection = PAGE_EXECUTE_READWRITE, bool own = true ); /// /// Reallocate existing block for new size /// /// New block size /// Desired base address of new block /// Memory protection /// New block address BLACKBONE_API call_result_t Realloc( size_t size, ptr_t desired = 0, DWORD protection = PAGE_EXECUTE_READWRITE ); /// /// Change memory protection /// /// New protection flags /// Memory offset in block /// Block size /// Old protection flags /// Status BLACKBONE_API NTSTATUS Protect( DWORD protection, uintptr_t offset = 0, size_t size = 0, DWORD* pOld = nullptr ); /// /// Free memory /// /// Size of memory chunk to free. If 0 - whole block is freed BLACKBONE_API NTSTATUS Free( size_t size = 0 ); /// /// Read data /// /// Data offset in block /// Size of data to read /// Output buffer /// /// If true, function will try to read all committed pages in range ignoring uncommitted. /// Otherwise function will fail if there is at least one non-committed page in region. /// /// Status BLACKBONE_API NTSTATUS Read( uintptr_t offset, size_t size, PVOID pResult, bool handleHoles = false ); /// /// Write data /// /// Data offset in block /// Size of data to write /// Buffer to write /// Status BLACKBONE_API NTSTATUS Write( uintptr_t offset, size_t size, const void* pData ); /// /// Read data /// /// Data offset in block /// Defult return value if read has failed /// Read data template T Read( uintptr_t offset, const T& def_val ) { T res = def_val; Read( offset, sizeof( T ), &res ); return res; } /// /// Read data /// /// Data offset in block /// Read data /// Status code template NTSTATUS Read( size_t offset, T& val ) { return Read( offset, sizeof( val ), &val ); } /// /// Write data /// /// Offset in block /// Data to write /// Status template NTSTATUS Write( uintptr_t offset, const T& data ) { return Write( offset, sizeof( data ), &data ); } /// /// Try to free memory and reset pointers /// BLACKBONE_API void Reset(); /// /// Memory will not be deallocated upon object destruction /// BLACKBONE_API inline void Release() { if (_pImpl) _pImpl->_own = false; } /// /// Get memory pointer /// /// Memory pointer template inline T ptr() const { return _pImpl ? (T)_pImpl->_ptr : T( 0 ); } /// /// Get block size /// /// Block size BLACKBONE_API inline size_t size() const { return _pImpl ? _pImpl->_size : 0; } /// /// Get block memory protection /// /// Memory protection flags BLACKBONE_API inline DWORD protection() const { return _pImpl ? _pImpl->_protection : 0; } /// /// Validate memory block /// true if memory pointer isn't 0 BLACKBONE_API inline bool valid() const { return( _pImpl.get() != nullptr && _pImpl->_ptr != 0); } /// /// Get memory pointer /// /// Memory pointer BLACKBONE_API inline operator ptr_t() const { return _pImpl ? _pImpl->_ptr : 0; } private: std::shared_ptr _pImpl; }; }