// DynLibUtils // Copyright (C) 2023 komashchenko (Phoenix) // https://github.com/komashchenko/DynLibUtils #ifndef DYNLIBUTILS_MEMADDR_H #define DYNLIBUTILS_MEMADDR_H #ifdef _WIN32 #pragma once #endif #include #include #include namespace DynLibUtils { class CMemory { public: CMemory() : m_ptr(0) {} CMemory(const CMemory&) noexcept = default; CMemory& operator= (const CMemory&) noexcept = default; CMemory(CMemory&& other) noexcept : m_ptr(std::exchange(other.m_ptr, 0)) {} CMemory(const uintptr_t ptr) : m_ptr(ptr) {} CMemory(const void* ptr) : m_ptr(reinterpret_cast(ptr)) {} inline operator uintptr_t() const noexcept { return m_ptr; } inline operator void*() const noexcept { return reinterpret_cast(m_ptr); } explicit inline operator bool() const noexcept { return m_ptr != 0; } inline bool operator!= (const CMemory& addr) const noexcept { return m_ptr != addr.m_ptr; } inline bool operator== (const CMemory& addr) const noexcept { return m_ptr == addr.m_ptr; } inline bool operator== (const uintptr_t& addr) const noexcept { return m_ptr == addr; } [[nodiscard]] inline uintptr_t GetPtr() const noexcept { return m_ptr; } template [[nodiscard]] inline T GetValue() const noexcept { return *reinterpret_cast(m_ptr); } template [[nodiscard]] inline T CCast() const noexcept { return (T)m_ptr; } template [[nodiscard]] inline T RCast() const noexcept { return reinterpret_cast(m_ptr); } template [[nodiscard]] inline T UCast() const noexcept { union { uintptr_t m_ptr; T cptr; } cast; return cast.m_ptr = m_ptr, cast.cptr; } [[nodiscard]] inline CMemory Offset(ptrdiff_t offset) const noexcept { return m_ptr + offset; } inline CMemory& OffsetSelf(ptrdiff_t offset) noexcept { m_ptr += offset; return *this; } [[nodiscard]] inline CMemory Deref(int deref = 1) const { uintptr_t reference = m_ptr; while (deref--) { if (reference) reference = *reinterpret_cast(reference); } return reference; } inline CMemory& DerefSelf(int deref = 1) { while (deref--) { if (m_ptr) m_ptr = *reinterpret_cast(m_ptr); } return *this; } [[nodiscard]] inline CMemory FollowNearCall(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5) const { return ResolveRelativeAddress(opcodeOffset, nextInstructionOffset); } inline CMemory& FollowNearCallSelf(const ptrdiff_t opcodeOffset = 0x1, const ptrdiff_t nextInstructionOffset = 0x5) { return ResolveRelativeAddressSelf(opcodeOffset, nextInstructionOffset); } [[nodiscard]] inline CMemory ResolveRelativeAddress(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4) const { const uintptr_t skipRegister = m_ptr + registerOffset; const int32_t relativeAddress = *reinterpret_cast(skipRegister); const uintptr_t nextInstruction = m_ptr + nextInstructionOffset; return nextInstruction + relativeAddress; } inline CMemory& ResolveRelativeAddressSelf(const ptrdiff_t registerOffset = 0x0, const ptrdiff_t nextInstructionOffset = 0x4) { const uintptr_t skipRegister = m_ptr + registerOffset; const int32_t relativeAddress = *reinterpret_cast(skipRegister); const uintptr_t nextInstruction = m_ptr + nextInstructionOffset; m_ptr = nextInstruction + relativeAddress; return *this; } private: uintptr_t m_ptr; }; } // namespace DynLibUtils #endif // DYNLIBUTILS_MEMADDR_H