metasploit-framework/lib/metasm/samples/dasm-plugins/match_libsigs.rb

94 lines
2.2 KiB
Ruby

# 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