From 82bb3107927ea4f4356789843698cba652713dd6 Mon Sep 17 00:00:00 2001 From: Vincent Brillault Date: Tue, 31 Jan 2017 19:41:05 +0100 Subject: [PATCH] WIP: Separate object (ExtendedStream) from logic (functions) --- oletools/oleform.py | 354 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- oletools/olevba.py | 4 ++-- 2 files changed, 181 insertions(+), 177 deletions(-) diff --git a/oletools/oleform.py b/oletools/oleform.py index 3ad821f..0b9be2e 100644 --- a/oletools/oleform.py +++ b/oletools/oleform.py @@ -49,33 +49,43 @@ class MorphDataPropMask(Mask): 'fBorderColor', 'fSpecialEffect', 'fMouseIcon', 'fPicture', 'fAccelerator', 'UnusedBits2', 'Reserved', 'fGroupName'] -class OleUserFormParser(object): - def __init__(self, control_stream, data_stream): - self.variables = [] - self.set_stream(control_stream) - self.consume_FormControl() - self.set_stream(data_stream) - self.consume_stored_data() - - def set_stream(self, stream): +class ExtendedStream(object): + def __init__(self, stream, path): self._pos = 0 - self._frozen_pos = [] + self._jumps = [] self._stream = stream + self._path = path + + @classmethod + def open(cls, ole_file, path): + stream = ole_file.openstream(path) + return cls(stream, path) def read(self, size): self._pos += size return self._stream.read(size) - def freeze(self): - self._frozen_pos.append(self._pos) + def will_jump_to(self, size): + self._next_jump = (True, size) + return self + + def will_pad(self, pad=4): + self._next_jump = (False, pad) + return self - def unfreeze(self, size): - self.read(self._frozen_pos.pop() - self._pos + size) + def __enter__(self): + (jump_type, size) = self._next_jump + self._jumps.append((self._pos, jump_type, size)) - def unfreeze_pad(self): - align_pos = (self._pos - self._frozen_pos.pop()) % 4 - if align_pos: - self.read(4 - align_pos) + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: + (start, jump_type, size) = self._jumps.pop() + if jump_type: + self.read(size - (self._pos - start)) + else: + align = (self._pos - start) % size + if align: + self.read(size - align) def unpacks(self, format, size): return struct.unpack(format, self.read(size)) @@ -83,177 +93,174 @@ class OleUserFormParser(object): def unpack(self, format, size): return self.unpacks(format, size)[0] + def raise_error(self, reason, back=0): + raise OleFormParsingError('{0}:{1}: {2}'.format(self.path, self._pos - back)) + def check_values(self, name, format, size, expected): value = self.unpacks(format, size) if value != expected: - raise OleFormParsingError('Invalid {0} at {1}: expected {2} got {3}'.format(name, self._pos - size, str(expected), str(value))) + self.raise_error('Invalid {0}: expected {1} got {2}'.format(name, str(expected), str(value))) def check_value(self, name, format, size, expected): self.check_values(name, format, size, (expected,)) - def consume_TextProps(self): - # TextProps: [MS-OFORMS] 2.3.1 - self.check_values('TextProps (versions)', 'Q', 8) - if UUIDS == (199447043, 36753, 4558, 11376937813817407569L): - # UUID == {0BE35203-8F91-11CE-9DE300AA004BB851} - # StdFont: [MS-OFORMS] 2.4.12 - self.check_value('StdFont (version)', 'Q', 8, 11376937813817407569L) - # StdPicture: [MS-OFORMS] 2.4.13 - self.check_value('StdPicture (Preamble)', 'Q', 8) + if UUIDS == (199447043, 36753, 4558, 11376937813817407569L): + # UUID == {0BE35203-8F91-11CE-9DE300AA004BB851} + # StdFont: [MS-OFORMS] 2.4.12 + stream.check_value('StdFont (version)', 'Q', 8, 11376937813817407569L) + # StdPicture: [MS-OFORMS] 2.4.13 + stream.check_value('StdPicture (Preamble)', '> 15 else: FORM_FLAG_DONTSAVECLASSTABLE = 0 # Skip the rest of DataBlock and ExtraDataBlock - self.unfreeze(cbform) - # FormStreamData: [MS-OFORMS] 2.2.10.5 - if propmask.fMouseIcon: - self.consume_GuidAndPicture() - if propmask.fFont: - self.consume_GuidAndFont() - if propmask.fPicture: - self.consume_GuidAndPicture() - # FormSiteData: [MS-OFORMS] 2.2.10.6 - if not FORM_FLAG_DONTSAVECLASSTABLE: - CountOfSiteClassInfo = self.unpack(' 0: - remaining_SiteDepthsAndTypes -= self.consume_FormObjectDepthTypeCount() - self.unfreeze_pad() - for i in range(CountOfSites): - self.consume_OleSiteConcreteControl() - - def consume_MorphDataControl(self): - # MorphDataControl: [MS-OFORMS] 2.2.5.1 - self.check_values('MorphDataControl (versions)', '