Class: Rex::OLE::Storage
- Inherits:
-
Object
- Object
- Rex::OLE::Storage
- Defined in:
- lib/rex/ole/storage.rb
Instance Attribute Summary collapse
-
#header ⇒ Object
Returns the value of attribute header.
Instance Method Summary collapse
- #close ⇒ Object
-
#create_storage(name, mode = STGM_READ, parent_stg = nil) ⇒ Object
storage manipulation functions.
-
#create_stream(name, mode = STGM_WRITE, parent_stg = nil) ⇒ Object
stream manipulation functions.
- #each ⇒ Object
-
#initialize(filename = nil, mode = STGM_READ) ⇒ Storage
constructor
A new instance of Storage.
- #inspect ⇒ Object
- #name ⇒ Object
- #next_mini_sector(sect) ⇒ Object
- #next_sector(sect) ⇒ Object
- #open(filename, mode) ⇒ Object
- #open_storage(name, mode = STGM_READ, parent_stg = nil) ⇒ Object
- #open_stream(name, mode = STGM_READ, parent_stg = nil) ⇒ Object
- #read_data(direntry) ⇒ Object
- #read_data_mini(direntry) ⇒ Object
- #read_mini_sector(sect, len) ⇒ Object
- #read_sector(sect, len) ⇒ Object
- #read_stream_data(direntry) ⇒ Object
- #write_mini_sector(sbuf, prev_sect = nil) ⇒ Object
- #write_mini_sector_raw(sect, sbuf) ⇒ Object
- #write_mini_stream(stm) ⇒ Object
- #write_sector(sbuf, type = nil, prev_sect = nil) ⇒ Object
- #write_sector_raw(sect, sbuf) ⇒ Object
- #write_stream(stm) ⇒ Object
-
#write_to_disk ⇒ Object
low-level functions.
- #write_user_data ⇒ Object
Constructor Details
#initialize(filename = nil, mode = STGM_READ) ⇒ Storage
Returns a new instance of Storage.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/rex/ole/storage.rb', line 15 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 |
Instance Attribute Details
#header ⇒ Object
Returns the value of attribute header.
13 14 15 |
# File 'lib/rex/ole/storage.rb', line 13 def header @header end |
Instance Method Details
#close ⇒ Object
77 78 79 80 81 82 |
# File 'lib/rex/ole/storage.rb', line 77 def close if (@modified) and (@mode != STGM_READ) write_to_disk end @fd.close end |
#create_storage(name, mode = STGM_READ, parent_stg = nil) ⇒ Object
storage manipulation functions
149 150 151 152 153 154 155 156 |
# File 'lib/rex/ole/storage.rb', line 149 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) ⇒ Object
stream manipulation functions
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/rex/ole/storage.rb', line 112 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 ⇒ Object
36 37 38 39 40 |
# File 'lib/rex/ole/storage.rb', line 36 def each @directory.each { |el| yield el } end |
#inspect ⇒ Object
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/rex/ole/storage.rb', line 84 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 ⇒ Object
43 44 45 |
# File 'lib/rex/ole/storage.rb', line 43 def name @filename end |
#next_mini_sector(sect) ⇒ Object
384 385 386 387 |
# File 'lib/rex/ole/storage.rb', line 384 def next_mini_sector(sect) return SECT_END if (sect >= @minifat.length) @minifat[sect] end |
#next_sector(sect) ⇒ Object
369 370 371 372 |
# File 'lib/rex/ole/storage.rb', line 369 def next_sector(sect) return SECT_END if (sect >= @fat.length) @fat[sect] end |
#open(filename, mode) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/rex/ole/storage.rb', line 48 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) ⇒ Object
158 159 160 |
# File 'lib/rex/ole/storage.rb', line 158 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) ⇒ Object
135 136 137 138 139 140 141 142 143 |
# File 'lib/rex/ole/storage.rb', line 135 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) ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/rex/ole/storage.rb', line 293 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) ⇒ Object
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/rex/ole/storage.rb', line 322 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) ⇒ Object
375 376 377 378 379 380 381 382 |
# File 'lib/rex/ole/storage.rb', line 375 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) ⇒ Object
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/rex/ole/storage.rb', line 352 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) ⇒ Object
285 286 287 288 289 290 291 |
# File 'lib/rex/ole/storage.rb', line 285 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) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/rex/ole/storage.rb', line 218 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) ⇒ Object
238 239 240 241 |
# File 'lib/rex/ole/storage.rb', line 238 def write_mini_sector_raw(sect, sbuf) dlog("Writing mini sector 0x%02x" % sect, 'rex', LEV_3) @ministream << sbuf end |
#write_mini_stream(stm) ⇒ Object
272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/rex/ole/storage.rb', line 272 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) ⇒ Object
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/rex/ole/storage.rb', line 189 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) ⇒ Object
211 212 213 214 215 |
# File 'lib/rex/ole/storage.rb', line 211 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) ⇒ Object
259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/rex/ole/storage.rb', line 259 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 ⇒ Object
low-level functions
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/rex/ole/storage.rb', line 166 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 ⇒ Object
245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/rex/ole/storage.rb', line 245 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 |