module SMC
This file tries to handle simple self-modifying code patterns To be used as a –plugin for a Disassembler object
Constants
- VirtSections
Public Class Methods
emu(dasm, addr)
click to toggle source
try to emulate the byte modifications creates a new virtual section in dasm holding decoded data adds the virtual section to the dasm, stores the addresses in VirtSections returns true if successful
# File samples/dasm-plugins/selfmodify.rb, line 88 def self.emu(dasm, addr) puts "emulate SMC @#{Metasm::Expression[addr]}" if $VERBOSE writer = nil dasm.each_xref(addr, :w) { |xr| writer = xr.origin } return if not dasm.di_at(writer) a_pre, a_entry, a_cond, a_out, loop_bd = find_loop(dasm, writer) return if not a_pre # expression checking if we get out of the loop loop_again_cond = dasm.cpu.get_jump_condition(dasm.decoded[a_cond]) loop_again_cond = Expression[:'!', loop_again_cond] if dasm.decoded[a_cond].next_addr != a_out init_bd = {} loop_bd.values.map { |v| v.externals }.flatten.uniq.each { |ext| bt = dasm.backtrace(ext, a_pre, :include_start => true) init_bd[ext] = bt.first if bt.length == 1 and bt.first != Metasm::Expression::Unknown and bt.first != Metasm::Expression[ext] } # reject non-determinist memory write loop_bd.delete_if { |k, v| k.kind_of? Metasm::Indirection and not dasm.get_section_at(k.pointer.bind(init_bd).reduce) } cow_data = CoWData.new(dasm) puts "emulation running..." if $VERBOSE pre_bd = init_bd loop do # the effects of the loop post_bd = loop_bd.inject({}) { |bd, (k, v)| if k.kind_of? Metasm::Indirection k = k.bind(pre_bd).reduce_rec raise "bad ptr #{k}" if not dasm.get_section_at(k.pointer.reduce) end bd.update k => Metasm::Expression[v.bind(pre_bd).reduce] } # the indirections used by the loop # read mem from cow_data # ignores stacked indirections & keys ind_bd = {} post_bd.values.map { |v| v.expr_indirections }.flatten.uniq.each { |ind| p = ind.pointer.reduce raise "bad loop read #{ind}" if not p.kind_of? Integer ind_bd[ind] = Metasm::Expression.decode_imm(cow_data[p, ind.len], "u#{ind.len*8}".to_sym, dasm.cpu.endianness) } post_bd.each { |k, v| next if not k.kind_of? Metasm::Indirection cow_data[k.pointer.reduce, k.len] = Metasm::Expression.encode_imm(v.bind(ind_bd).reduce, "u#{k.len*8}".to_sym, dasm.cpu.endianness) } break if loop_again_cond.bind(post_bd).reduce == 0 pre_bd.update(post_bd) pre_bd.delete_if { |k, v| not k.kind_of? Symbol } end puts "emulation done (#{cow_data.data.length} bytes)" if $VERBOSE VirtSections[dasm] ||= {} newbase = "smc#{VirtSections[dasm].length}" VirtSections[dasm][addr] = newbase dasm.add_section(Metasm::EncodedData.new(cow_data.data), newbase) dasm.comment[Metasm::Expression[newbase]] = "SelfModifyingCode from #{dasm.decoded[writer]}" true end
find_loop(dasm, addr)
click to toggle source
find the loop containing addr only trivial loops handled returns [loop start, last instr before loop, loop conditionnal jump, 1st instr after loop, loop binding]
# File samples/dasm-plugins/selfmodify.rb, line 160 def self.find_loop(dasm, addr) b = dasm.decoded[addr].block return if not b.to_normal.to_a.include? b.address b1 = b2 = b pre = (b1.from_normal - [b2.list.last.address]).first first = b1.address last = b2.list.last.address post = (b2.to_normal - [b1.address]).first loop_bd = dasm.code_binding(first, post, :include_flags => true) [pre, first, last, post, loop_bd] end
redirect(dasm, addr)
click to toggle source
redirects the code flow from addr to the decoded section
# File samples/dasm-plugins/selfmodify.rb, line 175 def self.redirect(dasm, addr) return if not VirtSections[dasm] or not newto = Metasm::Expression[VirtSections[dasm][addr]] dasm.each_instructionblock { |b| next if not b.to_normal.to_a.include? addr b.to_normal.map! { |tn| dasm.normalize(tn) == addr ? newto : tn } dasm.add_xref(newto, Metasm::Xref.new(:x, b.list.last.address)) b.list.last.add_comment "x:#{newto}" dasm.addrs_todo << { :addr => newto, :from => b.list.last.address } } end