Parent

Class/Module Index [+]

Quicksearch

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 18
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 80
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 152
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 115
        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)
                if (not Util.name_is_valid(name))
                        return nil
                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() click to toggle source
# File lib/rex/ole/storage.rb, line 39
def each
        @directory.each { |el|
                yield el
        }
end
inspect() click to toggle source
# File lib/rex/ole/storage.rb, line 87
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 46
def name
        @filename
end
next_mini_sector(sect) click to toggle source
# File lib/rex/ole/storage.rb, line 387
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 372
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 51
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 161
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 138
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 296
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 325
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 378
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 355
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 288
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 221
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 241
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 275
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 192
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 214
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 262
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 169
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 248
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

[Validate]

Generated with the Darkfish Rdoc Generator 2.