Commit 470d0806adfd231d2cd1736d71f79d659499a970
1 parent
5c9b328c
record_base: make compatible with container substreams
Showing
1 changed file
with
24 additions
and
12 deletions
oletools/record_base.py
| ... | ... | @@ -73,6 +73,7 @@ from oletools.thirdparty import olefile |
| 73 | 73 | # Helpers |
| 74 | 74 | ############################################################################### |
| 75 | 75 | |
| 76 | +STGTY_SUBSTREAM = 10 | |
| 76 | 77 | |
| 77 | 78 | ENTRY_TYPE2STR = { |
| 78 | 79 | olefile.STGTY_EMPTY: 'empty', |
| ... | ... | @@ -80,7 +81,8 @@ ENTRY_TYPE2STR = { |
| 80 | 81 | olefile.STGTY_STREAM: 'stream', |
| 81 | 82 | olefile.STGTY_LOCKBYTES: 'lock-bytes', |
| 82 | 83 | olefile.STGTY_PROPERTY: 'property', |
| 83 | - olefile.STGTY_ROOT: 'root' | |
| 84 | + olefile.STGTY_ROOT: 'root', | |
| 85 | + STGTY_SUBSTREAM: 'substream' | |
| 84 | 86 | } |
| 85 | 87 | |
| 86 | 88 | |
| ... | ... | @@ -131,7 +133,9 @@ class OleRecordFile(olefile.OleFileIO): |
| 131 | 133 | else: |
| 132 | 134 | clz = self.stream_class_for_name(direntry.name) |
| 133 | 135 | yield clz(self._open(direntry.isectStart, direntry.size), |
| 134 | - None if is_orphan else direntry.name) | |
| 136 | + direntry.size, | |
| 137 | + None if is_orphan else direntry.name, | |
| 138 | + direntry.entry_type) | |
| 135 | 139 | |
| 136 | 140 | |
| 137 | 141 | class OleRecordStream(object): |
| ... | ... | @@ -142,10 +146,13 @@ class OleRecordStream(object): |
| 142 | 146 | abstract base class |
| 143 | 147 | """ |
| 144 | 148 | |
| 145 | - def __init__(self, stream, name): | |
| 149 | + def __init__(self, stream, size, name, stream_type): | |
| 146 | 150 | self.stream = stream |
| 151 | + self.size = size | |
| 147 | 152 | self.name = name |
| 148 | - self.size = stream.size | |
| 153 | + if stream_type not in ENTRY_TYPE2STR: | |
| 154 | + raise ValueError('Unknown stream type: {0}'.format(stream_type)) | |
| 155 | + self.stream_type = stream_type | |
| 149 | 156 | |
| 150 | 157 | def read_record_head(self): |
| 151 | 158 | """ read first few bytes of record to determine size and type |
| ... | ... | @@ -191,7 +198,7 @@ class OleRecordStream(object): |
| 191 | 198 | if fill_data or force_read: |
| 192 | 199 | data = self.stream.read(rec_size) |
| 193 | 200 | if len(data) != rec_size: |
| 194 | - raise IOError('Not enough data in stream ({0} < {1})' | |
| 201 | + raise IOError('Unexpected end of stream ({0} < {1})' | |
| 195 | 202 | .format(len(data), rec_size)) |
| 196 | 203 | else: |
| 197 | 204 | self.stream.seek(rec_size, SEEK_CUR) |
| ... | ... | @@ -199,9 +206,11 @@ class OleRecordStream(object): |
| 199 | 206 | yield rec_clz(rec_type, rec_size, other, pos, data) |
| 200 | 207 | |
| 201 | 208 | def __str__(self): |
| 202 | - return '[{2} {0} (size {1})' \ | |
| 203 | - .format(self.name or '[orphan]', self.size, | |
| 204 | - self.__class__.__name__) | |
| 209 | + return '[{0} {1} (type {2}, size {3})' \ | |
| 210 | + .format(self.__class__.__name__, | |
| 211 | + self.name or '[orphan]', | |
| 212 | + ENTRY_TYPE2STR[self.stream_type], | |
| 213 | + self.size) | |
| 205 | 214 | |
| 206 | 215 | |
| 207 | 216 | class OleSummaryInformationStream(OleRecordStream): |
| ... | ... | @@ -272,13 +281,15 @@ class OleRecordBase(object): |
| 272 | 281 | |
| 273 | 282 | |
| 274 | 283 | def test(filenames, ole_file_class=OleRecordFile, |
| 275 | - must_parse=None): | |
| 284 | + must_parse=None, do_per_record=None): | |
| 276 | 285 | """ parse all given file names and print rough structure |
| 277 | 286 | |
| 278 | 287 | if an error occurs while parsing a stream of type in must_parse, the error |
| 279 | 288 | will be raised. Otherwise a message is printed |
| 280 | 289 | """ |
| 281 | - logging.basicConfig(level=logging.DEBUG) | |
| 290 | + logging.basicConfig(level=logging.INFO) | |
| 291 | + if do_per_record is None: | |
| 292 | + do_per_record = lambda record: None | |
| 282 | 293 | if not filenames: |
| 283 | 294 | logging.info('need file name[s]') |
| 284 | 295 | return 2 |
| ... | ... | @@ -290,10 +301,11 @@ def test(filenames, ole_file_class=OleRecordFile, |
| 290 | 301 | ole = ole_file_class(filename) |
| 291 | 302 | |
| 292 | 303 | for stream in ole.iter_streams(): |
| 293 | - logging.info(stream) | |
| 304 | + logging.info(' parse ' + str(stream)) | |
| 294 | 305 | try: |
| 295 | 306 | for record in stream.iter_records(): |
| 296 | - logging.info(' {0}'.format(record)) | |
| 307 | + logging.info(' found ' + str(record)) | |
| 308 | + do_per_record(record) | |
| 297 | 309 | except Exception: |
| 298 | 310 | if not must_parse: |
| 299 | 311 | raise | ... | ... |