Module: OneGadget::Emulators::TrackedMemory
- Included in:
- Processor
- Defined in:
- lib/one_gadget/emulators/tracked_memory.rb
Overview
The memory a candidate reads and writes. Every store is filed under the base its address is an offset from -- the stack pointer, the frame pointer, or any register holding a pointer the caller supplies -- so a later load of the same slot reads back what this candidate put there, and a load of an untouched one is answered as what the caller left. Mixed into Processor.
Instance Method Summary collapse
-
#bp_based_stack ⇒ Hash{Integer => Lambda}?
Memory written through Processor#bp, or nil when the arch has none.
-
#get_corresponding_stack(base) ⇒ Hash{Integer => Lambda}?
The memory
baseaddresses: what this candidate has written through it, keyed by offset. -
#resolve_address(address) ⇒ (Hash{Integer => Lambda}?, Integer)
Where
addresslands in the memory this emulator tracks: the stack it falls in and its offset within it. -
#setup_frame_pointer(bp) ⇒ void
Enable frame-pointer stack tracking with
bpas the frame register, so a gadget staging data at +[bp+imm]+ (e.g. an argv array off the frame pointer) is recovered instead of collapsing to a barewritable:. -
#sp_based_stack ⇒ Hash{Integer => OneGadget::Emulators::Lambda}
Memory written through
sp. -
#writes_through(text) ⇒ Array<String>
The values this candidate wrote through an address built from
text, which the array reported attexttherefore holds -- wherever in it they landed.
Instance Method Details
#bp_based_stack ⇒ Hash{Integer => Lambda}?
Returns Memory written through Processor#bp, or nil when the arch has none.
17 |
# File 'lib/one_gadget/emulators/tracked_memory.rb', line 17 def bp_based_stack = bp && get_corresponding_stack(bp) |
#get_corresponding_stack(base) ⇒ Hash{Integer => Lambda}?
The memory base addresses: what this candidate has written through it,
keyed by offset. Every base gets one -- the stack pointer, the frame
pointer, any other register, and a value no register names at all (a
pointer the candidate derived and then built an array through).
Keyed by how the base renders, which is what makes one store enough: a register that gets reassigned addresses somewhere else and renders differently, so it lands on a different key without any invalidation to arrange. Only a store overwriting what the base itself reads from would break that, which a candidate short enough to be a gadget doesn't do.
60 61 62 63 64 |
# File 'lib/one_gadget/emulators/tracked_memory.rb', line 60 def get_corresponding_stack(base) return nil unless base.is_a?(OneGadget::Emulators::Lambda) || registers.key?(base.to_s) tracked_memory[base.to_s] end |
#resolve_address(address) ⇒ (Hash{Integer => Lambda}?, Integer)
Where address lands in the memory this emulator tracks: the stack it
falls in and its offset within it. A load or store passes the address it
dereferences, i.e. its operand with that dereference peeled off.
39 40 41 42 |
# File 'lib/one_gadget/emulators/tracked_memory.rb', line 39 def resolve_address(address) base, offset = address_base(address) [get_corresponding_stack(base), offset] end |
#setup_frame_pointer(bp) ⇒ void
This method returns an undefined value.
Enable frame-pointer stack tracking with bp as the frame register, so a
gadget staging data at +[bp+imm]+ (e.g. an argv array off the frame
pointer) is recovered instead of collapsing to a bare writable:. A nil
bp leaves the arch +sp+-only. Call from the arch initializer after super.
25 26 27 |
# File 'lib/one_gadget/emulators/tracked_memory.rb', line 25 def setup_frame_pointer(bp) @bp = bp end |
#sp_based_stack ⇒ Hash{Integer => OneGadget::Emulators::Lambda}
Returns Memory written through sp.
14 |
# File 'lib/one_gadget/emulators/tracked_memory.rb', line 14 def sp_based_stack = get_corresponding_stack(sp) |
#writes_through(text) ⇒ Array<String>
The values this candidate wrote through an address built from text, which
the array reported at text therefore holds -- wherever in it they landed.
A reader told about that array has to be told about these too, or it is
described as though the gadget had not written to it.
74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/one_gadget/emulators/tracked_memory.rb', line 74 def writes_through(text) return [] if text.empty? derived_writes.filter_map do |base, values| next unless operands_of(base).any? { |operand| operand.to_s == text } # A literal is not the caller's to arrange -- it is already what it is, # and the NULL such a loop writes to terminate the array is one. values.grep_v(Integer).map(&:to_s) end.flatten.uniq end |