Commit dd498c52938d18bde9d068ec56fbd5a617e30ecf

Authored by Christian Herdtweck
1 parent 002fca03

record_base: throw encryption error when iterating encrypted files

Sofar, most tools (like msodde) do not complain if file is encrypted, but
cannot inspect it either. That gives the user a false sense of security
which is dangerous. Raise error to make the situation clear. But only
raise when iterating records (stream names are still reliable and useful.
Showing 1 changed file with 25 additions and 2 deletions
oletools/record_base.py
... ... @@ -63,6 +63,18 @@ import logging
63 63  
64 64 import olefile
65 65  
  66 +try:
  67 + from oletools.common.errors import FileIsEncryptedError
  68 +except ImportError:
  69 + # little hack to allow absolute imports even if oletools is not installed.
  70 + PARENT_DIR = os.path.normpath(os.path.dirname(os.path.dirname(
  71 + os.path.abspath(__file__))))
  72 + if PARENT_DIR not in sys.path:
  73 + sys.path.insert(0, PARENT_DIR)
  74 + del PARENT_DIR
  75 + from oletools.common.errors import FileIsEncryptedError
  76 +from oletools import oleid
  77 +
66 78  
67 79 ###############################################################################
68 80 # Helpers
... ... @@ -112,6 +124,12 @@ class OleRecordFile(olefile.OleFileIO):
112 124 Subclass of OleFileIO!
113 125 """
114 126  
  127 + def open(self, filename, *args, **kwargs):
  128 + """Call OleFileIO.open, raise error if is encrypted."""
  129 + #super(OleRecordFile, self).open(filename, *args, **kwargs)
  130 + OleFileIO.open(self, filename, *args, **kwargs)
  131 + self.is_encrypted = oleid.OleID(self).check_encrypted().value
  132 +
115 133 @classmethod
116 134 def stream_class_for_name(cls, stream_name):
117 135 """ helper for iter_streams, must be overwritten in subclasses
... ... @@ -143,7 +161,8 @@ class OleRecordFile(olefile.OleFileIO):
143 161 stream = clz(self._open(direntry.isectStart, direntry.size),
144 162 direntry.size,
145 163 None if is_orphan else direntry.name,
146   - direntry.entry_type)
  164 + direntry.entry_type,
  165 + self.is_encrypted)
147 166 yield stream
148 167 stream.close()
149 168  
... ... @@ -156,13 +175,14 @@ class OleRecordStream(object):
156 175 abstract base class
157 176 """
158 177  
159   - def __init__(self, stream, size, name, stream_type):
  178 + def __init__(self, stream, size, name, stream_type, is_encrypted=False):
160 179 self.stream = stream
161 180 self.size = size
162 181 self.name = name
163 182 if stream_type not in ENTRY_TYPE2STR:
164 183 raise ValueError('Unknown stream type: {0}'.format(stream_type))
165 184 self.stream_type = stream_type
  185 + self.is_encrypted = is_encrypted
166 186  
167 187 def read_record_head(self):
168 188 """ read first few bytes of record to determine size and type
... ... @@ -191,6 +211,9 @@ class OleRecordStream(object):
191 211  
192 212 Stream must be positioned at start of records (e.g. start of stream).
193 213 """
  214 + if self.is_encrypted:
  215 + raise FileIsEncryptedError()
  216 +
194 217 while True:
195 218 # unpacking as in olevba._extract_vba
196 219 pos = self.stream.tell()
... ...