Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Learn C++ Hex Editing for Save Data and Memory Editing

Newbie Spellweaver
Joined
Dec 27, 2022
Messages
14
Reaction score
3
I'm really just interested in writing programs for editing save data on emulators, but I'm sure this could help others who might be interested in larger scale memory editing, so I'd like to ask this in a more broad way.

Bonus question: What about resources on live editing memory as well, like cheatengine or scanmem?
 
Joined
Apr 3, 2011
Messages
2
Reaction score
2
Hi, it's as simple as it is in C++:

Code:
1. Open file: fstream::open (use the binary flag)
2. Set the put pointer position: fstream::seekp (to the memory address for e.g. 0x08)
3. Write data at the put pointer position: fstream::put
4. Close file: fstream::close
 
Junior Spellweaver
Joined
Oct 27, 2008
Messages
165
Reaction score
89
Serialization, the example below is in c#:


And this is in C++:
Code:
    class IWriter // @suppress("Class has a virtual method and non-virtual destructor")
    {
    public:
        virtual void Write(const void* buffer, const int& nSize) = 0;

    public:
        virtual void Write(const int8_t& i8) = 0;
        virtual void Write(const int16_t& i16) = 0;
        virtual void Write(const int32_t& i32) = 0;
        virtual void Write(const int64_t& i64) = 0;
        virtual void Write(const uint8_t& u8) = 0;
        virtual void Write(const uint16_t& u16) = 0;
        virtual void Write(const uint32_t& u32) = 0;
        virtual void Write(const CGuid& guid) = 0;
        virtual void Write(const std::string& str) = 0;
        virtual void Write(const std::wstring& str) = 0;
        virtual void Write(const bool& b) = 0;
        virtual void Write(const float& f) = 0;
        virtual void Write(const double& d) = 0;

    };

    class IReader // @suppress("Class has a virtual method and non-virtual destructor")
    {
    public:
        virtual void Read(void* buffer, const int& nSize) = 0;

    public:
        virtual int8_t ReadInt8(void) = 0;
        virtual int16_t ReadInt16(void) = 0;
        virtual int32_t ReadInt32(void)= 0;
        virtual int64_t ReadInt64(void)= 0;
        virtual uint8_t ReadUInt8(void)= 0;
        virtual uint16_t ReadUInt16(void)= 0;
        virtual uint32_t ReadUInt32(void)= 0;
        virtual uint64_t ReadUInt64(void)= 0;

        virtual std::string ReadString(void)= 0;
        virtual std::wstring ReadWString(void)= 0;
        virtual CGuid ReadGuid(void)= 0;
        virtual bool ReadBool(void)= 0;
        virtual float ReadSingle(void)= 0;
        virtual double ReadDouble(void)= 0;
    };

 class ISerializable // @suppress("Class has a virtual method and non-virtual destructor")
    {
    public:
        virtual void Serialize(IWriter* writer) = 0;
        virtual int Deserialize(IReader* reader ) = 0;
    };


And the implementation(the example below deserializes openstreetmap nodes):
Code:
class CNode : public ISerializable
    {
        protected:
            int  m_nVersion = 1;
            unsigned long long  m_nIndex = -1;
            double              m_dLatitude = -1;
            double              m_dLongitude = -1;
            bool                m_bVisible = false;
            std::list<CTag*>    m_tags;


        public:
            CNode(void);
            virtual ~CNode(void);

        public:
            inline unsigned long long Index(void) { return m_nIndex; }
            inline double Latitude(void) { return m_dLatitude; }
            inline double Longitude(void) { return m_dLongitude; }
            inline bool Visible(void) { return m_bVisible; }
            inline std::list<CTag*> Tags(void) { return m_tags; }

        public:
            inline void Index(unsigned long long value) { m_nIndex = value; }
            inline void Latitude(double value) { m_dLatitude = value; }
            inline void Longitude(double value) { m_dLongitude = value; }
            inline void Visible(bool value) { m_bVisible = value; }
            inline void Tags(std::list<CTag*>& value) { m_tags = value; }

        public:
            void Serialize(IWriter& writer);
        void Deserialize(IReader& reader);
    };

void CNode::Serialize(IWriter& writer)
{
    writer.Write(m_nVersion);
    writer.Write(m_nIndex);
    writer.Write(m_dLatitude);
    writer.Write(m_dLongitude);
    writer.Write(m_bVisible);

    // tags
    stream.WriteUInt8(static_cast<unsigned char>(m_tags.size()));
    for(std::list<CTag*>::iterator it  = m_tags.begin(); it != m_tags.end(); it++)
    {
        CTag* tag = *it;
        tag->Serialize(writer);
    }
}

int CNode::Deserialize(IReader& reader)
{
   int nVersion = reader.ReadUInt32();
   switch(nVersion)
   {
       case 1:   {
    m_nIndex = reader.ReadUInt64();
    m_dLatitude = reader.ReadDouble();
    m_dLongitude = reader.ReadDouble();
    m_bVisible = reader.ReadBool();

    // tags
    int nSize = reader.ReadUInt8();
    for(int nIndex = 0; nIndex < nSize; nIndex++)
    {
        CTag* tag = new CTag();
        tag->Deserialize(reader);

        m_tags.push_back(tag);
    }
     }
      break;
}

     return nVersion;
}

For memory editing you have to access the process memory, you will also need to know knowledge about memory segmentation, and how to calculate the memory offsets to change values.
 
Last edited:
Newbie Spellweaver
Joined
Dec 27, 2022
Messages
14
Reaction score
3
Thank you both for the answers.

I had found a way to both read using <fstream>, but it took me a little bit of reading through documentation to figure out that I need to use .write() to properly write to the file.

Just as a side note, what I've been working with requires a checksum, so if anyone is reading this in the future: Be weary of the checksum!
 
Back
Top