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 }