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 | 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 | ... | ... |