class PEdump::PE

Attributes

ioh_offset[RW]

Public Class Methods

logger() click to toggle source
# File lib/pedump/pe.rb, line 112
def self.logger; PEdump.logger; end
read(f, args = {}) click to toggle source
# File lib/pedump/pe.rb, line 59
def self.read f, args = {}
  pe_offset = f.tell
  pe_sig = f.read 4
  #logger.error "[!] 'NE' format is not supported!" if pe_sig == "NE\x00\x00"
  if pe_sig != "PE\x00\x00"
    if args[:force]
      logger.warn  "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect})"
    else
      logger.debug "[?] no PE signature (want: 'PE\\x00\\x00', got: #{pe_sig.inspect}). (not forced)"
      return nil
    end
  end
  pe = PE.new(pe_sig)
  pe.image_file_header = IMAGE_FILE_HEADER.read(f)
  pe.ioh_offset = f.tell # offset to IMAGE_OPTIONAL_HEADER
  if pe.ifh.SizeOfOptionalHeader.to_i > 0
    if pe.x64?
      pe.image_optional_header = IMAGE_OPTIONAL_HEADER64.read(f, pe.ifh.SizeOfOptionalHeader)
    else
      pe.image_optional_header = IMAGE_OPTIONAL_HEADER32.read(f, pe.ifh.SizeOfOptionalHeader)
    end
  end

  nToRead=pe.ifh.NumberOfSections.to_i

  # The Windows loader expects to find the PE section headers after the optional header. It calculates the address of the first section header by adding SizeOfOptionalHeader to the beginning of the optional header.
  # // http://www.phreedom.org/research/tinype/
  f.seek( pe.ioh_offset + pe.ifh.SizeOfOptionalHeader.to_i )
  pe.sections = read_sections(f, nToRead, args)

  pe_end = f.tell
  if s=pe.sections.find{ |s| (pe_offset...pe_end).include?(s.va) }
    if args[:pass2]
      # already called with CompositeIO ?
      PEdump.logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! 2nd time?!"

    elsif pe_end-pe_offset < 0x100_000
      PEdump.logger.warn "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! trying to rebuild..."
      f.seek pe_offset
      data = f.read(s.va-pe_offset)
      f.seek s.PointerToRawData
      io = CompositeIO.new(StringIO.new(data), f)
      args1 = args.dup
      args1[:pass2] = true
      return PE.read(io, args1)
    else
      PEdump.logger.error "[!] section with va=0x#{s.va.to_s(16)} overwrites PE header! too big to rebuild!"
    end
  end

  pe
end
read_sections(f, nToRead, args = {}) click to toggle source
# File lib/pedump/pe.rb, line 29
def self.read_sections f, nToRead, args = {}
  force = args[:force]

  if nToRead > 0xffff
    if force.is_a?(Numeric) && force > 1
      PEdump.logger.warn "[!] too many sections (#{nToRead}). forced. reading all"
    else
      PEdump.logger.warn "[!] too many sections (#{nToRead}). not forced, reading first 65535"
      nToRead = 65535
    end
  end

  sections = []
  nToRead.times do
    break if f.eof?
    sections << IMAGE_SECTION_HEADER.read(f)
  end

  if sections.any?
    # zero all missing values of last section
    sections.last.tap do |last_section|
      last_section.each_pair do |k,v|
        last_section[k] = 0 if v.nil?
      end
    end
  end

  sections
end

Public Instance Methods

dll?() click to toggle source
# File lib/pedump/pe.rb, line 21
def dll?
  ifh && ifh.flags.include?('DLL')
end
pack() click to toggle source
# File lib/pedump/pe.rb, line 25
def pack
  signature + ifh.pack + ioh.pack
end
x64?() click to toggle source
# File lib/pedump/pe.rb, line 18
def x64?
  ifh && ifh.Machine == 0x8664
end