class Rex::PeParsey::PeBase

Constants

IMAGE_BASE_RELOCATION

Struct

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
IMAGE_BASE_RELOCATION_TYPE_OFFSET
IMAGE_DATA_DIRECTORY

Struct

typedef struct _IMAGE_DATA_DIRECTORY {
    DWORD   VirtualAddress;
    DWORD   Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
IMAGE_DATA_DIRECTORY_SIZE
IMAGE_DIRECTORY_ENTRY_ARCHITECTURE
IMAGE_DIRECTORY_ENTRY_BASERELOC
IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT
IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
IMAGE_DIRECTORY_ENTRY_COPYRIGHT
IMAGE_DIRECTORY_ENTRY_DEBUG
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT
IMAGE_DIRECTORY_ENTRY_EXCEPTION
IMAGE_DIRECTORY_ENTRY_EXPORT
IMAGE_DIRECTORY_ENTRY_GLOBALPTR
IMAGE_DIRECTORY_ENTRY_IAT
IMAGE_DIRECTORY_ENTRY_IMPORT
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG
IMAGE_DIRECTORY_ENTRY_RESOURCE
IMAGE_DIRECTORY_ENTRY_SECURITY
IMAGE_DIRECTORY_ENTRY_TLS
IMAGE_DOS_HEADER

Struct

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
IMAGE_DOS_HEADER_SIZE
IMAGE_DOS_SIGNATURE

define IMAGE_DOS_SIGNATURE 0x5A4D // MZ

IMAGE_EXPORT_DESCRIPTOR

Struct defining the export table

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
IMAGE_EXPORT_DESCRIPTOR_SIZE

sizeof(struct _IMAGE_EXPORT_DESCRIPTOR)

IMAGE_FILE_HEADER

C struct defining the PE file header

typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER_SIZE

define IMAGE_SIZEOF_FILE_HEADER 20

IMAGE_FILE_MACHINE_ALPHA64

define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64

IMAGE_FILE_MACHINE_AMD64

define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)

IMAGE_FILE_MACHINE_I386

define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.

IMAGE_FILE_MACHINE_IA64

define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64

IMAGE_IMPORT_DESCRIPTOR

Struct

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;            // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    };
    DWORD   TimeDateStamp;                  // 0 if not bound,
                                            // -1 if bound, and real date\time stamp
                                            //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
                                            // O.W. date/time stamp of DLL bound to (Old BIND)

    DWORD   ForwarderChain;                 // -1 if no forwarders
    DWORD   Name;
    DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR_SIZE
IMAGE_LOAD_CONFIG_DIRECTORY32

Struct

