# This file is part of Metasm, the Ruby assembly manipulation suite # Copyright (C) 2006-2009 Yoann GUILLOT # # Licence is LGPL, see LICENCE in the top-level directory # metasm dasm plugin # finds instances of indirect calls a la call [ecx+40h], backtraces ecx, comments with the C++ object function pointer name # if the backtracked object has no type, prompt for a C structure name. # TODO simpler gui interface to set [base+off] => ; struct->member @indirect_call_struct = {} def solve_indirect_call_set_struct(ptr, struct) struct = @c_parser.toplevel.struct[struct] if struct.kind_of? String raise 'no such struct' if not struct @indirect_call_struct[ptr] = struct end def solve_indirect_calls @decoded.values.grep(DecodedInstruction).each { |di| next if not di.opcode.props[:saveip] # only calls fptr = get_xrefs_x(di) next if fptr.to_a.length != 1 fptr = Expression[fptr.first].reduce_rec next if not fptr.kind_of? Indirection next if not fptr.pointer.lexpr.kind_of? Symbol next if not fptr.pointer.rexpr.kind_of? Integer obj = backtrace(fptr.pointer.lexpr, di.address) obj.delete Expression::Unknown next if obj.length != 1 obj = obj.first obj = Expression[obj].reduce_rec next if not obj.kind_of? Indirection obj = obj.pointer # vtable ptr -> object ptr if not struct = @indirect_call_struct[obj] struct = yield obj if block_given? solve_indirect_call_set_struct(obj, struct || :none) end if struct.kind_of? C::Struct and fld = struct.members.find { |m| struct.offsetof(c_parser, m) == fptr.pointer.rexpr } and fld.name di.add_comment "#{struct.name || obj}->#{fld.name}" di.comment.delete 'x:unknown' end } end if gui solve_indirect_calls { |ptr| gui.inputbox("struct name for object at #{ptr}") { |name| solve_indirect_call_set_struct(ptr, name) # re-solve everything, cause we're called only once but many indirect calls may use ptr solve_indirect_calls gui.gui_update } } gui.gui_update nil end