Build Status Gem Version Maintainability Test Coverage Inline docs MIT License


Read/Write complicated structures in memory easily.


I usually need to dump a structure, say string in C++, from memory for debugging. This is not hard if using gdb. However, gdb doesn't support writing Ruby scripts (unless you use gdb-ruby, which has dependency of MemoryIO). So I create this repo and want to make the debug procedure much easier.

This repo has two main targets:

  1. To communiate with memory easily.
  2. To collect all common structures for debugging/learning.


It's not hard to read/write a process's memory (simply open the file /proc/$PID/mem), but it still worth to wrap it.

This repo also targets to collect all common structures, such as how to parse a C++/Rust/Python object from memory. Therefore, Pull Requests of adding new structures are welcome :D

Supported Platform

  • Linux
  • (TODO) Windows
  • (TODO) MacOS

Implemented Structures

Following is the list of supported structures. Each type has a full-name and an alias. For example,

require 'memory_io'

process = MemoryIO.attach(`pidof victim`.to_i)
# read a 64-bit unsigned integer, 1, as: 'basic/u64')
# is equivalent to, 1, as: :u64)

Goto the online document for more details of each type.


  • basic/u8: An unsigned 8-bit integer. Also known as: :u8
  • basic/u16: An unsigned 16-bit integer. Also known as: :u16
  • basic/u32: An unsigned 32-bit integer. Also known as: :u32
  • basic/u64: An unsigned 64-bit integer. Also known as: :u64
  • basic/s8: A signed 8-bit integer. Also known as: :s8
  • basic/s16: A signed 16-bit integer. Also known as: :s16
  • basic/s32: A signed 32-bit integer. Also known as: :s32
  • basic/s64: A signed 64-bit integer. Also known as: :s64
  • basic/float: IEEE-754 32-bit floating number. Also known as: :float
  • basic/double: IEEE-754 64-bit floating number. Also known as: :double


  • clang/c_str: A null-terminated string. Also known as: :c_str


  • cpp/string: The std::string class in C++11. Also known as: :string


Available on!

$ gem install memory_io


Read Process's Memory

require 'memory_io'

process = MemoryIO.attach(`pidof victim`.to_i)
puts'heap', 4, as: :u64).map { |c| '0x%016x' % c }
# 0x0000000000000000
# 0x0000000000000021
# 0x00000000deadbeef
# 0x0000000000000000
#=> nil'heap+0x10', 4, as: :u8).map { |c| '0x%x' % c }
#=> ['0xef', '0xbe', '0xad', '0xde']'libc', 4)
#=> "\x7fELF"

Write Process's Memory

require 'memory_io'

process = MemoryIO.attach('self') # Hack! Write memory of this process directly!
string = 'A' * 16
pos = string.object_id * 2 + 16, 16)

process.write(pos, 'memory_changed!!')
#=> 'memory_changed!!'

Customize Read

require 'memory_io'
process = MemoryIO.attach(`pidof victim`.to_i)

# An example that read a chunk of pt-malloc.
read_chunk = lambda do |stream|
  _prev_size =
  size = ('Q').first & -16) - 8
end'heap', 1, as: read_chunk)
#=> [24, "\xef\xbe\xad\xde\x00\x00...\x00"]

Define Own Structure

require 'memory_io'
process = MemoryIO.attach(`pidof victim`.to_i)

class MyType < MemoryIO::Types::Type

  # Define this if you need to 'write' to memory
  def self.write(stream, my_type)

  attr_accessor :val
  def initialize(val)
    @val = val

# Use snake-case symbol.'libc', 4, as: :my_type)
#=> [#<MyType @val="\x7F">,
# #<MyType @val="E">,
# #<MyType @val="L">,
# #<MyType @val="F">]

process.write('libc','MEOW'), as: :my_type)

# See if memory changed'libc', 4)
#=> 'MEOW'


To Add a New Structure