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,6 +73,7 @@ from oletools.thirdparty import olefile | ||
| 73 | # Helpers | 73 | # Helpers |
| 74 | ############################################################################### | 74 | ############################################################################### |
| 75 | 75 | ||
| 76 | +STGTY_SUBSTREAM = 10 | ||
| 76 | 77 | ||
| 77 | ENTRY_TYPE2STR = { | 78 | ENTRY_TYPE2STR = { |
| 78 | olefile.STGTY_EMPTY: 'empty', | 79 | olefile.STGTY_EMPTY: 'empty', |
| @@ -80,7 +81,8 @@ ENTRY_TYPE2STR = { | @@ -80,7 +81,8 @@ ENTRY_TYPE2STR = { | ||
| 80 | olefile.STGTY_STREAM: 'stream', | 81 | olefile.STGTY_STREAM: 'stream', |
| 81 | olefile.STGTY_LOCKBYTES: 'lock-bytes', | 82 | olefile.STGTY_LOCKBYTES: 'lock-bytes', |
| 82 | olefile.STGTY_PROPERTY: 'property', | 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,7 +133,9 @@ class OleRecordFile(olefile.OleFileIO): | ||
| 131 | else: | 133 | else: |
| 132 | clz = self.stream_class_for_name(direntry.name) | 134 | clz = self.stream_class_for_name(direntry.name) |
| 133 | yield clz(self._open(direntry.isectStart, direntry.size), | 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 | class OleRecordStream(object): | 141 | class OleRecordStream(object): |
| @@ -142,10 +146,13 @@ class OleRecordStream(object): | @@ -142,10 +146,13 @@ class OleRecordStream(object): | ||
| 142 | abstract base class | 146 | abstract base class |
| 143 | """ | 147 | """ |
| 144 | 148 | ||
| 145 | - def __init__(self, stream, name): | 149 | + def __init__(self, stream, size, name, stream_type): |
| 146 | self.stream = stream | 150 | self.stream = stream |
| 151 | + self.size = size | ||
| 147 | self.name = name | 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 | def read_record_head(self): | 157 | def read_record_head(self): |
| 151 | """ read first few bytes of record to determine size and type | 158 | """ read first few bytes of record to determine size and type |
| @@ -191,7 +198,7 @@ class OleRecordStream(object): | @@ -191,7 +198,7 @@ class OleRecordStream(object): | ||
| 191 | if fill_data or force_read: | 198 | if fill_data or force_read: |
| 192 | data = self.stream.read(rec_size) | 199 | data = self.stream.read(rec_size) |
| 193 | if len(data) != rec_size: | 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 | .format(len(data), rec_size)) | 202 | .format(len(data), rec_size)) |
| 196 | else: | 203 | else: |
| 197 | self.stream.seek(rec_size, SEEK_CUR) | 204 | self.stream.seek(rec_size, SEEK_CUR) |
| @@ -199,9 +206,11 @@ class OleRecordStream(object): | @@ -199,9 +206,11 @@ class OleRecordStream(object): | ||
| 199 | yield rec_clz(rec_type, rec_size, other, pos, data) | 206 | yield rec_clz(rec_type, rec_size, other, pos, data) |
| 200 | 207 | ||
| 201 | def __str__(self): | 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 | class OleSummaryInformationStream(OleRecordStream): | 216 | class OleSummaryInformationStream(OleRecordStream): |
| @@ -272,13 +281,15 @@ class OleRecordBase(object): | @@ -272,13 +281,15 @@ class OleRecordBase(object): | ||
| 272 | 281 | ||
| 273 | 282 | ||
| 274 | def test(filenames, ole_file_class=OleRecordFile, | 283 | def test(filenames, ole_file_class=OleRecordFile, |
| 275 | - must_parse=None): | 284 | + must_parse=None, do_per_record=None): |
| 276 | """ parse all given file names and print rough structure | 285 | """ parse all given file names and print rough structure |
| 277 | 286 | ||
| 278 | if an error occurs while parsing a stream of type in must_parse, the error | 287 | if an error occurs while parsing a stream of type in must_parse, the error |
| 279 | will be raised. Otherwise a message is printed | 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 | if not filenames: | 293 | if not filenames: |
| 283 | logging.info('need file name[s]') | 294 | logging.info('need file name[s]') |
| 284 | return 2 | 295 | return 2 |
| @@ -290,10 +301,11 @@ def test(filenames, ole_file_class=OleRecordFile, | @@ -290,10 +301,11 @@ def test(filenames, ole_file_class=OleRecordFile, | ||
| 290 | ole = ole_file_class(filename) | 301 | ole = ole_file_class(filename) |
| 291 | 302 | ||
| 292 | for stream in ole.iter_streams(): | 303 | for stream in ole.iter_streams(): |
| 293 | - logging.info(stream) | 304 | + logging.info(' parse ' + str(stream)) |
| 294 | try: | 305 | try: |
| 295 | for record in stream.iter_records(): | 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 | except Exception: | 309 | except Exception: |
| 298 | if not must_parse: | 310 | if not must_parse: |
| 299 | raise | 311 | raise |