class Metasm::COFF::ExportDirectory

lists the functions/addresses exported to the OS (pendant of ImportDirectory)

Attributes

exports[RW]
libname[RW]

Public Instance Methods

decode(coff) click to toggle source

decodes a COFF export table from coff.cursection

Calls superclass method Metasm::SerialStruct#decode
# 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
encode(coff) click to toggle source

encodes an export directory

Calls superclass method Metasm::SerialStruct#encode
# 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
set_default_values(coff) click to toggle source
Calls superclass method Metasm::SerialStruct#set_default_values
# 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