class Metasm::Gui::DisasmWidget
the main disassembler widget: this is a container for all the lower-level widgets that actually render the dasm state
Attributes
Public Instance Methods
add/change a comment @addr
# File metasm/gui/dasm_main.rb, line 262 def add_comment(addr) cmt = @dasm.comment[addr].to_a.join(' ') if di = @dasm.di_at(addr) cmt += di.comment.to_a.join(' ') end inputbox("new comment for #{Expression[addr]}", :text => cmt) { |c| c = c.split("\n") c = nil if c == [] do_add_comment(addr, c) session_append "do_add_comment(#{addr.inspect}, #{c.inspect})" gui_update } end
creates a new dasm window with the same disassembler object, focus it on addr#win
# File metasm/gui/dasm_main.rb, line 835 def clone_window(*focus) return if not popup = DasmWindow.new popup.display(@dasm, @entrypoints) w = popup.dasm_widget w.bg_color_callback = @bg_color_callback if bg_color_callback w.keyboard_callback = @keyboard_callback w.keyboard_callback_ctrl = @keyboard_callback_ctrl w.clones = @clones.concat w.clones w.focus_addr(*focus) popup end
returns the address of the item under the cursor in current view
# File metasm/gui/dasm_main.rb, line 111 def curaddr curview.current_address end
returns the object under the cursor in current view (@dasm.decoded)
# File metasm/gui/dasm_main.rb, line 116 def curobj curview.respond_to?(:curobj) ? curview.curobj : @dasm.decoded[curaddr] end
when updating @dasm, also update dasm for all views
# File metasm/gui/dasm_main.rb, line 71 def dasm=(d) @dasm = d view_indexes.each { |v| w = view(v) w.dasm = d if w.respond_to?(:'dasm=') } end
(re)decompile
# File metasm/gui/dasm_main.rb, line 317 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).curfuncaddr = nil end focus_addr(addr, :decompile) end
disassemble from this point if points to a call, make it return
# File metasm/gui/dasm_main.rb, line 286 def disassemble(addr) session_append "disassemble(#{addr.inspect}) ; wait_disassemble_bg" if di = @dasm.di_at(addr) and di.opcode.props[:saveip] di.block.each_to_normal { |t| 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 << { :addr => di.next_addr, :from => addr, :from_subfuncret => true } elsif addr @entrypoints << addr end start_disassemble_bg end
disassemble fast from this point (don't dasm subfunctions, don't backtrace)
# File metasm/gui/dasm_main.rb, line 303 def disassemble_fast(addr) @dasm.disassemble_fast(addr) session_append "dasm.disassemble_fast(#{addr.inspect})" gui_update end
disassemble fast & deep from this point (don't backtrace, but still dasm subfuncs)
# File metasm/gui/dasm_main.rb, line 310 def disassemble_fast_deep(addr) @dasm.disassemble_fast_deep(addr) session_append "dasm.disassemble_fast_deep(#{addr.inspect})" gui_update end
# File metasm/gui/dasm_main.rb, line 276 def do_add_comment(addr, c) if di = @dasm.di_at(addr) di.comment = c else @dasm.comment[addr] = c end end
ask the current view to update itself
# File metasm/gui/dasm_main.rb, line 232 def do_gui_update curview.gui_update if curview # invalidate all views ? end
# File metasm/gui/dasm_main.rb, line 847 def dragdropfile(f) case f when /\.(c|h|cpp)$/; @dasm.parse_c_file(f) when /\.map$/; @dasm.load_map(f) ; gui_update when /\.rb$/; @dasm.load_plugin(f) else messagebox("unsupported file extension #{f}") end end
display the specified address the display first searches in the current view if it cannot display the address, the listing, graph and decompile views are tried (in that order) the current focus address is saved in @pos_history (see focus_addr_back/redo) if quiet is false, a messagebox is popped if no view can display the address
# File metasm/gui/dasm_main.rb, line 175 def focus_addr(addr, viewidx=nil, quiet=false, *a) viewidx ||= curview_index || :listing return if not addr return if viewidx == curview_index and addr == curaddr and a.empty? oldpos = [curview_index, (curview.get_cursor_pos if curview)] views = [viewidx, oldpos[0]] views += [:listing, :graph, :decompile] & view_indexes if views.compact.uniq.find { |i| o_p = view(i).get_cursor_pos if (view(i).focus_addr(addr, *a) rescue nil) view(i).gui_update if i != oldpos[0] showview(i) true else view(i).set_cursor_pos o_p a.clear false end } @pos_history << oldpos if oldpos[0] # ignore start focus_addr @pos_history_redo.clear session_append "@session_focus_addr = #{addr.inspect} ; @pos_history = #{@pos_history.inspect}" true else messagebox "Invalid address #{addr}" if not quiet if oldpos[0] showview oldpos[0] curview.set_cursor_pos oldpos[1] end false end end
same as focus_addr
, also understands partial label names if the partial part is ambiguous, show a listwindow with all matches (if show_alt)
# File metasm/gui/dasm_main.rb, line 558 def focus_addr_autocomplete(v, show_alt=true) 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 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'] listwindow("list of labels", labels) { |i| focus_addr i[1] } end end end end
focus on the last address seen before the last focus_addr
# File metasm/gui/dasm_main.rb, line 209 def focus_addr_back(val = @pos_history.pop) return if not val @pos_history_redo << [curview_index, curview.get_cursor_pos] showview val[0] curview.set_cursor_pos val[1] true end
undo focus_addr_back
# File metasm/gui/dasm_main.rb, line 218 def focus_addr_redo if val = @pos_history_redo.pop @pos_history << [curview_index, curview.get_cursor_pos] showview val[0] curview.set_cursor_pos val[1] end end
ask the current view to update itself and redraw (incl all cloned widgets)
# File metasm/gui/dasm_main.rb, line 227 def gui_update @clones.each { |c| c.do_gui_update } end
# File metasm/gui/dasm_main.rb, line 38 def initialize_widget(dasm, ep=[]) @dasm = dasm @dasm.gui = self ep = [ep] if not ep.kind_of? Array @entrypoints = ep @pos_history = [] @pos_history_redo = [] @keyboard_callback = {} @keyboard_callback_ctrl = {} @clones = [self] @parent_widget = nil @gui_update_counter_max = 100 @dasm.callback_prebacktrace ||= lambda { Gui.main_iter } start_disassemble_bg addview :listing, AsmListingWidget.new(@dasm, self) addview :graph, GraphViewWidget.new(@dasm, self) addview :decompile, CdecompListingWidget.new(@dasm, self) addview :opcodes, AsmOpcodeWidget.new(@dasm, self) addview :hex, HexWidget.new(@dasm, self) 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
# File metasm/gui/dasm_main.rb, line 868 def inspect "<DisasmWidget @%x @dasm=#{dasm.inspect}>" % object_id end
calls focus_addr
(pre_yield_curaddr) after yield
# File metasm/gui/dasm_main.rb, line 242 def keep_focus_while addr = curaddr yield focus_addr curaddr if addr end
# File metasm/gui/dasm_main.rb, line 750 def keypress(key) return true if @keyboard_callback[key] and @keyboard_callback[key][key] case key when :enter; focus_addr curview.hl_word when :esc; focus_addr_back when ?/; inputbox('search word') { |w| next unless curview.respond_to? :hl_word next if w == '' curview.hl_word = w curview.hl_word_re = /(.*)(#{w})/ curview.redraw } when ?b; prompt_backtrace(curaddr) when ?c; disassemble(curaddr) when ?C; disassemble_fast(curaddr) when ?d; curobj.kind_of?(DecodedInstruction) ? toggle_expr_dec(curobj) : toggle_data(curaddr) when ?f; list_functions when ?g; prompt_goto when ?k; toggle_expr_str(curobj) when ?K; name_local_vars(curaddr) when ?l; list_labels when ?m; prompt_constant(curobj) when ?n; rename when ?o; toggle_expr_offset(curobj) when ?p; playpause_dasm when ?r; toggle_expr_char(curobj) when ?t; prompt_struct_ptr when ?v; $VERBOSE = ! $VERBOSE ; puts "#{'not ' if not $VERBOSE}verbose" # toggle verbose flag when ?x; list_xrefs when ?;; add_comment(curaddr) when ?\ ; toggle_view(:listing) when :tab; toggle_view(:decompile) when ?j; curview.keypress(:down) #when ?k; curview.keypress(:up) else p key if $DEBUG return @parent_widget ? @parent_widget.keypress(key) : false end true end
# File metasm/gui/dasm_main.rb, line 736 def keypress_ctrl(key) return true if @keyboard_callback_ctrl[key] and @keyboard_callback_ctrl[key][key] case key when :enter; focus_addr_redo when ?o; w = toplevel ; w.promptopen if w.respond_to? :promptopen when ?s; w = toplevel ; w.promptsave if w.respond_to? :promptsave when ?r; prompt_run_ruby when ?C; disassemble_fast_deep(curaddr) when ?f; prompt_search_decoded else return @parent_widget ? @parent_widget.keypress_ctrl(key) : false end true end
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 in green the callback is put only for the duration of the listwindow, and is not reentrant.
# File metasm/gui/dasm_main.rb, line 251 def list_bghilight(title, list, a={}, &b) prev_colorcb = bg_color_callback 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
# File metasm/gui/dasm_main.rb, line 339 def list_functions list = [['name', 'addr']] @dasm.function.keys.each { |f| addr = @dasm.normalize(f) next if not @dasm.di_at(addr) list << [@dasm.get_label_at(addr), Expression[addr]] } title = "list of functions" listwindow(title, list) { |i| focus_addr i[1] } end
# File metasm/gui/dasm_main.rb, line 350 def list_labels list = [['name', 'addr']] @dasm.prog_binding.each { |k, v| list << [k, Expression[@dasm.normalize(v)]] } listwindow("list of labels", list) { |i| focus_addr i[1] } end
# File metasm/gui/dasm_main.rb, line 358 def list_sections list = [['addr', 'length', 'name', 'info']] @dasm.section_info.each { |n,a,l,i| list << [Expression[a], Expression[l], n, i] } listwindow("list of sections", list) { |i| focus_addr i[0] if i[0] != '0' or @dasm.get_section_at(0) } end
# File metasm/gui/dasm_main.rb, line 366 def list_strings list = [['addr', 'string', 'length']] @dasm.strings_scan { |o, str| list << [Expression[o], str[0, 24].inspect, str.length] } listwindow("list of strings", list) { |i| focus_addr i[0] } end
# File metasm/gui/dasm_main.rb, line 374 def list_xrefs(addr=nil) list = [['address', 'type', 'instr']] if not addr and pointed_localvar addr = curview.hl_word faddr = @dasm.find_function_start(curaddr) func = @dasm.function[faddr] if func and func.localvars_xrefs stoff = func.localvars.index(addr) func.localvars_xrefs[stoff].to_a.each { |a| list << [Expression[a], '?'] if di = @dasm.di_at(a) list.last << di.instruction end } end else addr ||= pointed_addr @dasm.each_xref(addr) { |xr| next if not xr.origin list << [Expression[xr.origin], "#{xr.type}#{xr.len}"] if di = @dasm.di_at(xr.origin) list.last << di.instruction end } end if list.length == 1 messagebox "no xref to #{Expression[addr]}" if addr else listwindow("list of xrefs to #{Expression[addr]}", list) { |i| focus_addr(i[0], nil, true) } end end
# File metasm/gui/dasm_main.rb, line 715 def name_local_vars(a) @dasm.name_local_vars(a) session_append "dasm.name_local_vars(#{a.inspect})" gui_update end
parse an address and change it to a canonical address form supported formats: label names, or string with numerical value, incl hex (0x42 and 42h) if the string is full decimal, a check against mapped space is done to find if it is hexadecimal (eg 08048000)
# File metasm/gui/dasm_main.rb, line 144 def normalize(addr) case addr when ::String if @dasm.prog_binding[addr] addr = @dasm.prog_binding[addr] elsif (?0..?9).include? addr[0] or (?a..?f).include? addr.downcase[0] case addr when /^0x/i when /h$/i; addr = '0x' + addr[0...-1] when /[a-f]/i; addr = '0x' + addr when /^[0-9]+$/ addr = '0x' + addr if not @dasm.get_section_at(addr.to_i) and @dasm.get_section_at(addr.to_i(16)) end begin addr = Integer(addr) rescue ::ArgumentError return end else return end end addr end
pause/play disassembler returns true if playing this empties @dasm.addrs_todo, the dasm may still continue to work if this msg is
handled during an instr decoding/backtrace (the backtrace may generate new addrs_todo)
addresses in addrs_todo pointing to existing decoded instructions are left to create a prettier graph
# File metasm/gui/dasm_main.rb, line 669 def playpause_dasm @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| @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 puts "dasm restarted (#{@dasm.addrs_todo.length})" start_disassemble_bg true end end
returns the address of the label under the cursor or the address of the line of the cursor
# File metasm/gui/dasm_main.rb, line 121 def pointed_addr hl = curview.hl_word if hl =~ /^[0-9].*h$/ and a = hl.to_i(16) and @dasm.get_section_at(a) return a end @dasm.prog_binding[hl] || curview.current_address end
returns the ExpressionString
if the currently hilighted word is a :stackvar
# File metasm/gui/dasm_main.rb, line 130 def pointed_localvar(obj=curobj, hl=curview.hl_word) return if not obj.kind_of?(Renderable) localvar = nil obj.each_expr { |e| next unless e.kind_of?(ExpressionString) localvar = e if e.type == :stackvar and e.str == hl } localvar end
# File metasm/gui/dasm_main.rb, line 413 def prompt_backtrace(addr=curaddr) inputbox('expression to backtrace', :text => curview.hl_word) { |e| expr = IndExpression.parse_string(e) bd = {} registers = (@dasm.cpu.dbg_register_list.map { |r| r.to_s } rescue []) expr.externals.grep(String).each { |w| if registers.include? w.downcase bd[w] = w.downcase.to_sym end } 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 = [['order', 'address', 'type', 'old value', 'value']] order = 0 log.each { |t, *a| 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 << [('%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, :bghilight_index => 1) { |i| a = i[1].empty? ? i[3] : i[1] focus_addr(a, nil, true) } } end
prompts for a structure name, autocompletes to known structures, and/or display a listwindow with possible completions, yields the target structure name
# File metasm/gui/dasm_main.rb, line 505 def prompt_c_struct(prompt, opts={}) inputbox(prompt, opts) { |st_name| stars = '' if opts[:allow_stars] stars = st_name[/\**$/] st_name[stars] = '' end # TODO propose typedef struct {} moo; too sh = @dasm.c_parser.toplevel.struct if sh[st_name].kind_of?(C::Union) stn_list = [st_name] else stn_list = sh.keys.grep(String).find_all { |k| sh[k].kind_of?(C::Union) } end if name = stn_list.find { |n| n == st_name } || stn_list.find { |n| n.downcase == st_name.downcase } # single match yield(name+stars) else # try autocomplete list = [['name']] list += stn_list.sort.grep(/#{st_name}/i).map { |stn| [stn+stars] } if list.length == 2 # single autocompletion yield(list[1][0]) else listwindow(prompt, list) { |ans| yield(ans[0]) } end end } end
prompt the contant to use in place of some numeric value
# File metasm/gui/dasm_main.rb, line 458 def prompt_constant(di=curobj) return if not di.kind_of?(DecodedInstruction) di.each_expr { |e| next unless e.kind_of?(Expression) if (e.lexpr.kind_of?(Integer) or e.lexpr.kind_of?(ExpressionString)) and (!curview.hl_word or curview.hl_word == Expression[e.lexpr].to_s) v = Expression[e.lexpr].reduce lst = [] dasm.c_constants.each { |cn, cv, fm| lst << [cn, fm] if v == cv } if not lst.empty? default = Expression[v].to_s lst << [default] listwindow("constant for #{Expression[v]}", [['name', 'enum']] + lst) { |a| if a[0] == default e.lexpr = v else e.lexpr = ExpressionString.new(v, a[0], :constant) end session_append "if di = dasm.di_at(#{di.address.inspect}) ; di.each_expr { |e| e.lexpr = #{e.lexpr.inspect} if e.kind_of?(Expression) and e.lexpr and Expression[e.lexpr].reduce == #{v.inspect} } ; end" gui_update } end end if (e.rexpr.kind_of? Integer or e.rexpr.kind_of?(ExpressionString)) and (!curview.hl_word or curview.hl_word == Expression[e.rexpr].to_s) v = Expression[e.rexpr].reduce lst = [] dasm.c_constants.each { |cn, cv, fm| lst << [cn, fm] if v == cv } if not lst.empty? default = Expression[v].to_s lst << [default] listwindow("constant for #{Expression[v]}", [['name', 'enum']] + lst) { |a| if a[0] == default e.rexpr = v else e.rexpr = ExpressionString.new(v, a[0], :constant) end session_append "if di = dasm.di_at(#{di.address.inspect}) ; di.each_expr { |e| e.rexpr = #{e.rexpr.inspect} if e.kind_of?(Expression) and e.rexpr and Expression[e.rexpr].reduce == #{v.inspect} } ; end" gui_update } end end } end
jump to address
# File metasm/gui/dasm_main.rb, line 407 def prompt_goto inputbox('address to go', :text => Expression[curaddr]) { |v| focus_addr_autocomplete(v) } end
parses a C
header
# File metasm/gui/dasm_main.rb, line 581 def prompt_parse_c_file openfile('open C header') { |f| @dasm.parse_c_file(f) rescue messagebox("#{$!}\n#{$!.backtrace}") } end
run arbitrary ruby
# File metasm/gui/dasm_main.rb, line 588 def prompt_run_ruby inputbox('ruby code to eval()') { |c| messagebox eval(c).inspect[0, 512], 'eval' session_append "#eval #{c.inspect}" } end
run ruby plugin
# File metasm/gui/dasm_main.rb, line 596 def prompt_run_ruby_plugin openfile('ruby plugin') { |f| @dasm.load_plugin(f) } end
search for a regexp in dasm
.decoded.to_s
# File metasm/gui/dasm_main.rb, line 601 def prompt_search_decoded inputbox('text to search in instrs (regex)', :text => curview.hl_word) { |pat| re = /#{pat}/i found = [] @dasm.decoded.each { |k, v| found << k if v.to_s =~ re } list = [['addr', 'str']] + found.map { |a| [Expression[a], @dasm.decoded[a].to_s] } list_bghilight("search result for /#{pat}/i", list) { |i| focus_addr i[0] } } end
prompt the struct to use for offset in a given instr
# File metasm/gui/dasm_main.rb, line 541 def prompt_struct_ptr(reg=curview.hl_word, addr=curaddr) return if not reg or not @dasm.cpu.register_symbols.find { |rs| rs.to_s == reg.to_s } reg = reg.to_sym di = @dasm.di_at(addr) return if not di.kind_of?(DecodedInstruction) prompt_c_struct("struct pointed by #{reg}", :allow_stars => true) { |st| # TODO store that info for the decompiler ? @dasm.trace_update_reg_structptr(addr, reg, st) session_append "dasm.trace_update_reg_structptr(#{addr.inspect}, #{reg.inspect}, #{st.inspect})" gui_update } end
calls the @dasm.rebase method to change the load base address of the current program
# File metasm/gui/dasm_main.rb, line 614 def rebase(addr=nil) if not addr inputbox('rebase address') { |a| rebase(Integer(a)) } else na = curaddr + dasm.rebase(addr) gui_update focus_addr na end end
redraw the window
# File metasm/gui/dasm_main.rb, line 237 def redraw curview.redraw end
prompts for a new name for what is under the cursor (or the current address)
# File metasm/gui/dasm_main.rb, line 625 def rename(what=nil) if not what and localvar = pointed_localvar addr = curaddr str = localvar.str.dup inputbox("new name for #{localvar}", :text => localvar.to_s) { |v| if v =~ /^[a-z_][a-z0-9_]*$/i localvar.str.replace v session_append "pointed_localvar(dasm.decoded[#{addr.inspect}], #{str.inspect}).str.replace(#{v.inspect})" gui_update else messagebox("invalid local var name #{v.inspect}") end } return end what ||= pointed_addr if @dasm.prog_binding[what] or old = @dasm.get_label_at(what) old ||= what inputbox("new name for #{old}", :text => old) { |v| if v == '' @dasm.del_label_at(what) session_append "dasm.del_label_at(#{what.inspect})" else @dasm.rename_label(old, v) session_append "dasm.rename_label(#{old.inspect}, #{v.inspect})" end gui_update } else inputbox("label name for #{Expression[what]}", :text => Expression[what]) { |v| next if v == '' @dasm.set_label_at(what, v) @dasm.split_block(what) session_append "dasm.set_label_at(#{what.inspect}, #{v.inspect}) ; dasm.split_block(#{what.inspect})" gui_update } end end
# File metasm/gui/dasm_main.rb, line 797 def replay_session(filename) i = 0 File.readlines(filename).each { |l| instance_eval l i += 1 } focus_addr(@session_focus_addr) if @session_focus_addr puts "Session replay finished" rescue ::Exception puts "Session replay: error on line #{i}: #{$!.class} #{$!}" end
# File metasm/gui/dasm_main.rb, line 793 def save_session(filename) @session_file = filename end
append one line to the session file converts addresses to hex, deletes consecutive set_focus lines
# File metasm/gui/dasm_main.rb, line 811 def session_append(str) return if not session_file # convert decimal addrs to hex str = str.sub(/(\(|\[|= )(\d\d\d\d\d\d+)/) { $1 + ('0x%x' % $2.to_i) } @session_lastsz_setfocus ||= nil # prevent warning if str =~ /^@session_focus_addr = / and @session_lastsz_setfocus # overwrite previous set_focus File.truncate(session_file, @session_lastsz_setfocus) if File.size(session_file) == @session_lastsz is_setfocus = true end File.open(session_file, 'a') { |fd| fd.puts str } @session_lastsz = File.size(session_file) @session_lastsz_setfocus = @session_lastsz if not is_setfocus rescue @session_file = nil puts "Failed to save session, disabling (#{$!.class} #{$!})" end
# File metasm/gui/dasm_main.rb, line 856 def spawn_emudbg edbg = EmuDebugger.new(@dasm) edbg.pc = curaddr DbgWindow.new(edbg) end
start an idle callback that will run one round of @dasm.disassemble_mainiter
# File metasm/gui/dasm_main.rb, line 80 def start_disassemble_bg return if @dasm.addrs_todo.empty? and @entrypoints.all? { |ep| @dasm.decoded[ep] } gui_update_counter = 0 run = false Gui.idle_add { # metasm disassembler loop # update gui once in a while if run or not @entrypoints.empty? or not @dasm.addrs_todo.empty? protect { run = @dasm.disassemble_mainiter(@entrypoints) } gui_update_counter += 1 if gui_update_counter > @gui_update_counter_max gui_update_counter = 0 gui_update end true else gui_update false end } end
# File metasm/gui/dasm_main.rb, line 106 def terminate @clones.delete self end
change the format of displayed data under addr (byte, word, dword, qword) currently this is done using a fake empty xref
# File metasm/gui/dasm_main.rb, line 328 def toggle_data(addr) session_append "toggle_data(#{addr.inspect})" return if @dasm.decoded[addr] or not @dasm.get_section_at(addr) @dasm.add_xref(addr, Xref.new(nil, nil, 1)) if not @dasm.xrefs[addr] @dasm.each_xref(addr) { |x| x.len = {1 => 2, 2 => 4, 4 => 8}[x.len] || 1 break } gui_update end
toggles <41h> vs <'A'> display
# File metasm/gui/dasm_main.rb, line 688 def toggle_expr_char(o) @dasm.toggle_expr_char(o) session_append "dasm.toggle_expr_char(dasm.decoded[#{curaddr.inspect}])" gui_update end
toggle <10h> vs <16> display
# File metasm/gui/dasm_main.rb, line 695 def toggle_expr_dec(o) @dasm.toggle_expr_dec(o) session_append "dasm.toggle_expr_dec(dasm.decoded[#{curaddr.inspect}])" gui_update end
toggle <401000h> vs <'sub_fancyname'> in the current instr display
# File metasm/gui/dasm_main.rb, line 702 def toggle_expr_offset(o) @dasm.toggle_expr_offset(o) session_append "dasm.toggle_expr_offset(dasm.decoded[#{curaddr.inspect}])" gui_update end
toggle constant/localvar names with raw value
# File metasm/gui/dasm_main.rb, line 709 def toggle_expr_str(o) @dasm.toggle_expr_str(o) session_append "dasm.toggle_expr_str(dasm.decoded[#{curaddr.inspect}])" gui_update end
# File metasm/gui/dasm_main.rb, line 721 def toggle_view(idx) default = (idx == :graph ? :listing : :graph) # switch to idx ; if already in idx, use default focus_addr(curaddr, ((curview_index == idx) ? default : idx)) end
undefines the whole function body
# File metasm/gui/dasm_main.rb, line 728 def undefine_function(addr, incl_subfuncs = false) list = [] @dasm.each_function_block(addr, incl_subfuncs) { |b| list << b } list.each { |b| @dasm.undefine_from(b) } session_append "undefine_function(#{addr.inspect}, #{incl_subfuncs.inspect})" gui_update end
# File metasm/gui/dasm_main.rb, line 102 def wait_disassemble_bg Gui.main_iter until @entrypoints.empty? and @dasm.addrs_todo.empty? end