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,17 +1098,20 @@ def decompress_stream(compressed_container):
1098 return decompressed_container 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 Extract VBA macros from an OleFileIO object. 1103 Extract VBA macros from an OleFileIO object.
1104 Internal function, do not call directly. 1104 Internal function, do not call directly.
1105 1105
1106 vba_root: path to the VBA root storage, containing the VBA storage and the PROJECT stream 1106 vba_root: path to the VBA root storage, containing the VBA storage and the PROJECT stream
1107 vba_project: path to the PROJECT stream 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 This is a generator, yielding (stream path, VBA filename, VBA source code) for each VBA code stream 1110 This is a generator, yielding (stream path, VBA filename, VBA source code) for each VBA code stream
1109 """ 1111 """
1110 # Open the PROJECT stream: 1112 # Open the PROJECT stream:
1111 project = ole.openstream(project_path) 1113 project = ole.openstream(project_path)
  1114 + log.debug('relaxed is {}'.format(relaxed))
1112 1115
1113 # sample content of the PROJECT stream: 1116 # sample content of the PROJECT stream:
1114 1117
@@ -2047,7 +2050,7 @@ class VBA_Parser(object): @@ -2047,7 +2050,7 @@ class VBA_Parser(object):
2047 - PowerPoint 2007+ (.pptm, .ppsm) 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 Constructor for VBA_Parser 2055 Constructor for VBA_Parser
2053 2056
@@ -2060,6 +2063,9 @@ class VBA_Parser(object): @@ -2060,6 +2063,9 @@ class VBA_Parser(object):
2060 :param container: str, path and filename of container if the file is within 2063 :param container: str, path and filename of container if the file is within
2061 a zip archive, None otherwise. 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 raises a FileOpenError if all attemps to interpret the data header failed 2069 raises a FileOpenError if all attemps to interpret the data header failed
2064 """ 2070 """
2065 #TODO: filename should only be a string, data should be used for the file-like object 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,6 +2082,7 @@ class VBA_Parser(object):
2076 self.ole_subfiles = [] 2082 self.ole_subfiles = []
2077 self.filename = filename 2083 self.filename = filename
2078 self.container = container 2084 self.container = container
  2085 + self.relaxed = relaxed
2079 self.type = None 2086 self.type = None
2080 self.vba_projects = None 2087 self.vba_projects = None
2081 self.vba_forms = None 2088 self.vba_forms = None
@@ -2183,7 +2190,9 @@ class VBA_Parser(object): @@ -2183,7 +2190,9 @@ class VBA_Parser(object):
2183 log.debug('Opening OLE file %s within zip' % subfile) 2190 log.debug('Opening OLE file %s within zip' % subfile)
2184 ole_data = z.open(subfile).read() 2191 ole_data = z.open(subfile).read()
2185 try: 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 except FileOpenError as exc: 2196 except FileOpenError as exc:
2188 log.info('%s is not a valid OLE file (%s)' % (subfile, exc)) 2197 log.info('%s is not a valid OLE file (%s)' % (subfile, exc))
2189 continue 2198 continue
@@ -2220,7 +2229,9 @@ class VBA_Parser(object): @@ -2220,7 +2229,9 @@ class VBA_Parser(object):
2220 # TODO: handle different offsets => separate function 2229 # TODO: handle different offsets => separate function
2221 try: 2230 try:
2222 ole_data = mso_file_extract(mso_data) 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 except MsoExtractionError: 2235 except MsoExtractionError:
2225 log.info('Failed decompressing an MSO container in %r - %s' 2236 log.info('Failed decompressing an MSO container in %r - %s'
2226 % (fname, MSG_OLEVBA_ISSUES)) 2237 % (fname, MSG_OLEVBA_ISSUES))
@@ -2282,7 +2293,9 @@ class VBA_Parser(object): @@ -2282,7 +2293,9 @@ class VBA_Parser(object):
2282 2293
2283 # TODO: check if it is actually an OLE file 2294 # TODO: check if it is actually an OLE file
2284 # TODO: get the MSO filename from content_location? 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 except MsoExtractionError: 2299 except MsoExtractionError:
2287 log.info('Failed decompressing an MSO container in %r - %s' 2300 log.info('Failed decompressing an MSO container in %r - %s'
2288 % (fname, MSG_OLEVBA_ISSUES)) 2301 % (fname, MSG_OLEVBA_ISSUES))
@@ -2530,8 +2543,9 @@ class VBA_Parser(object): @@ -2530,8 +2543,9 @@ class VBA_Parser(object):
2530 vba_stream_ids = set() 2543 vba_stream_ids = set()
2531 for vba_root, project_path, dir_path in self.vba_projects: 2544 for vba_root, project_path, dir_path in self.vba_projects:
2532 # extract all VBA macros from that VBA root storage: 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 # store direntry ids in a set: 2549 # store direntry ids in a set:
2536 vba_stream_ids.add(self.ole_file._find(stream_path)) 2550 vba_stream_ids.add(self.ole_file._find(stream_path))
2537 yield (self.filename, stream_path, vba_filename, vba_code) 2551 yield (self.filename, stream_path, vba_filename, vba_code)
@@ -3139,7 +3153,8 @@ def main(): @@ -3139,7 +3153,8 @@ def main():
3139 3153
3140 try: 3154 try:
3141 # Open the file 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 if options.output_mode == 'detailed': 3159 if options.output_mode == 'detailed':
3145 # fully detailed output 3160 # fully detailed output