class Rex::PeScan::Analyze::Information

Attributes

pe[RW]

Public Class Methods

new(pe) click to toggle source
# File lib/rex/pescan/analyze.rb, line 74
def initialize(pe)
  self.pe = pe
end

Public Instance Methods

add_fields(tbl, obj, fields) click to toggle source
# File lib/rex/pescan/analyze.rb, line 78
def add_fields(tbl, obj, fields)
  fields.each do |name|
    begin
      tbl << [name, "0x%.8x" % obj.send(name)]
    rescue ::NoMethodError => e
      $stderr.puts "Invalid field #{name}"
    end
  end
end
scan(param) click to toggle source
# File lib/rex/pescan/analyze.rb, line 88
def scan(param)

  $stdout.puts "\n\n"

  tbl = table("Image Headers", ['Name', 'Value'])
  add_fields(tbl, pe.hdr.file, %W{
    Characteristics
    SizeOfOptionalHeader
    PointerToSymbolTable
    TimeDateStamp
    NumberOfSections
    Machine
  })
  $stdout.puts tbl.to_s
  $stdout.puts "\n\n"

  tbl = table("Optional Image Headers", ['Name', 'Value'])
  add_fields(tbl, pe.hdr.opt, %W{
    ImageBase
    Magic
    MajorLinkerVersion
    MinorLinkerVersion
    SizeOfCode
    SizeOfInitializeData
    SizeOfUninitializeData
    AddressOfEntryPoint
    BaseOfCode
    BaseOfData
    SectionAlignment
    FileAlignment
    MajorOperatingSystemVersion
    MinorOperatingSystemVersion
    MajorImageVersion
    MinorImageVersion
    MajorSubsystemVersion
    MinorSubsystemVersion
    Win32VersionValue
    SizeOfImage
    SizeOfHeaders
    CheckSum
    Subsystem
    DllCharacteristics
    SizeOfStackReserve
    SizeOfStackCommit
    SizeOfHeapReserve
    SizeOfHeapCommit
    LoaderFlags
    NumberOfRvaAndSizes
  })

  $stdout.puts tbl.to_s
  $stdout.puts "\n\n"

  # Get DllCharacteristics (in Integer)
  dllcharacteristics = pe.hdr.opt.struct[23].value

  if (dllcharacteristics > 0)
    tbl = table("DllCharacteristics", ['Flag', 'Value'])

    # http://msdn.microsoft.com/en-us/library/ms680339(v=vs.85).aspx
    traits = {
      :ASLR      => 'False',  #IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
      :Integrity => 'False',  #IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
      :NX        => 'False',  #IMAGE_DLLCHARACTERISTICS_NX_COMPAT
      :Isolation => 'False',  #IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
      :SEH       => 'False',  #IMAGE_DLLCHARACTERISTICS_NO_SEH
      :Bind      => 'False',  #IMAGE_DLLCHARACTERISTICS_NO_BIND
      :WDM       => 'False',  #IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
      :Terminal  => 'False'   #IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
    }

    # Convert integer to an bit array
    c_bits = ("%32d" %dllcharacteristics.to_s(2)).split('').map { |e| e.to_i }.reverse

    # Check characteristics
    traits[:ASLR]      = 'True' if c_bits[6]  == 1  #0x0040
    traits[:Integrity] = 'True' if c_bits[7]  == 1  #0x0080
    traits[:NX]        = 'True' if c_bits[8]  == 1  #0x0100
    traits[:Isolation] = 'True' if c_bits[9]  == 1  #0x0200
    traits[:SEH]       = 'True' if c_bits[10] == 1  #0x0400
    traits[:Bind]      = 'True' if c_bits[11] == 1  #0x0800
    traits[:WDM]       = 'True' if c_bits[13] == 1  #2000
    traits[:Terminal]  = 'True' if c_bits[15] == 1  #0x8000

    # Putting results to table
    traits.each do |trait_name, trait_value|
      tbl << [trait_name, trait_value]
    end

    $stdout.puts tbl.to_s
    $stdout.puts "\n\n"
  end

  if (pe.exports)
    tbl = table("Exported Functions", ['Ordinal', 'Name', 'Address'])
    pe.exports.entries.each do |ent|
      tbl << [ent.ordinal, ent.name, "0x%.8x" % pe.rva_to_vma(ent.rva)]
    end
    $stdout.puts tbl.to_s
    $stdout.puts "\n\n"
  end

  # Rex::PeParsey::Pe doesn't seem to give us any offset information for each function,
  # which makes it difficult to calculate the actual addresses for them. So instead we
  # are using Metasm::COFF::ImportDirectory to do this task.  The ability to see
  # addresses is mainly for ROP.
  if (pe.imports)
    tbl = table("Imported Functions", ['Library', 'Address', 'Ordinal', 'Name'])
    exefmt = Metasm::AutoExe.orshellcode{ Metasm.const_get('x86_64').new }
    exe = exefmt.decode_file(pe._isource.file.path)
    ibase = pe.image_base
    exe_imports = exe.imports
    exe_imports.each do |lib|
      lib_name   = lib.libname
      ini_offset = lib.iat_p
      func_table = lib.imports
      offset     = 0
      func_table.each do |func|
        func_addr = "0x%08x" %(ibase + ini_offset + offset)
        tbl << [lib_name, func_addr, func.hint, func.name]
        offset += 4
      end
    end

    $stdout.puts tbl.to_s
    $stdout.puts "\n\n"
  end

  if(pe.config)
    tbl = table("Configuration Header", ['Name', 'Value'])
    add_fields(tbl, pe.config, %W{
      Size
      TimeDateStamp
      MajorVersion
      MinorVersion
      GlobalFlagsClear
      GlobalFlagsSet
      CriticalSectionDefaultTimeout
      DeCommitFreeBlockThreshold
      DeCommitTotalFreeThreshold
      LockPrefixTable
      MaximumAllocationSize
      VirtualMemoryThreshold
      ProcessAffinityMask
      ProcessHeapFlags
      CSDVersion
      Reserved1
      EditList
      SecurityCookie
      SEHandlerTable
      SEHandlerCount
    })
    $stdout.puts tbl.to_s
    $stdout.puts "\n\n"
  end


  if(pe.resources)
    tbl = table("Resources", ['ID', 'Language', 'Code Page', 'Size', 'Name'])
    pe.resources.keys.sort.each do |rkey|
      res = pe.resources[rkey]
      tbl << [rkey, res.lang, res.code, res.size, res.file]
    end
    $stdout.puts tbl.to_s
    $stdout.puts "\n\n"
  end

  tbl = table("Section Header", ["Name", "VirtualAddress", "SizeOfRawData", "Characteristics"])
  pe.sections.each do |sec|
    tbl << [ sec.name, *[sec.vma, sec.raw_size, sec.flags].map{|x| "0x%.8x" % x} ]
  end
  $stdout.puts tbl.to_s
  $stdout.puts "\n\n"

end
table(name, cols) click to toggle source
# File lib/rex/pescan/analyze.rb, line 264
def table(name, cols)
  Rex::Ui::Text::Table.new(
    'Header'  => name,
    'Columns' => cols
  )
end