Commit d6d204b99b70d792a7ceb2f3872f78e769323580

Authored by Christian Herdtweck
1 parent 08870d71

forward options.relaxed through VBA_Parsers to _extract_vba

Showing 1 changed file with 23 additions and 8 deletions
oletools/olevba.py
... ... @@ -1098,17 +1098,20 @@ def decompress_stream(compressed_container):
1098 1098 return decompressed_container
1099 1099  
1100 1100  
1101   -def _extract_vba(ole, vba_root, project_path, dir_path):
  1101 +def _extract_vba(ole, vba_root, project_path, dir_path, relaxed=False):
1102 1102 """
1103 1103 Extract VBA macros from an OleFileIO object.
1104 1104 Internal function, do not call directly.
1105 1105  
1106 1106 vba_root: path to the VBA root storage, containing the VBA storage and the PROJECT stream
1107 1107 vba_project: path to the PROJECT stream
  1108 + :param relaxed: If True, only create info/debug log entry if data is not as expected
  1109 + (e.g. opening substream fails); if False, raise an error in this case
1108 1110 This is a generator, yielding (stream path, VBA filename, VBA source code) for each VBA code stream
1109 1111 """
1110 1112 # Open the PROJECT stream:
1111 1113 project = ole.openstream(project_path)
  1114 + log.debug('relaxed is {}'.format(relaxed))
1112 1115  
1113 1116 # sample content of the PROJECT stream:
1114 1117  
... ... @@ -2047,7 +2050,7 @@ class VBA_Parser(object):
2047 2050 - PowerPoint 2007+ (.pptm, .ppsm)
2048 2051 """
2049 2052  
2050   - def __init__(self, filename, data=None, container=None):
  2053 + def __init__(self, filename, data=None, container=None, relaxed=False):
2051 2054 """
2052 2055 Constructor for VBA_Parser
2053 2056  
... ... @@ -2060,6 +2063,9 @@ class VBA_Parser(object):
2060 2063 :param container: str, path and filename of container if the file is within
2061 2064 a zip archive, None otherwise.
2062 2065  
  2066 + :param relaxed: if True, treat mal-formed documents and missing streams more like MS office:
  2067 + do nothing; if False (default), raise errors in these cases
  2068 +
2063 2069 raises a FileOpenError if all attemps to interpret the data header failed
2064 2070 """
2065 2071 #TODO: filename should only be a string, data should be used for the file-like object
... ... @@ -2076,6 +2082,7 @@ class VBA_Parser(object):
2076 2082 self.ole_subfiles = []
2077 2083 self.filename = filename
2078 2084 self.container = container
  2085 + self.relaxed = relaxed
2079 2086 self.type = None
2080 2087 self.vba_projects = None
2081 2088 self.vba_forms = None
... ... @@ -2183,7 +2190,9 @@ class VBA_Parser(object):
2183 2190 log.debug('Opening OLE file %s within zip' % subfile)
2184 2191 ole_data = z.open(subfile).read()
2185 2192 try:
2186   - self.ole_subfiles.append(VBA_Parser(filename=subfile, data=ole_data))
  2193 + self.ole_subfiles.append(
  2194 + VBA_Parser(filename=subfile, data=ole_data,
  2195 + relaxed=self.relaxed))
2187 2196 except FileOpenError as exc:
2188 2197 log.info('%s is not a valid OLE file (%s)' % (subfile, exc))
2189 2198 continue
... ... @@ -2220,7 +2229,9 @@ class VBA_Parser(object):
2220 2229 # TODO: handle different offsets => separate function
2221 2230 try:
2222 2231 ole_data = mso_file_extract(mso_data)
2223   - self.ole_subfiles.append(VBA_Parser(filename=fname, data=ole_data))
  2232 + self.ole_subfiles.append(
  2233 + VBA_Parser(filename=fname, data=ole_data,
  2234 + relaxed=self.relaxed))
2224 2235 except MsoExtractionError:
2225 2236 log.info('Failed decompressing an MSO container in %r - %s'
2226 2237 % (fname, MSG_OLEVBA_ISSUES))
... ... @@ -2282,7 +2293,9 @@ class VBA_Parser(object):
2282 2293  
2283 2294 # TODO: check if it is actually an OLE file
2284 2295 # TODO: get the MSO filename from content_location?
2285   - self.ole_subfiles.append(VBA_Parser(filename=fname, data=ole_data))
  2296 + self.ole_subfiles.append(
  2297 + VBA_Parser(filename=fname, data=ole_data,
  2298 + relaxed=self.relaxed))
2286 2299 except MsoExtractionError:
2287 2300 log.info('Failed decompressing an MSO container in %r - %s'
2288 2301 % (fname, MSG_OLEVBA_ISSUES))
... ... @@ -2530,8 +2543,9 @@ class VBA_Parser(object):
2530 2543 vba_stream_ids = set()
2531 2544 for vba_root, project_path, dir_path in self.vba_projects:
2532 2545 # extract all VBA macros from that VBA root storage:
2533   - for stream_path, vba_filename, vba_code in _extract_vba(self.ole_file, vba_root, project_path,
2534   - dir_path):
  2546 + for stream_path, vba_filename, vba_code in \
  2547 + _extract_vba(self.ole_file, vba_root, project_path,
  2548 + dir_path, self.relaxed):
2535 2549 # store direntry ids in a set:
2536 2550 vba_stream_ids.add(self.ole_file._find(stream_path))
2537 2551 yield (self.filename, stream_path, vba_filename, vba_code)
... ... @@ -3139,7 +3153,8 @@ def main():
3139 3153  
3140 3154 try:
3141 3155 # Open the file
3142   - vba_parser = VBA_Parser_CLI(filename, data=data, container=container)
  3156 + vba_parser = VBA_Parser_CLI(filename, data=data, container=container,
  3157 + relaxed=options.relaxed)
3143 3158  
3144 3159 if options.output_mode == 'detailed':
3145 3160 # fully detailed output
... ...