class MemoryIO::Process
Records information of a process.
Attributes
perm[R]
@api private @return [#readable?, writable?]
Public Class Methods
new(pid)
click to toggle source
@api private
Create process object from pid.
@param [Integer] pid
Process id.
@note
This class only supports procfs-based system. i.e. /proc is mounted and readable.
@todo
Support MacOS
@todo
Support Windows
# File lib/memory_io/process.rb, line 24 def initialize(pid) @pid = pid @mem = "/proc/#{pid}/mem" # check permission of '/proc/pid/mem' @perm = MemoryIO::Util.file_permission(@mem) # TODO: raise custom exception raise Errno::ENOENT, @mem if perm.nil? # FIXME: use logger warn(<<-EOS.strip) unless perm.readable? || perm.writable? You have no permission to read/write this process. Check the setting of /proc/sys/kernel/yama/ptrace_scope, or try again as the root user. To enable attach another process, do: $ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope EOS end
Public Instance Methods
bases()
click to toggle source
Parse /proc/[pid]/maps
to get all bases.
@return [{Symbol => Integer}]
Hash of bases.
@example
process = Process.new(`pidof victim`.to_i) puts process.bases.map { |key, val| format('%s: 0x%016x', key, val) } # vsyscall: 0xffffffffff600000 # vdso: 0x00007ffd5b565000 # vvar: 0x00007ffd5b563000 # stack: 0x00007ffd5ad21000 # ld: 0x00007f339a69b000 # libc: 0x00007f33996f1000 # heap: 0x00005571994a1000 # victim: 0x0000557198bcb000 #=> nil
# File lib/memory_io/process.rb, line 62 def bases file = "/proc/#{@pid}/maps" stat = MemoryIO::Util.file_permission(file) return {} unless stat&.readable? maps = ::IO.binread(file).split("\n").map do |line| # 7f76515cf000-7f76515da000 r-xp 00000000 fd:01 29360257 /lib/x86_64-linux-gnu/libnss_files-2.24.so addr, _perm, _offset, _dev, _inode, pathname = line.strip.split(' ', 6) next nil if pathname.nil? addr = addr.to_i(16) pathname = pathname[1..-2] if pathname =~ /^\[.+\]$/ pathname = ::File.basename(pathname) [MemoryIO::Util.trim_libname(pathname).to_sym, addr] end maps.compact.reverse.to_h end
read(addr, num_elements, **options)
click to toggle source
Read from process's memory.
This method has almost same arguements and return types as {IO#read}. The only difference is this method needs parameter addr
(which will be passed to paramter from
in {IO#read}).
@param [Integer, String] addr
The address start to read. When String is given, it will be safe-evaluated. You can use variables such as +'heap'/'stack'/'libc'+ in this parameter. See examples.
@param [Integer] num_elements
Number of elements to read. See {IO#read}.
@return [String, Object, Array<Object>]
See {IO#read}.
@example
process = MemoryIO.attach(`pidof victim`.to_i) puts process.read('heap', 4, as: :u64).map { |c| '0x%016x' % c } # 0x0000000000000000 # 0x0000000000000021 # 0x00000000deadbeef # 0x0000000000000000 #=> nil process.read('heap+0x10', 4, as: :u8).map { |c| '0x%x' % c } #=> ['0xef', '0xbe', '0xad', '0xde'] process.read('libc', 4) #=> "\x7fELF"
@see IO#read
# File lib/memory_io/process.rb, line 111 def read(addr, num_elements, **options) mem_io(:read) { |io| io.read(num_elements, from: MemoryIO::Util.safe_eval(addr, **bases), **options) } end
write(addr, objects, **options)
click to toggle source
Write objects at addr
.
This method has almost same arguments as {IO#write}.
@param [Integer, String] addr
The address to start to write. See examples.
@param [Object, Array<Object>] objects
Objects to write. If +objects+ is an array, the write procedure will be invoked +objects.size+ times.
@return [void]
@example
process = MemoryIO.attach('self') s = 'A' * 16 process.write(s.object_id * 2 + 16, 'BBBBCCCC') s #=> 'BBBBCCCCAAAAAAAA'
@see IO#write
# File lib/memory_io/process.rb, line 135 def write(addr, objects, **options) mem_io(:write) { |io| io.write(objects, from: MemoryIO::Util.safe_eval(addr, **bases), **options) } end
Private Instance Methods
mem_io(perm) { |io| ... }
click to toggle source
# File lib/memory_io/process.rb, line 141 def mem_io(perm) flags = perm == :write ? 'wb' : 'rb' File.open(@mem, flags) { |f| yield MemoryIO::IO.new(f) } end