Class: ASMREPL::REPL
Constant Summary collapse
- CFuncs =
Linux
Constants included from Fiddle
Instance Method Summary collapse
- #bold(string) ⇒ Object
- #display_state(state) ⇒ Object
- #display_state_change(last_state, state) ⇒ Object
-
#initialize ⇒ REPL
constructor
A new instance of REPL.
- #start ⇒ Object
Constructor Details
#initialize ⇒ REPL
Returns a new instance of REPL.
23 24 25 26 27 28 29 |
# File 'lib/asmrepl/repl.rb', line 23 def initialize size = 1024 * 16 # 16k is enough for anyone! @buffer = CFuncs.jitbuffer(size) CFuncs.memset(@buffer.memory, 0xCC, size) @parser = ASMREPL::Parser.new @assembler = ASMREPL::Assembler.new end |
Instance Method Details
#bold(string) ⇒ Object
62 63 64 |
# File 'lib/asmrepl/repl.rb', line 62 def bold string "\e[1m#{string}\e[0m" end |
#display_state(state) ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/asmrepl/repl.rb', line 31 def display_state state puts bold(" CPU STATE ".center(48, "=")) puts state puts puts "FLAGS: #{state.flags.inspect}" puts end |
#display_state_change(last_state, state) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/asmrepl/repl.rb', line 39 def display_state_change last_state, state puts bold(" REGISTER CHANGES ".center(48, "=")) show_flags = false state.fields.each do |field| next if field == "rip" if last_state[field] != state[field] print "#{field.ljust(6)} " print sprintf("%#018x", last_state[field] & MAXINT) print " => " puts bold(sprintf("%#018x", state[field] & MAXINT)) end end if last_state.flags != state.flags puts puts "FLAGS: #{state.flags.inspect}" end puts end |
#start ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/asmrepl/repl.rb', line 66 def start pid = fork { CFuncs.traceme @buffer.to_function([], TYPE_INT).call } tracer = CFuncs::Tracer.new pid should_cpu = true last_state = nil while tracer.wait state = tracer.state # Show CPU state once on boot if last_state.nil? display_state state last_state = state else display_state_change last_state, state last_state = state end use_history = true begin loop do cmd = nil prompt = sprintf("(rip %#018x)> ", state.rip) text = Reline.readmultiline(prompt, use_history) do |multiline_input| case multiline_input when /\Adisasm\Z/ cmd = :disasm when /\A\s*(\w+)\s*\Z/ register = $1 cmd = [:read, register] when /\A\s*(\w+)\s*=\s*(\d+)\Z/ register = $1 cmd = [:write, register, $2.to_i] else cmd = :run end true end case cmd in :disasm # disassembles the JIT buffer. This is just for development, # I don't want to make a hard dependency on crabstone right now. # If you want to use this, install crabstone begin require "asmrepl/disasm" ASMREPL::Disasm.disasm @buffer rescue end in :run break if text.chomp.empty? begin parser_result = @parser.parse text.chomp rescue puts "Invalid intruction" next end begin binary = @assembler.assemble parser_result # Move the JIT buffer to the current instruction pointer, but # rewind RIP so that we write over the int3 pos = (state.rip - @buffer.memory.to_i - 1) @buffer.seek pos binary.bytes.each { |byte| @buffer.putc byte } state.rip -= 1 tracer.state = state rescue Fisk::Errors::InvalidInstructionError => e # Print an error message when the instruction is invalid puts e. next end break in [:write, reg, val] state[reg] = val tracer.state = state in [:read, "cpu"] display_state state in [:read, reg] val = state[reg] if val puts sprintf("%#018x", state[reg]) else puts "Unknown command: " puts " " + text end else end end rescue Interrupt puts "" exit 0 end tracer.continue end end |