class Rex::OLE::Storage
Attributes
header[RW]
Public Class Methods
new(filename=nil, mode=STGM_READ)
click to toggle source
# File lib/rex/ole/storage.rb, line 14 def initialize(filename=nil, mode=STGM_READ) @mode = mode @modified = nil @fd = nil @filename = nil @header = Header.new @difat = DIFAT.new self @fat = FAT.new self @minifat = MiniFAT.new self @directory = Directory.new self @ministream = Stream.new self if (filename) @filename = filename open(filename, mode) return end end
Public Instance Methods
close()
click to toggle source
# File lib/rex/ole/storage.rb, line 76 def close if (@modified) and (@mode != STGM_READ) write_to_disk end @fd.close end
create_storage(name, mode=STGM_READ, parent_stg=nil)
click to toggle source
storage manipulation functions
# File lib/rex/ole/storage.rb, line 148 def create_storage(name, mode=STGM_READ, parent_stg=nil) stg = SubStorage.new self stg.name = name parent_stg ||= @directory dlog("Adding storage #{name} to storage #{parent_stg.name}", 'rex', LEV_3) @directory.link_item(parent_stg, stg) stg end
create_stream(name, mode=STGM_WRITE, parent_stg=nil)
click to toggle source
stream manipulation functions
# File lib/rex/ole/storage.rb, line 111 def create_stream(name, mode=STGM_WRITE, parent_stg=nil) if (stm = open_stream(name, mode, parent_stg)) stm.close return nil end # eek, don't check the name for now # if we do, we cant create alot of streams (summary info for example) =begin if (not Util.name_is_valid(name)) return nil end =end stm = Stream.new self stm.name = name parent_stg ||= @directory dlog("Adding stream #{name} to storage #{parent_stg.name}", 'rex', LEV_3) @directory.link_item(parent_stg, stm) @modified = true stm end
each() { |el| ... }
click to toggle source
# File lib/rex/ole/storage.rb, line 35 def each @directory.each { |el| yield el } end
inspect()
click to toggle source
# File lib/rex/ole/storage.rb, line 83 def inspect ret = "" ret << "header = %s\n" % @header.to_s ret << "*** %u DIFAT sectors\n" % @difat.length ret << @difat.to_s << "\n" ret << "*** %u FAT sectors\n" % @fat.length ret << @fat.to_s << "\n" ret << "*** %u MiniFAT sectors:\n" % @minifat.length if (@minifat.length > 0) ret << @minifat.to_s << "\n" end ret << "*** ministream (%u bytes):\n" % @ministream.length if (@ministream.length > 0) ret << @ministream.to_s << "\n" end ret << "*** %u directory entries\n" % @directory.num_entries ret << @directory.to_s << "\n" end
name()
click to toggle source
# File lib/rex/ole/storage.rb, line 42 def name @filename end
next_mini_sector(sect)
click to toggle source
# File lib/rex/ole/storage.rb, line 383 def next_mini_sector(sect) return SECT_END if (sect >= @minifat.length) @minifat[sect] end
next_sector(sect)
click to toggle source
# File lib/rex/ole/storage.rb, line 368 def next_sector(sect) return SECT_END if (sect >= @fat.length) @fat[sect] end
open(filename, mode)
click to toggle source
# File lib/rex/ole/storage.rb, line 47 def open(filename, mode) if (mode == STGM_READWRITE) fmode = 'r+b' elsif (mode == STGM_WRITE) fmode = 'w+b' else fmode = 'rb' end @fd = File.new(filename, fmode) # don't read for new files if (mode == STGM_WRITE) # ensure there is a root write_to_disk return end # parse the header @header.read @fd @difat.read @fat.read @difat @minifat.read @directory.read # NOTE: we can't use read_stream_data here (must read using regular FAT, regardless of size) # read data using the root node's start/length @ministream << read_data(@directory) end
open_storage(name, mode=STGM_READ, parent_stg=nil)
click to toggle source
# File lib/rex/ole/storage.rb, line 157 def open_storage(name, mode=STGM_READ, parent_stg=nil) @directory.find_stream_by_name_and_type(name, STGTY_STORAGE) end
open_stream(name, mode=STGM_READ, parent_stg=nil)
click to toggle source
# File lib/rex/ole/storage.rb, line 134 def open_stream(name, mode=STGM_READ, parent_stg=nil) parent_stg ||= @directory stm = parent_stg.find_stream_by_name_and_type(name, STGTY_STREAM) if (stm) # TODO: optimize out the need to read all of the data up-front stm << read_stream_data(stm) end stm end
read_data(direntry)
click to toggle source
# File lib/rex/ole/storage.rb, line 292 def read_data(direntry) ret = "" visited = [] left = direntry.length sect = direntry.start_sector while (sect != SECT_END) if (visited.include?(sect)) raise RuntimeError, 'Sector chain loop detected (0x%08x)' % sect end visited << sect # how much to read? block = @header.sector_size block = left if (block > left) # read it. dlog("read_data - reading 0x%x bytes" % block, 'rex', LEV_3) buf = read_sector(sect, block) ret << buf left -= buf.length # done? break if (left == 0) sect = next_sector(sect) end ret end
read_data_mini(direntry)
click to toggle source
# File lib/rex/ole/storage.rb, line 321 def read_data_mini(direntry) ret = "" visited = [] left = direntry.length sect = direntry.start_sector while (sect != SECT_END) if (visited.include?(sect)) raise RuntimeError, 'Sector chain loop detected (0x%08x mini)' % sect end visited << sect # how much to read? block = @header.mini_sector_size block = left if (block > left) # read it. dlog("read_data_mini - reading 0x%x bytes" % block, 'rex', LEV_3) buf = read_mini_sector(sect, block) ret << buf left -= buf.length # done? break if (left == 0) sect = next_mini_sector(sect) end ret end
read_mini_sector(sect, len)
click to toggle source
# File lib/rex/ole/storage.rb, line 374 def read_mini_sector(sect, len) dlog("Reading mini sector 0x%x" % sect, 'rex', LEV_3) off = (@header.mini_sector_size * sect) dlog("Reading from offset 0x%x of ministream" % off, 'rex', LEV_3) @ministream.seek(off) data = @ministream.read(len) data end
read_sector(sect, len)
click to toggle source
# File lib/rex/ole/storage.rb, line 351 def read_sector(sect, len) off = ((sect + 1) * @header.sector_size) @fd.seek(off, ::IO::SEEK_SET) buf = @fd.read(len) if (not buf) if (@fd.eof?) raise RuntimeError, 'EOF while reading sector data (0x%08x)' % sect else raise RuntimeError, 'Unknown error while reading sector data (0x%08x)' % sect end end if (buf.length != len) raise RuntimeError, 'Insufficient data for sector (0x%08x): got %u of %u' % [sect, buf.length, len] end buf end
read_stream_data(direntry)
click to toggle source
# File lib/rex/ole/storage.rb, line 284 def read_stream_data(direntry) if (direntry.length < @header._ulMiniSectorCutoff) return read_data_mini(direntry) end read_data(direntry) end
write_mini_sector(sbuf, prev_sect=nil)
click to toggle source
# File lib/rex/ole/storage.rb, line 217 def write_mini_sector(sbuf, prev_sect=nil) len = sbuf.length if (len != @header.mini_sector_size) if (len < @header.mini_sector_size) sbuf = sbuf.dup sbuf << "\x00" * (@header.mini_sector_size - len) else raise RuntimeError, 'not mini sector sized!' end end idx = @minifat.allocate_sector # point the previous mini sector to here if (prev_sect) @minifat[prev_sect] = idx end write_mini_sector_raw(idx, sbuf) idx end
write_mini_sector_raw(sect, sbuf)
click to toggle source
# File lib/rex/ole/storage.rb, line 237 def write_mini_sector_raw(sect, sbuf) dlog("Writing mini sector 0x%02x" % sect, 'rex', LEV_3) @ministream << sbuf end
write_mini_stream(stm)
click to toggle source
# File lib/rex/ole/storage.rb, line 271 def write_mini_stream(stm) dlog("Writing \"%s\" to mini stream" % stm.name, 'rex', LEV_3) prev_sect = nil stm.seek(0) while (sbuf = stm.read(@header.mini_sector_size)) sect = write_mini_sector(sbuf, prev_sect) stm_start ||= sect prev_sect = sect end stm_start end
write_sector(sbuf, type=nil, prev_sect=nil)
click to toggle source
# File lib/rex/ole/storage.rb, line 188 def write_sector(sbuf, type=nil, prev_sect=nil) len = sbuf.length if (len != @header.sector_size) # pad it if less if (len < @header.sector_size) sbuf = sbuf.dup sbuf << "\x00" * (@header.sector_size - len) else raise RuntimeError, 'not sector sized!' end end # write the data idx = @fat.allocate_sector(type) # point previous sector to here if (prev_sect) @fat[prev_sect] = idx end write_sector_raw(idx, sbuf) return idx end
write_sector_raw(sect, sbuf)
click to toggle source
# File lib/rex/ole/storage.rb, line 210 def write_sector_raw(sect, sbuf) dlog("Writing sector 0x%02x" % sect, 'rex', LEV_3) @fd.seek((sect + 1) * @header.sector_size, ::IO::SEEK_SET) @fd.write(sbuf) end
write_stream(stm)
click to toggle source
# File lib/rex/ole/storage.rb, line 258 def write_stream(stm) dlog("Writing \"%s\" to regular stream" % stm.name, 'rex', LEV_3) stm_start = nil prev_sect = nil stm.seek(0) while (sbuf = stm.read(@header.sector_size)) sect = write_sector(sbuf, nil, prev_sect) stm_start ||= sect prev_sect = sect end stm_start end
write_to_disk()
click to toggle source
low-level functions
# File lib/rex/ole/storage.rb, line 165 def write_to_disk # reset FAT/DIFAT @difat = DIFAT.new self @fat = FAT.new self @header.write @fd write_user_data # NOTE: we call write_stream here since we MUST write this to # the regular stream (regardless of size) ms_start = write_stream(@ministream) @directory.set_ministream_params(ms_start, @ministream.length) @minifat.write @directory.write @fat.write(@difat) @difat.write # write it again, now that its complete @header.write @fd @fd.flush end
write_user_data()
click to toggle source
# File lib/rex/ole/storage.rb, line 244 def write_user_data @directory.each_entry { |stm| # only regular streams this pass next if (stm.type != STGTY_STREAM) if (stm.length >= @header._ulMiniSectorCutoff) stm.start_sector = write_stream(stm) else # NOTE: stm_start is a minifat value stm.start_sector = write_mini_stream(stm) end } end