class Elf

Attributes

arch[RW]

attr_accessor :gotplt

bits[RW]

attr_accessor :gotplt

dynamic[RW]

attr_accessor :gotplt

global[RW]

attr_accessor :gotplt

got[RW]

attr_accessor :gotplt

sections[RW]

attr_accessor :gotplt

Public Class Methods

new(file) click to toggle source
# File lib/elf.rb, line 276
def initialize(file)
    # To avoid unicode
    binary = File.read(file).force_encoding('binary')
    # To fix bugs leading eof, that's why here is a newline ...
    elf = ElfParser.read binary + "\n"
    # parse information we need
    extract_info binary, elf
end

Private Instance Methods

extract_info(binary, elf) click to toggle source
# File lib/elf.rb, line 287
def extract_info(binary, elf)
    @arch = elf.arch.to_s
    @bits = elf.bits.to_i
    # parse section name
    parse_section_name binary, elf
    # parse symbol table
    parse_symtab binary, elf
    # Parse dynamic section
    parse_dynamic_constant binary, elf
    ## parse rel.plt
    parse_relplt binary, elf
end
parse_dynamic_constant(binary, elf) click to toggle source
# File lib/elf.rb, line 318
def parse_dynamic_constant(binary, elf)
    dynamic = nil
    elf.e_shnum.times do |i|
        content = binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
        if elf.sh[i].sh_type == 6 # DYNAMIC
            size = elf.sh[i].sh_size / elf.sh[i].sh_entsize
            if @bits == 32
                dynamic = BinData::Array.new(:type => :dynamic32, :initial_length => size)
            else
                dynamic = BinData::Array.new(:type => :dynamic64, :initial_length => size)
            end
            dynamic.read content
        end
    end
    @dynamic = {}
    dynamic.each do |d|
        # PLTREL
        if d.d_tag == 20
            if d.d_val == 7
                @dynamic["rel_type"]= "RELA"
            elsif d.d_val == 17
                @dynamic["rel_type"]= "REL"
            end
        # STRTAB
        elsif d.d_tag == 5
            @dynamic["strtab"]= d.d_val.to_i
        # SYMTAB
        elsif d.d_tag == 6
            @dynamic["symtab"]= d.d_val.to_i
        # JMPREL
        elsif d.d_tag == 0x17
            @dynamic["jmprel"]= d.d_val.to_i
        end
    end
end
parse_relplt(binary, elf) click to toggle source
# File lib/elf.rb, line 385
def parse_relplt(binary, elf)
    rel = nil
    reldyn = nil
    elf.e_shnum.times do |i|
        if @dynamic["rel_type"] == "REL"
            if elf.sh[i].name_str == ".rel.plt"
                size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
                if elf.e_ident[:ei_class] == 1
                    rel = BinData::Array.new(:type => :relplt32, :initial_length => size)
                else
                    rel = BinData::Array.new(:type => :relplt64, :initial_length => size)
                end
                rel.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
            elsif elf.sh[i].name_str == ".rel.dyn"
                size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
                if @bits == 32
                    reldyn = BinData::Array.new(:type => :relplt32, :initial_length => size)
                else
                    reldyn = BinData::Array.new(:type => :relplt64, :initial_length => size)
                end
                reldyn.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
            end
        elsif @dynamic["rel_type"] == "RELA"
            if elf.sh[i].name_str == ".rela.plt"
                size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
                if @bits == 32
                    rel = BinData::Array.new(:type => :relaplt32, :initial_length => size)
                else
                    rel = BinData::Array.new(:type => :relaplt64, :initial_length => size)
                end
                rel.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
            elsif elf.sh[i].name_str == ".rela.dyn"
                size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
                if @bits == 32
                    reldyn = BinData::Array.new(:type => :relaplt32, :initial_length => size)
                else
                    reldyn = BinData::Array.new(:type => :relaplt64, :initial_length => size)
                end
                reldyn.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
            end
        end
    end

    # extract information
    @got = {}
    rel.each do |r|
        if r.type.to_i == 7 # JMP_SLOT
            @got[elf.symtab[r.sym_index.to_i].name_str.to_s] = r.r_offset.to_i
        end
    end
    @global = Hash.new {|h, k| h[k] = Hash.new}
    reldyn.each do |r|
        if r.type.to_i == 6 # GLOB_DAT
            @global[elf.symtab[r.sym_index.to_i].name_str.to_s]["offset"] = r.r_offset.to_i
            @global[elf.symtab[r.sym_index.to_i].name_str.to_s]["value"] = elf.symtab[r.sym_index.to_i].st_value.to_i
        end
    end
end
parse_section_name(binary, elf) click to toggle source
# File lib/elf.rb, line 300
def parse_section_name(binary, elf)
    strtab_offset = elf.sh[elf.e_shstrndx].sh_offset.to_i
    strtab = binary[(strtab_offset)..-1]
    @sections = Hash.new{|h, k| h[k] = Hash.new }
    elf.e_shnum.times do |i|
        sh_name = elf.sh[i].sh_name.to_i
        elf.sh[i].name_str.assign BinData::Stringz.read strtab[sh_name..-1]
        flag = "r"
        flag += (elf.sh[i].sh_flags & 1) > 0 ? "w" : "-"
        flag += (elf.sh[i].sh_flags & 4) > 0 ? "x" : "-"

        @sections[elf.sh[i].name_str.to_s]["addr"] = elf.sh[i].sh_addr.to_i
        @sections[elf.sh[i].name_str.to_s]["offset"] = elf.sh[i].sh_offset.to_i
        @sections[elf.sh[i].name_str.to_s]["size"] = elf.sh[i].sh_size.to_i
        @sections[elf.sh[i].name_str.to_s]["flag"] = flag
    end
end
parse_symtab(binary, elf) click to toggle source
# File lib/elf.rb, line 354
def parse_symtab(binary, elf)
    # find dynamic symtab
    symtab = nil
    elf.e_shnum.times do |i|
        if elf.sh[i].name_str.to_s == ".dynsym"
            size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
            if elf.e_ident[:ei_class] == 1
                symtab = BinData::Array.new(:type => :symtab32, :initial_length => size)
            else
                symtab = BinData::Array.new(:type => :symtab64, :initial_length => size)
            end
            symtab = symtab.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
        end
    end

    # find dynamic strtab
    strtab = nil
    elf.e_shnum.times do |i|
        if elf.sh[i].name_str.to_s == ".dynstr"
            strtab = binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
        end
    end

    # find the name of dynamic symbol
    symtab.size.times do |i|
        symtab[i].name_str.assign BinData::Stringz.read strtab[symtab[i].st_name..-1]
    end

    elf.symtab.assign symtab
end