Class: Indis::VMMap

Inherits:
Object
  • Object
show all
Defined in:
lib/indis-core/vmmap.rb

Overview

VMMap provides access to target’s virtaul memory address space

Instance Method Summary collapse

Constructor Details

#initialize(target) ⇒ VMMap

Returns a new instance of VMMap.



23
24
25
26
# File 'lib/indis-core/vmmap.rb', line 23

def initialize(target)
  @target = target
  @blocks = {}
end

Instance Method Details

#[](ofs) ⇒ Indis::Entity #[](range) ⇒ Array<Indis::Entity,nil,Fixnum>

Overloads:

  • #[](ofs) ⇒ Indis::Entity
    TODO:

    should also return one-byte

    Returns an entity at given address, same as #entity_at

    Parameters:

    • range (Fixnum)

      offset for entity

    Returns:

  • #[](range) ⇒ Array<Indis::Entity,nil,Fixnum>

    Returns a list of entities and bytes at given range. The resulting Array contains all bytes in range. For each entity it is mapped “as-is” and the following bytes up to Entity#size are filled with nil’s. For each unmapped byte it is returned as a Fixnum

    Parameters:

    • range (Range)

      range

    Returns:

    Raises:

    • (ArgumentError)

      if there is no segment at given range or the range spans several segments

Raises:

  • (ArgumentError)


115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/indis-core/vmmap.rb', line 115

def [](range)
  return entity_at(range) if range.is_a?(Fixnum)
  
  raise ArgumentError, "Unknown argument type #{range.class}" unless range.is_a?(Range)
  seg = segment_at(range.begin)
  raise ArgumentError, "No segment mapped at #{range.begin}" unless seg
  range_max = range.exclude_end? ? range.last-1 : range.last
  raise ArgumentError, "Segment #{seg} at #{range.begin}, but segment #{segment_at(range_max)} at #{range.end}" unless seg == segment_at(range_max)
  
  a = Array.new(range_max - range.begin + 1)
  ofs = range.begin
  range_begin = range.begin
  seg_vmaddr = seg.vmaddr
  
  begin
    b = @blocks[ofs]
    if b
      a[ofs-range_begin] = b
      ofs += b.size
    else
      a[ofs-range_begin] = seg.bytes[ofs-seg_vmaddr].ord
      ofs += 1
    end
  end while ofs <= range_max
  a
end

#address_valid?(ofs) ⇒ Boolean

Returns True if the address belongs to some segment.

Returns:

  • (Boolean)

    True if the address belongs to some segment



42
43
44
# File 'lib/indis-core/vmmap.rb', line 42

def address_valid?(ofs)
  segment_at(ofs) != nil
end

#byte_at(ofs) ⇒ Fixnum

Returns a byte value at given virtual address.

Returns:

  • (Fixnum)

    a byte value at given virtual address



47
48
49
50
51
52
53
54
55
# File 'lib/indis-core/vmmap.rb', line 47

def byte_at(ofs)
  seg = segment_at(ofs)
  return nil unless seg
  
  sect = section_at(ofs) # TODO: optimize here
  s = sect || seg
  
  s.bytes[ofs-s.vmaddr].ord
end

#bytes_at(ofs, size) ⇒ Array<Fixnum>

Returns a list of bytes at given virtual address span.

Returns:

  • (Array<Fixnum>)

    a list of bytes at given virtual address span



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/indis-core/vmmap.rb', line 58

def bytes_at(ofs, size)
  seg = segment_at(ofs)
  return nil unless seg
  
  sect = section_at(ofs) # TODO: optimize here
  s = sect || seg
  
  st = ofs-s.vmaddr
  ed = st + size
  s.bytes[st...ed].unpack('C*')
end

#entity_at(ofs) ⇒ Indis::Entity

Returns an entity mapped to given address.

Returns:



71
72
73
# File 'lib/indis-core/vmmap.rb', line 71

def entity_at(ofs)
  @blocks[ofs]
end

#has_unmapped(ofs, size) ⇒ Object

Returns True if the given range contains no entities.

Returns:

  • True if the given range contains no entities



76
77
78
79
# File 'lib/indis-core/vmmap.rb', line 76

def has_unmapped(ofs, size)
  size.times { |o| return false if entity_at(ofs+o) }
  true
end

#map(e) ⇒ Object

Maps an entity (based on its offset).

Raises:

  • (ArgumentError)

    if the range is occupied by another entity



83
84
85
86
# File 'lib/indis-core/vmmap.rb', line 83

def map(e)
  raise ArgumentError, "Tried to map #{e} at #{e.vmaddr}+#{e.size} on top of #{self[e.vmaddr...(e.vmaddr+e.size)]}" unless has_unmapped(e.vmaddr, e.size)
  @blocks[e.vmaddr] = e
end

#map!(e) ⇒ Object

Forcefully maps an entity (based on its offset) unmapping any other entities in the same address range



90
91
92
93
94
95
96
97
98
99
# File 'lib/indis-core/vmmap.rb', line 90

def map!(e)
  (e.vmaddr...(e.vmaddr+e.size)).each do |ofs|
    b = @blocks[ofs]
    if b
      b.unmap
      @blocks[ofs] = nil
    end
  end
  map(e)
end

#section_at(ofs) ⇒ Indis::Section

Returns a section at given address or nil.

Returns:



34
35
36
37
38
39
# File 'lib/indis-core/vmmap.rb', line 34

def section_at(ofs)
  seg = segment_at(ofs)
  return nil unless seg
  
  seg.sections.each.find { |s| (s.vmaddr...s.vmaddr+s.vmsize).include? ofs }
end

#segment_at(ofs) ⇒ Indis::Segment

Returns a segment at given address or nil.

Returns:



29
30
31
# File 'lib/indis-core/vmmap.rb', line 29

def segment_at(ofs)
  @target.segments.each.find { |s| (s.vmaddr...s.vmaddr+s.vmsize).include? ofs }
end