lists the functions/addresses exported to the OS (pendant of ImportDirectory)
decodes a COFF export table from coff.cursection
# File metasm/exe_format/coff_decode.rb, line 75 def decode(coff) super(coff) if coff.sect_at_rva(@libname_p) @libname = coff.decode_strz end if coff.sect_at_rva(@func_p) @exports = [] addrs = [] @num_exports.times { addrs << coff.decode_word } @num_exports.times { |i| e = Export.new e.ordinal = i + @ordinal_base addr = addrs[i] if addr >= coff.directory['export_table'][0] and addr < coff.directory['export_table'][0] + coff.directory['export_table'][1] and coff.sect_at_rva(addr) name = coff.decode_strz e.forwarder_lib, name = name.split('.', 2) if name.index('.') if name[0] == # e.forwarder_ordinal = name[1..-1].to_i else e.forwarder_name = name end else e.target = e.target_rva = addr end @exports << e } end if coff.sect_at_rva(@names_p) namep = [] num_names.times { namep << coff.decode_word } end if coff.sect_at_rva(@ord_p) ords = [] num_names.times { ords << coff.decode_half } end if namep and ords namep.zip(ords).each { |np, oi| next if not @exports[oi] @exports[oi].name_p = np if coff.sect_at_rva(np) @exports[oi].name = coff.decode_strz end } end end
encodes an export directory
# File metasm/exe_format/coff_encode.rb, line 73 def encode(coff) edata = {} %w[edata addrtable namptable ord_table libname nametable].each { |name| edata[name] = EncodedData.new } label = lambda { |n| coff.label_at(edata[n], 0, n) } rva = lambda { |n| Expression[label[n], :-, coff.label_at(coff.encoded, 0)] } rva_end = lambda { |n| Expression[[label[n], :-, coff.label_at(coff.encoded, 0)], :+, edata[n].virtsize] } # ordinal base: smallest number > 1 to honor ordinals, minimize gaps olist = @exports.map { |e| e.ordinal }.compact # start with lowest ordinal, substract all exports unused to fill ordinal sequence gaps omin = olist.min.to_i gaps = olist.empty? ? 0 : olist.max+1 - olist.min - olist.length noord = @exports.length - olist.length @ordinal_base ||= [omin - (noord - gaps), 1].max @libname_p = rva['libname'] @num_exports = [@exports.length, @exports.map { |e| e.ordinal }.compact.max.to_i - @ordinal_base].max @num_names = @exports.find_all { |e| e.name }.length @func_p = rva['addrtable'] @names_p = rva['namptable'] @ord_p = rva['ord_table'] edata['edata'] << super(coff) edata['libname'] << @libname << 0 elist = @exports.find_all { |e| e.name and not e.ordinal }.sort_by { |e| e.name } @exports.find_all { |e| e.ordinal }.sort_by { |e| e.ordinal }.each { |e| elist.insert(e.ordinal-@ordinal_base, e) } elist.each { |e| if not e # export by ordinal with gaps # XXX test this value with the windows loader edata['addrtable'] << coff.encode_word(0xffff_ffff) next end if e.forwarder_lib edata['addrtable'] << coff.encode_word(rva_end['nametable']) edata['nametable'] << e.forwarder_lib << . << if not e.forwarder_name "##{e.forwarder_ordinal}" else e.forwarder_name end << 0 else edata['addrtable'] << coff.encode_word(Expression[e.target, :-, coff.label_at(coff.encoded, 0)]) end if e.name edata['ord_table'] << coff.encode_half(edata['addrtable'].virtsize/4 - 1) edata['namptable'] << coff.encode_word(rva_end['nametable']) edata['nametable'] << e.name << 0 end } # sorted by alignment directives %w[edata addrtable namptable ord_table libname nametable].inject(EncodedData.new) { |ed, name| ed << edata[name] } end
# File metasm/exe_format/coff_encode.rb, line 132 def set_default_values(coff) @timestamp ||= Time.now.to_i @libname ||= 'metalib' @ordinal_base ||= 1 super(coff) end