def get_report(self): """ Return oletools report or create if not already cached. """ if self.sample.oletools_report is not None: return self.sample.oletools_report report = { 'autoexec': [], 'suspicious': [], } file_path = self.sample.file_path try: vbaparser = VBA_Parser(file_path) # VBA_Parser reports macros for office documents report['has_macros'] = vbaparser.detect_vba_macros( ) or vbaparser.detect_xlm_macros() try: report['vba'] = vbaparser.reveal() except TypeError: # office document with no macros pass all_macros = vbaparser.extract_all_macros() if (report['has_macros'] and len(all_macros) == 1 and isinstance(all_macros[0], tuple) and len(all_macros[0]) >= 3 and all_macros[0][2] == file_path): logger.warning( "Buggy oletools version detected, result overridden. May " "lead to false negatives, please update to fixed version") report['has_macros'] = False if vbaparser.detect_vba_macros(): vb_code = vbaparser.extract_all_macros() for (_, _, _, c) in vb_code: autoexec = detect_autoexec(c) if len(autoexec) >= 1: report['autoexec'].append(autoexec[0]) suspicious = detect_suspicious(c) if len(suspicious) >= 1: report['suspicious'].append(suspicious[0]) vbaparser.close() except IOError: raise except (TypeError, FileOpenError): # The given file is not an office document. pass except Exception as error: logger.exception(error) report = OletoolsReport(report) self.sample.register_oletools_report(report) return report
def compile_input_file(input_file: str) -> Program: path = Path(input_file) if path.is_dir(): # A directory must be a project containing VBA source files return Compiler.compile_project(input_file) with open(input_file, "rb") as f: content = f.read() # Try to deserialize an already compiled program try: serializer = Serializer() obj = serializer.deserialize(content) if type(obj) == Program: return obj except SerializationError: pass # Compile an Office document or VBA source files units = [] if magic_from_buffer(content, mime=True) == "text/plain": if not input_file.endswith(".vbs"): input_file += ".vbs" units.append(Unit.from_content(content.decode("utf-8"), input_file)) else: vba_parser = VBA_Parser(input_file, data=content) for _, _, vba_filename, vba_code in vba_parser.extract_all_macros(): units.append(Unit.from_content(vba_code, vba_filename)) return Compiler.compile_units(units)
def extract_macros_from_office2003(fullpath, fileobj=None): ''' :return: [(host_fullpath, filename_from_host, data), ... ] ''' from oletools.olevba import VBA_Parser vp = VBA_Parser(fullpath, data=fileobj.read() if fileobj else None) r = [] try: if vp.detect_vba_macros(): macros = vp.extract_all_macros() assert (macros ) # macros detect, if cannot extact, must be error occured if macros: for (subfullpath, stream_path, vba_filename, vba_code) in macros: a = os.path.basename(fullpath) b = os.path.basename(subfullpath) vba_filename += u'.vba' sub = (io_text_arg(fullpath), io_text_arg(vba_filename if a == b else u'{0}_{1}'. format(b, vba_filename)), vba_code) r.append(sub) except: pass finally: vp.close() return r
def get_macro(self): """ Get Macros from an Office file and write them to a text file """ try: self.mk_tmp_dir() print "Getting Macros from {}".format(self.file) vb = VBA_Parser(self.file, relaxed=True) if vb.detect_vba_macros(): with open("{}{}macros.txt".format(self.tmp_dir, os.sep), "w") as macro_file: for (subfilename, stream_path, vba_filename, vba_code) in vb.extract_all_macros(): macro_file.write(vba_code) except Exception as e: print "get_macro Exception: {}".format(e)
def parse_vba(file): print_output(file, '\n\n-----------------------------------------\n[Analyzing with olevba]\n-----------------------------------------\n', 'text') ole_macro_result = 'no vb-macro' has_macros = False indicators = [] macro_indicators = [] vbaparser = VBA_Parser(filescanner_proc_dir+file) # Check for Macros if not vbaparser.detect_vba_macros(): print_output(file, '[-] No Macros Found', 'text') return has_macros, ole_macro_result, indicators if True: print_output(file, '[-] MACROS FOUND', 'text') has_macros = True ole_macro_result = 'VB-MACRO FOUND' # Variable to be passed to MacroRaptor vba_code_all_modules = '' for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_all_macros(): vba_code_all_modules += vba_code + '\n' for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): print_output(file, '\nOLE Stream: {0}'.format(string_clean(stream_path)), 'text') print_output(file, 'VBA Filename: {0}'.format(string_clean(vba_filename)), 'text') # Analyse the VBA Code results = vbaparser.analyze_macros(show_decoded_strings=True) for kw_type, keyword, description in results: # Add IOC detections to indicators list if kw_type == 'IOC': indicators.append(description+': '+keyword) print_output(file, '{} - {} - {}'.format(kw_type, keyword, description), 'shell') else: print_output(file, '{} - {} - {}'.format(kw_type, keyword, description), 'text') # Deobfusgate and return macro code # print_output(file, '\n'+vbaparser.reveal(), 'text') # Print number of items in each category and append to indicators list print_output(file, '', 'shell') print_output(file, 'AutoExec keywords: {}'.format(vbaparser.nb_autoexec), 'shell') if vbaparser.nb_autoexec != 0: indicators.append('AutoExec keywords: {}'.format(vbaparser.nb_autoexec)) print_output(file, 'Suspicious keywords: {}'.format(vbaparser.nb_suspicious), 'shell') if vbaparser.nb_suspicious != 0: indicators.append('Suspicious keywords: {}'.format(vbaparser.nb_suspicious)) print_output(file, 'IOCs: {}'.format(vbaparser.nb_iocs), 'shell') print_output(file, 'Hex obfuscated strings: {}'.format(vbaparser.nb_hexstrings), 'shell') if vbaparser.nb_hexstrings != 0: indicators.append('Hex obfuscated strings: {}'.format(vbaparser.nb_hexstrings)) print_output(file, 'Base64 obfuscated strings: {}'.format(vbaparser.nb_base64strings), 'shell') if vbaparser.nb_base64strings != 0: indicators.append('Base64 obfuscated strings: {}'.format(vbaparser.nb_base64strings)) print_output(file, 'Dridex obfuscated strings: {}'.format(vbaparser.nb_dridexstrings), 'shell') if vbaparser.nb_dridexstrings != 0: indicators.append('Dridex obfuscated strings: {}'.format(vbaparser.nb_dridexstrings)) print_output(file, 'VBA obfuscated strings: {}'.format(vbaparser.nb_vbastrings), 'shell') if vbaparser.nb_vbastrings != 0: indicators.append('VBA obfuscated strings: {}'.format(vbaparser.nb_vbastrings)) # Update indicators list with matches from MRaptor macro_indicators = scan_macro(file, vba_code_all_modules) indicators = indicators + macro_indicators # Use oledump to gather VBA code for archiving oledump_scan(file, '-p plugin_vba_summary.py') # Close the file vbaparser.close() return has_macros, ole_macro_result, indicators
def get_report(self): """ Return oletools report or create if not already cached. """ if self.sample.oletools_report is not None: return self.sample.oletools_report report = { 'autoexec': [], 'suspicious' : [], } filename = self.sample.filename try: vbaparser = VBA_Parser(filename, data=self.sample.content) # VBA_Parser reports macros for office documents report['has_macros'] = vbaparser.detect_vba_macros() or vbaparser.detect_xlm_macros() try: report['vba'] = vbaparser.reveal() except TypeError: # office document with no macros pass # When called on an empty or text document oletools will falsely # report that it contains macros and returns a one item list of # macros which contains only the filename again. # # Oletool assume the submitted file is the plain text macro if # it can not determine another file type. # # Add a workaround to detect this behaviour and override the # result. all_macros = vbaparser.extract_all_macros() if (report['has_macros'] and len(all_macros) == 1 and isinstance(all_macros[0], tuple) and len(all_macros[0]) >= 3 and all_macros[0][2] == filename): report['has_macros'] = False if vbaparser.detect_vba_macros(): vb_code = vbaparser.extract_all_macros() for (_, _, _, c) in vb_code: autoexec = detect_autoexec(c) if len(autoexec) >= 1: report['autoexec'].extend(autoexec) suspicious = detect_suspicious(c) if len(suspicious) >= 1: report['suspicious'].extend(suspicious) vbaparser.close() except IOError: raise except (TypeError, FileOpenError): # The given file is not an office document. pass except Exception as error: logger.exception(error) report = OletoolsReport(report) self.sample.register_oletools_report(report) return report