typedef struct {
    DWORD   Size;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   GlobalFlagsClear;
    DWORD   GlobalFlagsSet;
    DWORD   CriticalSectionDefaultTimeout;
    DWORD   DeCommitFreeBlockThreshold;
    DWORD   DeCommitTotalFreeThreshold;
    DWORD   LockPrefixTable;            // VA
    DWORD   MaximumAllocationSize;
    DWORD   VirtualMemoryThreshold;
    DWORD   ProcessHeapFlags;
    DWORD   ProcessAffinityMask;
    WORD    CSDVersion;
    WORD    Reserved1;
    DWORD   EditList;                   // VA
    DWORD   SecurityCookie;             // VA
    DWORD   SEHandlerTable;             // VA
    DWORD   SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
IMAGE_LOAD_CONFIG_DIRECTORY64

Struct

typedef struct {
    ULONG      Size;
    ULONG      TimeDateStamp;
    USHORT     MajorVersion;
    USHORT     MinorVersion;
    ULONG      GlobalFlagsClear;
    ULONG      GlobalFlagsSet;
    ULONG      CriticalSectionDefaultTimeout;
    ULONGLONG  DeCommitFreeBlockThreshold;
    ULONGLONG  DeCommitTotalFreeThreshold;
    ULONGLONG  LockPrefixTable;         // VA
    ULONGLONG  MaximumAllocationSize;
    ULONGLONG  VirtualMemoryThreshold;
    ULONGLONG  ProcessAffinityMask;
    ULONG      ProcessHeapFlags;
    USHORT     CSDVersion;
    USHORT     Reserved1;
    ULONGLONG  EditList;                // VA
    ULONGLONG  SecurityCookie;          // VA
    ULONGLONG  SEHandlerTable;          // VA
    ULONGLONG  SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
IMAGE_LOAD_TLS_DIRECTORY32

Struct

typedef struct {
    DWORD   Size;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   GlobalFlagsClear;
    DWORD   GlobalFlagsSet;
    DWORD   CriticalSectionDefaultTimeout;
    DWORD   DeCommitFreeBlockThreshold;
    DWORD   DeCommitTotalFreeThreshold;
    DWORD   LockPrefixTable;            // VA
    DWORD   MaximumAllocationSize;
    DWORD   VirtualMemoryThreshold;
    DWORD   ProcessHeapFlags;
    DWORD   ProcessAffinityMask;
    WORD    CSDVersion;
    WORD    Reserved1;
    DWORD   EditList;                   // VA
    DWORD   SecurityCookie;             // VA
    DWORD   SEHandlerTable;             // VA
    DWORD   SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
IMAGE_LOAD_TLS_DIRECTORY64

Struct

typedef struct {
    ULONG      Size;
    ULONG      TimeDateStamp;
    USHORT     MajorVersion;
    USHORT     MinorVersion;
    ULONG      GlobalFlagsClear;
    ULONG      GlobalFlagsSet;
    ULONG      CriticalSectionDefaultTimeout;
    ULONGLONG  DeCommitFreeBlockThreshold;
    ULONGLONG  DeCommitTotalFreeThreshold;
    ULONGLONG  LockPrefixTable;         // VA
    ULONGLONG  MaximumAllocationSize;
    ULONGLONG  VirtualMemoryThreshold;
    ULONGLONG  ProcessAffinityMask;
    ULONG      ProcessHeapFlags;
    USHORT     CSDVersion;
    USHORT     Reserved1;
    ULONGLONG  EditList;                // VA
    ULONGLONG  SecurityCookie;          // VA
    ULONGLONG  SEHandlerTable;          // VA
    ULONGLONG  SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
IMAGE_NT_OPTIONAL_HDR32_MAGIC

Struct

typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //

    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;

    //
    // NT additional fields.
    //

    DWORD   ImageBase;
    DWORD   SectionAlignment;
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

#define IMAGE_NT_OPTIONAL_HDR32_MAGIC      0x10b
#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER    224
IMAGE_NT_OPTIONAL_HDR64_MAGIC

define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240

IMAGE_NT_SIGNATURE

define IMAGE_NT_SIGNATURE 0x00004550 // PE00

IMAGE_NUMBEROF_DIRECTORY_ENTRIES
IMAGE_OPTIONAL_HEADER32
IMAGE_OPTIONAL_HEADER64

Struct

typedef struct _IMAGE_OPTIONAL_HEADER64 {
   USHORT      Magic;
   UCHAR       MajorLinkerVersion;
   UCHAR       MinorLinkerVersion;
   ULONG       SizeOfCode;
   ULONG       SizeOfInitializedData;
   ULONG       SizeOfUninitializedData;
   ULONG       AddressOfEntryPoint;
   ULONG       BaseOfCode;
   ULONGLONG   ImageBase;
   ULONG       SectionAlignment;
   ULONG       FileAlignment;
   USHORT      MajorOperatingSystemVersion;
   USHORT      MinorOperatingSystemVersion;
   USHORT      MajorImageVersion;
   USHORT      MinorImageVersion;
   USHORT      MajorSubsystemVersion;
   USHORT      MinorSubsystemVersion;
   ULONG       Win32VersionValue;
   ULONG       SizeOfImage;
   ULONG       SizeOfHeaders;
   ULONG       CheckSum;
   USHORT      Subsystem;
   USHORT      DllCharacteristics;
   ULONGLONG   SizeOfStackReserve;
   ULONGLONG   SizeOfStackCommit;
   ULONGLONG   SizeOfHeapReserve;
   ULONGLONG   SizeOfHeapCommit;
   ULONG       LoaderFlags;
   ULONG       NumberOfRvaAndSizes;
   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
IMAGE_ORDINAL_FLAG32
IMAGE_RUNTIME_FUNCTION_ENTRY

Struct

typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
    DWORD BeginAddress;
    DWORD EndAddress;
    DWORD UnwindInfoAddress;
} _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
IMAGE_RUNTIME_FUNCTION_ENTRY_SZ

Exception directory

IMAGE_SECTION_HEADER

Struct

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
IMAGE_SIZEOF_BASE_RELOCATION

define IMAGE_SIZEOF_BASE_RELOCATION 8

IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
IMAGE_SIZEOF_NT_OPTIONAL64_HEADER

define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b

IMAGE_SIZEOF_SECTION_HEADER

define IMAGE_SIZEOF_SECTION_HEADER 40

SUPPORTED_MACHINES
UNWIND_INFO_HEADER
UNWIND_INFO_HEADER_SZ
UNW_FLAG_CHAININFO
UNW_FLAG_EHANDLER
UNW_FLAG_UHANDLER
UWOP_ALLOC_LARGE
UWOP_ALLOC_SMALL
UWOP_PUSH_MACHFRAME
UWOP_PUSH_NONVOL
UWOP_SAVE_NONVOL
UWOP_SAVE_NONVOL_FAR
UWOP_SAVE_XMM128
UWOP_SAVE_XMM128_FAR
UWOP_SET_FPREG

Attributes

_config_header[RW]
_dos_header[RW]
_exception_header[RW]
_exports_cache[RW]
_exports_cached[RW]
_file_header[RW]
_imports_cache[RW]
_imports_cached[RW]
_isource[RW]

instance stuff

_optional_header[RW]
_relocations_cache[RW]
_relocations_cached[RW]
_resources_cache[RW]
_resources_cached[RW]
_section_headers[RW]
_tls_header[RW]
hdr[RW]
header_section[RW]
image_base[RW]
sections[RW]

Public Class Methods

_align_offset(offset, alignment) click to toggle source

Just a stupid routine to round an offset up to it’s alignment.

For example, you’re going to want this for FileAlignment and SectionAlignment, etc…

# File lib/rex/peparsey/pebase.rb, line 1133
def self._align_offset(offset, alignment)
  offset += alignment - 1
  offset -= offset % alignment
  return offset
end
_parse_dos_header(rawdata) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 134
def self._parse_dos_header(rawdata)
  return DosHeader.new(rawdata)
end
_parse_file_header(rawdata) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 212
def self._parse_file_header(rawdata)
  return FileHeader.new(rawdata)
end
_parse_optional_header(rawdata) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 570
def self._parse_optional_header(rawdata)
  case rawdata.length
    # no optional header
    when 0
      return nil

    # good, good
    when IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
      return OptionalHeader32.new(rawdata)

    when IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
      return OptionalHeader64.new(rawdata)

    # bad, bad
    else
      raise OptionalHeaderError, "I don't know this header size, #{rawdata.length}", caller
  end

end
_parse_section_headers(rawdata) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 642
def self._parse_section_headers(rawdata)
  section_headers = [ ]
  size = IMAGE_SIZEOF_SECTION_HEADER
  numsections = rawdata.length / size

  numsections.times do |i|
    data = rawdata[i * size, size]
    section_headers << SectionHeader.new(data)
  end

  return section_headers
end
new_from_file(filename, disk_backed = false) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1156
def self.new_from_file(filename, disk_backed = false)

  file = ::File.new(filename)
  file.binmode # windows... :\

  if disk_backed
    return self.new(ImageSource::Disk.new(file))
  else
    obj = new_from_string(file.read)
    file.close
    return obj
  end
end
new_from_string(data) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1170
def self.new_from_string(data)
  return self.new(ImageSource::Memory.new(data))
end

Public Instance Methods

_find_section_by_rva(rva) click to toggle source

Find a section by an RVA

# File lib/rex/peparsey/pebase.rb, line 1234
def _find_section_by_rva(rva)
  all_sections.each do |section|
    if section.contains_rva?(rva)
      return section
    end
  end

  return nil
end
_load_exception_directory() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1096
def _load_exception_directory
  @exception   = []

  exception_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_EXCEPTION]
  rva             = exception_entry.v['VirtualAddress']
  size            = exception_entry.v['Size']

  return if (rva == 0)

  data = _isource.read(rva_to_file_offset(rva), size)

  case hdr.file.Machine
    when IMAGE_FILE_MACHINE_AMD64
      count = data.length / IMAGE_RUNTIME_FUNCTION_ENTRY_SZ

      count.times { |current|
        @exception << RuntimeFunctionEntry.new(self,
          data.slice!(0, IMAGE_RUNTIME_FUNCTION_ENTRY_SZ))
      }
    else
  end

  return @exception
end
_load_exports() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1378
def _load_exports

  #
  # Get the data directory entry, size, etc
  #
  exports_entry = _optional_header['DataDirectory'][0]
  rva           = exports_entry.v['VirtualAddress']
  size          = exports_entry.v['Size']

  return nil if size == 0

  #
  # Ok, so we have the data directory, now lets parse it
  #

  directory = IMAGE_EXPORT_DESCRIPTOR.make_struct
  directory.from_s(_isource.read(rva_to_file_offset(rva), IMAGE_EXPORT_DESCRIPTOR_SIZE))

  #
  # We can have nameless exports, so we need to do the whole
  # NumberOfFunctions NumberOfNames foo
  #
  num_functions = directory.v['NumberOfFunctions']
  num_names     = directory.v['NumberOfNames']

  dllname_rva   = directory.v['Name']
  dllname       = _isource.read_asciiz(rva_to_file_offset(dllname_rva))

  # FIXME Base, etc
  fun_off       = rva_to_file_offset(directory.v['AddressOfFunctions'])
  name_off      = rva_to_file_offset(directory.v['AddressOfNames'])
  ord_off       = rva_to_file_offset(directory.v['AddressOfNameOrdinals'])
  base          = directory.v['Base']

  # Allocate the list of names
  names = Array.new(num_functions)

  #
  # Iterate the names and name/ordinal list, getting the names
  # and storing them in the name list...
  #
  num_names.times do |i|
    name_rva = _isource.read(name_off + (i * 4), 4).unpack('V')[0]
    ordinal  = _isource.read(ord_off + (i * 2), 2).unpack('v')[0]
    name     = _isource.read_asciiz(rva_to_file_offset(name_rva))

    # store the exported name in the name list
    names[ordinal] = name
  end

  exports = ExportDirectory.new(dllname, [ ], base)

  #
  # Now just iterate the functions (rvas) list..
  #
  num_functions.times do |i|
    rva      = _isource.read(fun_off + (i * 4), 4).unpack('V')[0]

    # ExportEntry.new(name, ordinal, rva)
    exports.entries << ExportEntry.new(names[i], i + base, rva)
  end

  return exports
end
_load_imports() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1307
def _load_imports
  #
  # Get the data directory entry, size, etc
  #
  imports_entry = _optional_header['DataDirectory'][1]
  rva           = imports_entry.v['VirtualAddress']
  size          = imports_entry.v['Size']

  return nil if size == 0

  #
  # Ok, so we have the data directory, now lets parse it
  #

  imports = [ ]

  descriptors_data = _isource.read(rva_to_file_offset(rva), size)

  while descriptors_data.length >= IMAGE_IMPORT_DESCRIPTOR_SIZE
    descriptor = IMAGE_IMPORT_DESCRIPTOR.make_struct
    descriptor.from_s(descriptors_data)
    descriptors_data = descriptor.leftover

    othunk = descriptor.v['OriginalFirstThunk']
    fthunk = descriptor.v['FirstThunk']

    break if fthunk == 0

    dllname = _isource.read_asciiz(rva_to_file_offset(descriptor.v['Name']))

    import = ImportDescriptor.new(dllname, [ ])

    # we prefer the Characteristics/OriginalFirstThunk...
    thunk_off = rva_to_file_offset(othunk == 0 ? fthunk : othunk)

    while (orgrva = _isource.read(thunk_off, 4).unpack('V')[0]) != 0
      hint = nil
      name = nil

      if (orgrva & IMAGE_ORDINAL_FLAG32) != 0
        hint = orgrva & 0xffff
      else
        foff = rva_to_file_offset(orgrva)
        hint = _isource.read(foff, 2).unpack('v')[0]
        name = _isource.read_asciiz(foff + 2)
      end

      import.entries << ImportEntry.new(name, hint)

      thunk_off += 4
    end

    imports << import
  end

  return imports
end
_load_relocations() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1454
def _load_relocations

  #
  # Get the data directory entry, size, etc
  #
  exports_entry = _optional_header['DataDirectory'][5]
  rva           = exports_entry.v['VirtualAddress']
  size          = exports_entry.v['Size']

  return nil if size == 0

  #
  # Ok, so we have the data directory, now lets parse it
  #

  dirdata = _isource.read(rva_to_file_offset(rva), size)

  relocdirs = [ ]

  while dirdata.length >= IMAGE_SIZEOF_BASE_RELOCATION
    header = IMAGE_BASE_RELOCATION.make_struct
    header.from_s(dirdata)
    dirdata = header.leftover

    numrelocs = (header.v['SizeOfBlock'] - IMAGE_SIZEOF_BASE_RELOCATION) / 2

    relocbase = header.v['VirtualAddress']

    relocdir = RelocationDirectory.new(relocbase, [ ])

    numrelocs.times do
      reloc = IMAGE_BASE_RELOCATION_TYPE_OFFSET.make_struct
      reloc.from_s(dirdata)
      dirdata = reloc.leftover

      typeoffset = reloc.v['TypeOffset']

      relocrva  = relocbase + (typeoffset & 0xfff)
      reloctype = (typeoffset >> 12) & 0xf

      relocdir.entries << RelocationEntry.new(relocrva, reloctype)
    end

    relocdirs << relocdir
  end

  return relocdirs
end
_load_resources() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1516
def _load_resources
  #
  # Get the data directory entry, size, etc
  #
  rsrc_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_RESOURCE]
  rva        = rsrc_entry.v['VirtualAddress']
  size       = rsrc_entry.v['Size']

  return nil if size == 0

  #
  # Ok, so we have the data directory, now lets parse it
  #
  data = _isource.read(rva_to_file_offset(rva), size)

  self._resources_cache = {}
  _parse_resource_directory(data)
end
_parse_config_header() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 831
def _parse_config_header

  #
  # Get the data directory entry, size, etc
  #
  exports_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]
  rva           = exports_entry.v['VirtualAddress']
  size          = exports_entry.v['Size']

  return nil if size == 0

  #
  # Ok, so we have the data directory, now lets parse it
  #

  dirdata = _isource.read(rva_to_file_offset(rva), size)
  klass   = (ptr_64?) ? IMAGE_LOAD_CONFIG_DIRECTORY64 : IMAGE_LOAD_CONFIG_DIRECTORY32
  header  = klass.make_struct

  header.from_s(dirdata)

  @config = ConfigHeader.new(header)
end
_parse_resource_directory(data, rname=0, rvalue=0x80000000, path='0', pname=nil) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1535
def _parse_resource_directory(data, rname=0, rvalue=0x80000000, path='0', pname=nil)

  pname = _parse_resource_name(data, rname)
  if (path.scan('/').length == 1)
    if (pname !~ /^\d+/)
      path = "/" + pname
    else
      path = "/" + _resource_lookup( (rname & ~0x80000000).to_s)
    end
  end


  rvalue &= ~0x80000000
  vals  = data[rvalue, 16].unpack('VVvvvv')

  chars = vals[0]
  tdate = vals[1]
  vers  = "#{vals[2]}#{vals[3]}"
  count = vals[4] + vals[5]

  0.upto(count-1) do |i|

    ename, evalue = data[rvalue + 16 + ( i * 8), 8].unpack('VV')
    epath = path + '/' + i.to_s

    if (ename & 0x80000000 != 0)
      pname = _parse_resource_name(data, ename)
    end

    if (evalue & 0x80000000 != 0)
      # This is a subdirectory
      _parse_resource_directory(data, ename, evalue, epath, pname)
    else
      # This is an entry
      _parse_resource_entry(data, ename, evalue, epath, pname)
    end
  end

end
_parse_resource_entry(data, rname, rvalue, path, pname) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1607
def _parse_resource_entry(data, rname, rvalue, path, pname)

  rva, size, code = data[rvalue, 12].unpack('VVV')
  lang = _parse_resource_name(data, rname)

  ent = ResourceEntry.new(
    self,
    path,
    lang,
    code,
    rva,
    size,
    pname
  )
  self._resources_cache[path] = ent
end
_parse_resource_name(data, rname) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1624
def _parse_resource_name(data, rname)
  if (rname & 0x80000000 != 0)
    rname &= ~0x80000000
    unistr = data[rname+2, 2 * data[rname,2].unpack('v')[0] ]
    unistr, trash = unistr.split(/\x00\x00/n, 2)
    return unistr ? unistr.gsub(/\x00/n, '') : nil
  end

  rname.to_s
end
_parse_tls_header() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 962
def _parse_tls_header

  #
  # Get the data directory entry, size, etc
  #
  exports_entry = _optional_header['DataDirectory'][IMAGE_DIRECTORY_ENTRY_TLS]
  rva           = exports_entry.v['VirtualAddress']
  size          = exports_entry.v['Size']

  return nil if size == 0

  #
  # Ok, so we have the data directory, now lets parse it
  #

  dirdata = _isource.read(rva_to_file_offset(rva), size)
  klass   = (ptr_64?) ? IMAGE_LOAD_TLS_DIRECTORY64 : IMAGE_LOAD_TLS_DIRECTORY32
  header  = klass.make_struct

  header.from_s(dirdata)

  @tls = TLSHeader.new(header)
end
_resource_lookup(i) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1575
def _resource_lookup(i)
  tbl = {
    '1'      => 'RT_CURSOR',
    '2'      => 'RT_BITMAP',
    '3'      => 'RT_ICON',
    '4'      => 'RT_MENU',
    '5'      => 'RT_DIALOG',
    '6'      => 'RT_STRING',
    '7'      => 'RT_FONTDIR',
    '8'      => 'RT_FONT',
    '9'      => 'RT_ACCELERATORS',
    '10'     => 'RT_RCDATA',
    '11'     => 'RT_MESSAGETABLE',
    '12'     => 'RT_GROUP_CURSOR',
    '14'     => 'RT_GROUP_ICON',
    '16'     => 'RT_VERSION',
    '17'     => 'RT_DLGINCLUDE',
    '19'     => 'RT_PLUGPLAY',
    '20'     => 'RT_VXD',
    '21'     => 'RT_ANICURSOR',
    '22'     => 'RT_ANIICON',
    '23'     => 'RT_HTML',
    '24'     => 'RT_MANIFEST',
    '32767'  => 'RT_ERROR',
    '8192'   => 'RT_NEWRESOURCE',
    '8194'   => 'RT_NEWBITMAP',
    '8196'   => 'RT_NEWMENU',
    '8197'   => 'RT_NEWDIALOG'
  }
  tbl[i] || i
end
close() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1174
def close
  _isource.close
end
config() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 856
def config
  _parse_config_header if @config.nil?
  @config
end
exception() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1122
def exception
  _load_exception_directory if @exception.nil?
  @exception
end
exports() click to toggle source

We lazily parse the exports, and then cache it

# File lib/rex/peparsey/pebase.rb, line 1370
def exports
  if !_exports_cached
    self._exports_cache  = _load_exports
    self._exports_cached = true
  end
  return _exports_cache
end
file_offset_to_rva(foffset) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1205
def file_offset_to_rva(foffset)
  if foffset < 0
    raise WtfError, "lame", caller
  end

  all_sections.each do |section|
    if section.contains_file_offset?(foffset)
      return section.file_offset_to_rva(foffset)
    end
  end

  raise WtfError, "wtf! #{foffset}", caller
end
file_offset_to_vma(foffset) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1219
def file_offset_to_vma(foffset)
  return rva_to_vma(file_offset_to_rva(foffset))
end
find_section_by_rva(rva) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1243
def find_section_by_rva(rva)
  section = _find_section_by_rva(rva)

  if !section
    raise WtfError, "Cannot find rva! #{rva}", caller
  end

  return section
end
find_section_by_vma(vma) click to toggle source

Find a section by a VMA

# File lib/rex/peparsey/pebase.rb, line 1256
def find_section_by_vma(vma)
  return find_section_by_rva(vma_to_rva(vma))
end
imports() click to toggle source

We lazily parse the imports, and then cache it

# File lib/rex/peparsey/pebase.rb, line 1299
def imports
  if !_imports_cached
    self._imports_cache  = _load_imports
    self._imports_cached = true
  end
  return _imports_cache
end
read_asciiz_rva(rva) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1282
def read_asciiz_rva(rva)
  return find_section_by_rva(rva).read_asciiz_rva(rva)
end
read_asciiz_vma(vma) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1286
def read_asciiz_vma(vma)
  return read_asciiz_rva(vma_to_rva(vma))
end
read_rva(rva, length) click to toggle source

Some convenient methods to read a vma/rva without having the section… (inefficent though I suppose…)

# File lib/rex/peparsey/pebase.rb, line 1274
def read_rva(rva, length)
  return find_section_by_rva(rva).read_rva(rva, length)
end
read_vma(vma, length) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1278
def read_vma(vma, length)
  return read_rva(vma_to_rva(vma), length)
end
relocations() click to toggle source

Base relocations in the hizzy

# File lib/rex/peparsey/pebase.rb, line 1446
def relocations
  if !_relocations_cached
    self._relocations_cache  = _load_relocations
    self._relocations_cached = true
  end
  return _relocations_cache
end
resources() click to toggle source

We lazily parse the resources, and then cache them

# File lib/rex/peparsey/pebase.rb, line 1507
def resources
  if !_resources_cached
    _load_resources
    self._resources_cached = true
  end

  return self._resources_cache
end
rva_to_file_offset(rva) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1192
def rva_to_file_offset(rva)
  all_sections.each do |section|
    if section.contains_rva?(rva)
      return section.rva_to_file_offset(rva)
    end
  end
  raise WtfError, "wtf!", caller
end
rva_to_vma(rva) click to toggle source

Random rva, vma, file offset, section offset, etc conversion routines…

# File lib/rex/peparsey/pebase.rb, line 1184
def rva_to_vma(rva)
  return rva + image_base
end
tls() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 987
def tls
  _parse_config_header if @tls.nil?
  @tls
end
update_checksum() click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1635
def update_checksum
  off = _dos_header.e_lfanew + IMAGE_FILE_HEADER_SIZE + 0x40
  _isource.rawdata[off, 4] = [0].pack('V')

  rem = _isource.size % 4
  sum_me = ''
  sum_me << _isource.rawdata
  sum_me << "\x00" * (4 - rem) if rem > 0

  cksum = 0
  sum_me.unpack('V*').each { |el|
    cksum = (cksum & 0xffffffff) + (cksum >> 32) + el
    if cksum > 2**32
      cksum = (cksum & 0xffffffff) + (cksum >> 32)
    end
  }

  cksum = (cksum & 0xffff) + (cksum >> 16)
  cksum += (cksum >> 16)
  cksum &= 0xffff

  cksum += _isource.size

  _isource.rawdata[off, 4] = [cksum].pack('V')
end
valid_rva?(rva) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1260
def valid_rva?(rva)
  _find_section_by_rva(rva) != nil
end
valid_vma?(vma) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1263
def valid_vma?(vma)
  _find_section_by_rva(vma_to_rva(vma)) != nil
end
vma_to_file_offset(vma) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1201
def vma_to_file_offset(vma)
  return rva_to_file_offset(vma_to_rva(vma))
end
vma_to_rva(vma) click to toggle source
# File lib/rex/peparsey/pebase.rb, line 1188
def vma_to_rva(vma)
  return vma - image_base
end