metasm/gui/dasm_main.rb in metasm-1.0.3 vs metasm/gui/dasm_main.rb in metasm-1.0.4
- old
+ new
@@ -58,10 +58,14 @@
addview :coverage, CoverageWidget.new(@dasm, self)
addview :funcgraph, FuncGraphViewWidget.new(@dasm, self)
addview :cstruct, CStructWidget.new(@dasm, self)
view(:listing).grab_focus
+
+ if ENV['METASM_DASM_PLUGINS']
+ ENV['METASM_DASM_PLUGINS'].split(',').each { |p| @dasm.load_plugin p }
+ end
end
attr_reader :dasm
# when updating @dasm, also update dasm for all views
def dasm=(d)
@@ -108,11 +112,11 @@
curview.current_address
end
# returns the object under the cursor in current view (@dasm.decoded[curaddr])
def curobj
- @dasm.decoded[curaddr]
+ curview.respond_to?(:curobj) ? curview.curobj : @dasm.decoded[curaddr]
end
# returns the address of the label under the cursor or the address of the line of the cursor
def pointed_addr
hl = curview.hl_word
@@ -244,11 +248,12 @@
# calls listwindow with the same argument, but also creates a new bg_color_callback
# that will color lines whose address is to be found in list[0] in green
# the callback is put only for the duration of the listwindow, and is not reentrant.
def list_bghilight(title, list, a={}, &b)
prev_colorcb = bg_color_callback
- hash = list[1..-1].inject({}) { |h, l| h.update Expression[l[0] || :unknown].reduce => true }
+ addr_idx = a.delete(:bghilight_index) || 0
+ hash = list[1..-1].inject({}) { |h, l| h.update Expression[l[addr_idx] || :unknown].reduce => true }
@bg_color_callback = lambda { |addr| hash[addr] ? '0f0' : prev_colorcb ? prev_colorcb[addr] : nil }
redraw
popupend = lambda { @bg_color_callback = prev_colorcb ; redraw }
listwindow(title, list, a.merge(:ondestroy => popupend), &b)
end
@@ -285,13 +290,13 @@
t = @dasm.normalize t
next if not @dasm.decoded[t]
@dasm.function[t] ||= @dasm.function[:default] ? @dasm.function[:default].dup : DecodedFunction.new
}
di.block.add_to_subfuncret(di.next_addr)
- @dasm.addrs_todo << [di.next_addr, addr, true]
+ @dasm.addrs_todo << { :addr => di.next_addr, :from => addr, :from_subfuncret => true }
elsif addr
- @dasm.addrs_todo << [addr]
+ @entrypoints << addr
end
start_disassemble_bg
end
# disassemble fast from this point (don't dasm subfunctions, don't backtrace)
@@ -311,11 +316,11 @@
# (re)decompile
def decompile(addr)
session_append "decompile(#{addr.inspect})"
if @dasm.c_parser and var = @dasm.c_parser.toplevel.symbol[addr] and (var.type.kind_of? C::Function or @dasm.di_at(addr))
@dasm.decompiler.redecompile(addr)
- view(:decompile).curaddr = nil
+ view(:decompile).curfuncaddr = nil
end
focus_addr(addr, :decompile)
end
# change the format of displayed data under addr (byte, word, dword, qword)
@@ -417,31 +422,35 @@
}
expr = expr.bind(bd).reduce { |e_| e_.len ||= @dasm.cpu.size/8 if e_.kind_of? Indirection ; nil }
log = []
dasm.backtrace(expr, addr, :log => log)
- list = [['address', 'type', 'old value', 'value']]
+ list = [['order', 'address', 'type', 'old value', 'value']]
+ order = 0
log.each { |t, *a|
- list << [Expression[a[-1]], t]
+ order += 1
+ list << [('%03d' % order), Expression[a[-1]], t] rescue next
case t
when :start
list.last << a[0]
when :up
+ order -= 1
list.pop
when :di
+ list.last[-1] = "di #{@dasm.di_at(a[-1]).instruction rescue nil}"
list.last << a[1] << a[0]
when :func
list.last << a[1] << a[0]
when :found
list.pop
- a[0].each { |e_| list << [nil, :found, Expression[e_]] }
+ a[0].each { |e_| list << [('%03d' % (order += 1)), nil, :found, Expression[e_]] }
else
list.last << a[0] << a[1..-1].inspect
end
}
- list_bghilight("backtrace #{expr} from #{Expression[addr]}", list) { |i|
- a = i[0].empty? ? i[2] : i[0]
+ list_bghilight("backtrace #{expr} from #{Expression[addr]}", list, :bghilight_index => 1) { |i|
+ a = i[1].empty? ? i[3] : i[1]
focus_addr(a, nil, true)
}
}
end
@@ -550,12 +559,15 @@
if not focus_addr(v, nil, true)
labels = @dasm.prog_binding.map { |k, vv|
[k, Expression[@dasm.normalize(vv)]] if k.downcase.include? v.downcase
}.compact
case labels.length
- when 0; focus_addr(v)
- when 1; focus_addr(labels[0][0])
+ when 0
+ ve = @dasm.normalize(Expression.parse(v))
+ focus_addr(v) if not focus_addr(ve, nil, true)
+ when 1
+ focus_addr(labels[0][0])
else
if labels.all? { |k, vv| vv == labels[0][1] }
focus_addr(labels[0][0])
elsif show_alt
labels.unshift ['name', 'addr']
@@ -658,11 +670,11 @@
@dasm_pause ||= []
if @dasm_pause.empty? and @dasm.addrs_todo.empty?
true
elsif @dasm_pause.empty?
@dasm_pause = @dasm.addrs_todo.dup
- @dasm.addrs_todo.replace @dasm_pause.find_all { |a, *b| @dasm.decoded[@dasm.normalize(a)] }
+ @dasm.addrs_todo.replace @dasm_pause.find_all { |a| @dasm.decoded[@dasm.normalize(a[:addr])] }
@dasm_pause -= @dasm.addrs_todo
puts "dasm paused (#{@dasm_pause.length})"
else
@dasm.addrs_todo.concat @dasm_pause
@dasm_pause.clear
@@ -839,10 +851,16 @@
when /\.rb$/; @dasm.load_plugin(f)
else messagebox("unsupported file extension #{f}")
end
end
+ def spawn_emudbg
+ edbg = EmuDebugger.new(@dasm)
+ edbg.pc = curaddr
+ DbgWindow.new(edbg)
+ end
+
def extend_contextmenu(tg, menu, addr=nil)
if @parent_widget.respond_to?(:extend_contextmenu)
@parent_widget.extend_contextmenu(tg, menu, addr)
end
end
@@ -883,15 +901,18 @@
end
end
class DasmWindow < Window
attr_accessor :dasm_widget, :menu
- def initialize_window(title = 'metasm disassembler', dasm=nil, *ep)
+ def initialize_window(*args)
+ dasm = args.grep(Disassembler).first
+ args -= [dasm]
+ title = args.find { |a| dasm ? !dasm.get_section_at(a) : a.kind_of?(::String) } || 'metasm disassembler'
+ ep = args - [title]
self.title = title
@dasm_widget = nil
if dasm
- ep = ep.first if ep.length == 1 and ep.first.kind_of? Array
display(dasm, ep)
else
self.widget = NoDasmWidget.new(self)
end
end
@@ -907,14 +928,15 @@
# sets up a DisasmWidget as main widget of the window, replaces the current if it exists
# returns the widget
def display(dasm, ep=[])
@dasm_widget.terminate if @dasm_widget
- ep = [ep] if not ep.kind_of? Array
+ ep = [ep] if not ep.kind_of?(Array)
+ ep0 = ep.first
@dasm_widget = DisasmWidget.new(dasm, ep)
self.widget = @dasm_widget
- @dasm_widget.focus_addr(ep.first) if ep.first
+ @dasm_widget.focus_addr(ep0) if ep0
@dasm_widget
end
# returns the specified widget from the @dasm_widget (idx in :hex, :listing, :graph etc)
def widget(idx=nil)
@@ -939,12 +961,14 @@
openfile("please locate #{str}", :blocking => true) { |f| ret = f }
return if not ret
ret
end
}
- (@dasm_widget ? DasmWindow.new : self).display(exe.disassembler)
- self.title = "#{File.basename(path)} - metasm disassembler"
+ tg_win = self
+ tg_win = DasmWindow.new if @dasm_widget
+ tg_win.display(exe.disassembler)
+ tg_win.title = "#{File.basename(path)} - metasm disassembler"
exe
end
def promptopen(caption='choose target binary', &b)
openfile(caption) { |exename| loadfile(exename) ; b.call(self) if b }
@@ -1104,10 +1128,11 @@
addsubmenu(actions, '_Undefine') { @dasm_widget.dasm.undefine_from(@dasm_widget.curview.current_address) ; @dasm_widget.gui_update }
addsubmenu(actions, 'Unde_fine function') { @dasm_widget.undefine_function(@dasm_widget.curview.current_address) }
addsubmenu(actions, 'Undefine function & _subfuncs') { @dasm_widget.undefine_function(@dasm_widget.curview.current_address, true) }
addsubmenu(actions, 'Data', 'd') { @dasm_widget.toggle_data(@dasm_widget.curview.current_address) }
addsubmenu(actions, 'Pause dasm', 'p', :check) { |ck| !@dasm_widget.playpause_dasm }
+ addsubmenu(actions, 'Spawn EmuDb_g', 'G') { @dasm_widget.spawn_emudbg }
addsubmenu(actions, 'Run ruby snippet', '^r') { promptruby }
addsubmenu(actions, 'Run _ruby plugin') { @dasm_widget.prompt_run_ruby_plugin }
addsubmenu(@menu, actions, '_Actions')
@@ -1125,9 +1150,10 @@
:text => @dasm_widget.dasm.backtrace_maxblocks_data) { |target|
@dasm_widget.dasm.backtrace_maxblocks_data = Integer(target) if not target.empty?
} if @dasm_widget
}
addsubmenu(options)
+ addsubmenu(options, 'Forbid a_ll optimizations', :check) { |ck| @dasm_widget.dasm.decompiler.forbid_all_optimizations = ck }
addsubmenu(options, 'Forbid decompile _types', :check) { |ck| @dasm_widget.dasm.decompiler.forbid_decompile_types = ck }
addsubmenu(options, 'Forbid decompile _if/while', :check) { |ck| @dasm_widget.dasm.decompiler.forbid_decompile_ifwhile = ck }
addsubmenu(options, 'Forbid decomp _optimize', :check) { |ck| @dasm_widget.dasm.decompiler.forbid_optimize_code = ck }
addsubmenu(options, 'Forbid decomp optim_data', :check) { |ck| @dasm_widget.dasm.decompiler.forbid_optimize_dataflow = ck }
addsubmenu(options, 'Forbid decomp optimlab_els', :check) { |ck| @dasm_widget.dasm.decompiler.forbid_optimize_labels = ck }