metasm dasm plugin: allow loading library signature files (see samples/generate_libsigs.rb)
load signatures from a signature file
# File samples/dasm-plugins/match_libsigs.rb, line 12 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 { |sigh| sigh.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
matches the signatures against a big raw string yields offset, symname for each match returns nr of matches found
# File samples/dasm-plugins/match_libsigs.rb, line 68 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
matches the signatures against a raw string yields offset, symname for each match returns nr of matches found
# File samples/dasm-plugins/match_libsigs.rb, line 52 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
we found a match on str at off, identify the specific symbol that matched on conflict, only return the first match
# File samples/dasm-plugins/match_libsigs.rb, line 44 def matched_findsym(str, off) str = str[off, @siglenmax].unpack('H*').first @sigs.find { |sym, sig| str =~ /^#{sig}/ }[0] end