class Rex::OLE::Directory

This class serves as the root directory entry in addition to an abstraction around the concept of a directory as a whole.

Attributes

num_entries[RW]

XXX: num_entries is not maintained once a stream/storage is added!

Public Class Methods

new(stg) click to toggle source
Calls superclass method
# File lib/rex/ole/directory.rb, line 21
def initialize(stg)
  super

  @num_entries = 1
end

Public Instance Methods

each_entry(&block) click to toggle source
# File lib/rex/ole/directory.rb, line 35
def each_entry(&block)
  yield_entries(self, &block)
end
flatten_tree(entries, parent) click to toggle source

NOTE: this may not be necessary if we were to use each_entry

# File lib/rex/ole/directory.rb, line 168
def flatten_tree(entries, parent)
  entries << parent
  parent.each { |el|
    flatten_tree(entries, el)
  }
end
from_s(sid, buf) click to toggle source

low-level functions

Calls superclass method
# File lib/rex/ole/directory.rb, line 81
def from_s(sid, buf)
  super

  if (@_sidRightSib != DIR_NOSTREAM)
    raise RuntimeError, 'Root Entry is invalid! (has right sibling)'
  end
  if (@_sidLeftSib != DIR_NOSTREAM)
    raise RuntimeError, 'Root Entry is invalid! (has left sibling)'
  end
end
populate_children(entries, parent, sid) click to toggle source

recursively add entries to their proper parents :)

# File lib/rex/ole/directory.rb, line 152
def populate_children(entries, parent, sid)
  node = entries[sid]
  dlog("populate_children(entries, \"#{parent.name}\", #{sid}) - node: #{node.name}", 'rex', LEV_3)
  parent << node
  if (node.type == STGTY_STORAGE) and (node._sidChild != DIR_NOSTREAM)
    populate_children(entries, node, node._sidChild)
  end
  if (node._sidLeftSib != DIR_NOSTREAM)
    populate_children(entries, parent, node._sidLeftSib)
  end
  if (node._sidRightSib != DIR_NOSTREAM)
    populate_children(entries, parent, node._sidRightSib)
  end
end
read() click to toggle source
# File lib/rex/ole/directory.rb, line 92
def read
  @children = []
  visited = []
  entries = []
  root_node = nil
  sect = @stg.header._sectDirStart
  while (sect != SECT_END)

    if (visited.include?(sect))
      raise RuntimeError, 'Sector chain loop detected (0x%08x)' % sect
    end
    visited << sect

    sbuf = @stg.read_sector(sect, @stg.header.sector_size)
    while (sbuf.length >= DIRENTRY_SZ)
      debuf = sbuf.slice!(0, DIRENTRY_SZ)

      type = Util.get8(debuf, 0x42)
      case type
      when STGTY_ROOT
        if (entries.length != 0)
          raise RuntimeError, 'Root Entry found, but not first encountered!'
        end
        if (root_node)
          raise RuntimeError, 'Multiple root directory sectors detected (0x%08x)' % sect
        end
        de = self
        root_node = de

      when STGTY_STORAGE
        de = SubStorage.new @stg

      when STGTY_STREAM
        de = Stream.new @stg

      when STGTY_INVALID
        # skip invalid entries
        next

      else
        raise RuntimeError, 'Unsupported directory entry type (0x%02x)' % type
      end

      # read content
      de.from_s(entries.length, debuf)
      entries << de
    end
    sect = @stg.next_sector(sect)
  end

  @num_entries = entries.length

  # sort out the tree structure, starting with the root
  if (@_sidChild != DIR_NOSTREAM)
    populate_children(entries, root_node, @_sidChild)
  end
end
set_ministream_params(start, size) click to toggle source
# File lib/rex/ole/directory.rb, line 40
def set_ministream_params(start, size)
  @_sectStart = start
  @_ulSize = size
end
write() click to toggle source
# File lib/rex/ole/directory.rb, line 176
def write
  # flatten the directory again
  entries = []
  flatten_tree(entries, self)
  dlog("flattened tree has #{entries.length} entries...", 'rex', LEV_3)

  # count directory sectors
  ds_count = entries.length / 4
  if ((entries.length % 4) > 0)
    # one more sector to hold the rest
    ds_count += 1
  end

  # put the root entry first
  sbuf = self.pack

  # add the rest
  prev_sect = nil
  dir_start = nil
  entries.each { |de|
    # we already got the root entry, no more!
    next if (de.type == STGTY_ROOT)

    dir = de.pack
    dlog("writing dir entry #{de.name}", 'rex', LEV_3)
    sbuf << dir

    if (sbuf.length == @stg.header.sector_size)
      # we have a full sector, add it!
      sect = @stg.write_sector(sbuf, nil, prev_sect)
      prev_sect = sect
      dir_start ||= sect
      # reset..
      sbuf = ""
    end
  }

  # still a partial sector left?
  if (sbuf.length > 0)
    # add it! (NOTE: it will get padded with nul bytes if its not sector sized)
    sect = @stg.write_sector(sbuf, nil, prev_sect)
    prev_sect = sect
    dir_start ||= sect
  end

  @stg.header._sectDirStart = dir_start
end
yield_entries(de, &block) click to toggle source

woop, recursive each

# File lib/rex/ole/directory.rb, line 29
def yield_entries(de, &block)
  block.call(de)
  de.each { |el|
    yield_entries(el, &block)
  }
end