Commit d6d204b99b70d792a7ceb2f3872f78e769323580
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 |