# 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: allow loading library signature files (see samples/generate_libsigs.rb) class LibSignature attr_accessor :sigs, :siglenmax, :giantregex # load signatures from a signature file def initialize(file) # hash symbolname => signature @sigs = {} # populate sigs symname = nil sig = '' File.read(file).each_line { |l| case l when /^ / sig << l.strip else @sigs[symname] = sig symname = l.strip sig = '' end } @sigs[symname] = sig @sigs.delete nil @siglenmax = @sigs.values.map { |v| v.length }.max # compile a giant regex from the signatures re = @sigs.values.uniq.map { |sig| sig.gsub(/../) { |b| b == '..' ? '.' : ('\\x' + b) } }.join('|') # 'n' is a magic flag to allow high bytes in the regex (ruby1.9 + utfail) @giantregex = Regexp.new re, Regexp::MULTILINE, 'n' end # we found a match on str at off, identify the specific symbol that matched # on conflict, only return the first match def matched_findsym(str, off) str = str[off, @siglenmax].unpack('H*').first @sigs.find { |sym, sig| str =~ /^#{sig}/i }[0] end # matches the signatures against a raw string # yields offset, symname for each match # returns nr of matches found def match_chunk(str) count = 0 off = 0 while o = (str[off..-1] =~ @giantregex) count += 1 off += o sym = matched_findsym(str, off) yield off, sym off += 1 end count end # matches the signatures against a big raw string # yields offset, symname for each match # returns nr of matches found def match(str) chunksz = 1 << 20 chunkoff = 0 count = 0 while chunkoff < str.length chunk = str[chunkoff, chunksz+@siglenmax] count += match_chunk(chunk) { |o, sym| yield chunkoff+o, sym if o < chunksz } chunkoff += chunksz end count end end def match_libsigs(sigfile) ls = LibSignature.new(sigfile) count = 0 @sections.each { |b, s| count += ls.match(s.data) { |off, sym| set_label_at(b+off, sym) } } count end if gui gui.openfile('signature file to load') { |f| gui.messagebox "#{match_libsigs(f)} signatures found" } end