def _get_vba_parser(data): """Get an olevba VBA_Parser object for reading an Office file. This handles regular Office files and HTA files with VBScript script elements. @param data (str) The file contents for which to generate a VBA_Parser. @return (VBA_Parser object) On success, the olevba VBA_Parser object for the given file contents. On error, None. """ # First just try the most common case where olevba can directly get the VBA. vba = None try: vba = VBA_Parser('', data, relaxed=True) except Exception as e: if (log.getEffectiveLevel() == logging.DEBUG): log.debug("Creating VBA_PArser() Failed. Trying as HTA. " + safe_str_convert(e)) # If that did not work see if we can pull HTA wrapped VB from the data. extracted_data = get_vb_contents_from_hta(data) # If this throws an exception it will get passed up. vba = VBA_Parser('', extracted_data, relaxed=True) # Return the vba parser. return vba
def EXTRACT_VBA_MACRO(s, buff): EXTRACT_MACRO = {} counter = 0 ### TODO: REMOVE THIS WORKAROUND ONCE MODULE AUTHOR FIXES CODE ### ### Reference: http://stackoverflow.com/questions/32261679/strange-issue-using-logging-module-in-python/32264445#32264445 ### Reference: https://bitbucket.org/decalage/oletools/issues/26/use-of-logger ### /dev/null used instead of NullHandler for 2.6 compatibility logging.getLogger('workaround').root.addHandler( logging.FileHandler('/dev/null')) ### vba = VBA_Parser('None', data=buff) if not vba.detect_vba_macros(): return EXTRACT_MACRO for (filename, stream_path, vba_filename, vba_code) in vba.extract_macros(): CHILD_MACRO = OrderedDict([('OLE Stream', stream_path), ('VBA Filename', vba_filename.decode('ascii', 'ignore')), ('Scan', scan_macro(vba_code)), ('Buffer', vba_code)]) EXTRACT_MACRO['Object_%s' % counter] = CHILD_MACRO counter += 1 return EXTRACT_MACRO
def MacroHunter(targetFile): answerTable = PrettyTable() answerTable.field_names = [f"{green}Threat Levels{white}", f"{green}Macros{white}", f"{green}Descriptions{white}"] print(f"\n{infoS} Looking for VBA Macros...") try: fileData = open(targetFile, "rb").read() vbaparser = VBA_Parser(targetFile, fileData) macroList = list(vbaparser.analyze_macros()) if vbaparser.contains_macros == True: for fi in range(0, len(macroList)): if macroList[fi][0] == 'Suspicious': if "(use option --deobf to deobfuscate)" in macroList[fi][2]: sanitized = f"{macroList[fi][2]}".replace("(use option --deobf to deobfuscate)", "") answerTable.add_row([f"{yellow}{macroList[fi][0]}{white}", f"{macroList[fi][1]}", f"{sanitized}"]) elif "(option --decode to see all)" in macroList[fi][2]: sanitized = f"{macroList[fi][2]}".replace("(option --decode to see all)", "") answerTable.add_row([f"{yellow}{macroList[fi][0]}{white}", f"{macroList[fi][1]}", f"{sanitized}"]) else: answerTable.add_row([f"{yellow}{macroList[fi][0]}{white}", f"{macroList[fi][1]}", f"{macroList[fi][2]}"]) elif macroList[fi][0] == 'IOC': answerTable.add_row([f"{magenta}{macroList[fi][0]}{white}", f"{macroList[fi][1]}", f"{macroList[fi][2]}"]) elif macroList[fi][0] == 'AutoExec': answerTable.add_row([f"{red}{macroList[fi][0]}{white}", f"{macroList[fi][1]}", f"{macroList[fi][2]}"]) else: answerTable.add_row([f"{macroList[fi][0]}", f"{macroList[fi][1]}", f"{macroList[fi][2]}"]) print(f"{answerTable}\n") else: print(f"{errorS} Not any VBA macros found.") except: print(f"{errorS} An error occured while parsing that file for macro scan.")
def vba2graph_from_vba_object(filepath): """ vba2graph as library Args: filepath (string): path to file """ logger.info("Extracting macros from file") if HAVE_OLETOOLS: try: vba = VBA_Parser(filepath) except Exception as e: return False full_vba_code = "" for (subfilename, stream_path, vba_filename, vba_code) in vba.extract_macros(): full_vba_code += 'VBA MACRO %s \n' % vba_filename full_vba_code += '- ' * 39 + '\n' # Temporary workaround. Change when oletools 0.56 will be released. if isinstance(vba_code, bytes): vba_code = vba_code.decode('utf8', errors='replace') full_vba_code += vba_code vba.close() if full_vba_code: input_vba_content = handle_olevba_input(full_vba_code) return input_vba_content return False
def parseOLEDocument(f): """Parse an OLE document for VBA macros""" if not f or not useOLETools: return writeLog('DEBUG: Analyzing with oletools') try: v = VBA_Parser(f) except: writeLog("Not a supported file format: %s" % f) return writeLog('DEBUG: Detected file type: %s' % v.type) # Hack: Search for a .js extension fname, fextension = os.path.splitext(f) if v.detect_vba_macros() or fextension == ".js": writeLog('DEBUG: VBA Macros/JScript found') try: t = open("%s.analysis" % f, 'w') except IOError as e: writeLog("Cannot create analysis file %s.analysis: %s" % (f,e.strerror)) return for kw_type, keyword, description in v.analyze_macros(): t.write("%-12s | %-25s | %s\n" % (kw_type, keyword, description)) t.close() writeLog("DEBUG: Analysis dumped to %s.analysis" % f) else: writeLog('DEBUG: No VBA Macros found') return
def manage_encrypted_doc(self): self.olevba_results["is_encrypted"] = False # checks if it is an OLE file. That could be encrypted if self.vbaparser.ole_file: # check if the ole file is encrypted is_encrypted = self.vbaparser.detect_is_encrypted() self.olevba_results["is_encrypted"] = is_encrypted # in the case the file is encrypted I try to decrypt it # with the default password and the most common ones if is_encrypted: # by default oletools contains some basic passwords # we just add some more guesses common_pwd_to_check = [] for num in range(10): common_pwd_to_check.append(f"{num}{num}{num}{num}") # https://twitter.com/JohnLaTwC/status/1265377724522131457 filename_without_spaces_and_numbers = sub("[-_\d\s]", "", self.filename) filename_without_extension = sub( "(\..+)", "", filename_without_spaces_and_numbers ) common_pwd_to_check.append(filename_without_extension) self.passwords_to_check.extend(common_pwd_to_check) decrypted_file_name = self.vbaparser.decrypt_file( self.passwords_to_check ) self.olevba_results[ "additional_passwords_tried" ] = self.passwords_to_check if decrypted_file_name: self.vbaparser = VBA_Parser(decrypted_file_name) else: self.olevba_results["cannot_decrypt"] = True raise CannotDecryptException( "cannot decrypt the file with the default password" )
def olevba_trig(file): try: vbaparser = VBA_Parser(file) if vbaparser.detect_vba_macros(): for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): print('Filename :', filename) print('OLE stream :', stream_path) print('VBA filename:', vba_filename) print('- ' * 39) print(vba_code) print('- ' * 39) results = vbaparser.analyze_macros() for kw_type, keyword, description in results: print('type=%s - keyword=%s - description=%s' % (kw_type, keyword, description)) print('AutoExec keywords: %d' % vbaparser.nb_autoexec) print('Suspicious keywords: %d' % vbaparser.nb_suspicious) print('IOCs: %d' % vbaparser.nb_iocs) print('Hex obfuscated strings: %d' % vbaparser.nb_hexstrings) print('Base64 obfuscated strings: %d' % vbaparser.nb_base64strings) print('Dridex obfuscated strings: %d' % vbaparser.nb_dridexstrings) print('VBA obfuscated strings: %d' % vbaparser.nb_vbastrings) print("\n") except: e = sys.exc_info()[0] print(f'{e} from {file}')
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_report(self, sample): """ Return oletools report or create if not already cached. """ if sample.oletools_report != None: return sample.oletools_report report = {} try: vbaparser = VBA_Parser(sample.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: # no macros pass vbaparser.close() except IOError: raise except (TypeError, FileOpenError): # The given file is not an office document. pass except Exception as error: logger.exception(error) sample.register_oletools_report(OletoolsReport(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 parse_vba(self, save_path): save = False vbaparser = VBA_Parser(__sessions__.current.file.path) # Check for Macros if not vbaparser.detect_vba_macros(): self.log('error', "No Macro's Detected") return self.log('info', "Macro's Detected") #try: if True: an_results = {'AutoExec':[], 'Suspicious':[], 'IOC':[], 'Hex String':[], 'Base64 String':[], 'Dridex String':[], 'VBA string':[]} for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): self.log('info', "Stream Details") self.log('item', "OLE Stream: {0}".format(string_clean(stream_path))) self.log('item', "VBA Filename: {0}".format(string_clean(vba_filename))) # Analyse the VBA Code vba_scanner = VBA_Scanner(vba_code) analysis = vba_scanner.scan(include_decoded_strings=True) for kw_type, keyword, description in analysis: an_results[kw_type].append([string_clean_hex(keyword), description]) # Save the code to external File if save_path: try: with open(save_path, 'a') as out: out.write(vba_code) save = True except: self.log('error', "Unable to write to {0}".format(save_path)) return # Print all Tables together self.log('info', "AutoRun Macros Found") self.log('table', dict(header=['Method', 'Description'], rows=an_results['AutoExec'])) self.log('info', "Suspicious Keywords Found") self.log('table', dict(header=['KeyWord', 'Description'], rows=an_results['Suspicious'])) self.log('info', "Possible IOC's") self.log('table', dict(header=['IOC', 'Type'], rows=an_results['IOC'])) self.log('info', "Hex Strings") self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Hex String'])) self.log('info', "Base64 Strings") self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Base64 String'])) self.log('info', "Dridex String") self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['Dridex String'])) self.log('info', "VBA string") self.log('table', dict(header=['Decoded', 'Raw'], rows=an_results['VBA string'])) if save: self.log('success', "Writing VBA Code to {0}".format(save_path)) #except: #self.log('error', "Unable to Process File") # Close the file vbaparser.close()
def process(self, sample, tag): try: hashbot = Hasher(sample) mymagic = magic.Magic(mime=True) sample_info = self.identify_sample(oletools.oleid.OleID(sample)) vba = VBA_Parser(sample) # Extend the results of sample_info with extra data and add to Splunk sample_info['submit_date'] = int(time()) sample_info['filetype'] = mymagic.from_file(sample) sample_info['sample_type'] = 'office' sample_info['id_tag'] = tag sample_info['sha1'] = hashbot.get_sha1() sample_info['md5'] = hashbot.get_md5() indicators = dict() if self.doc_has_macros(vba): macro = self.macro_extraction(vba) data = VBA_Scanner(macro['vba_code']).scan(include_decoded_strings=False) i = 1 for kw_type, keyword, description in data: indicators[str(i)] = {'type':kw_type, 'keyword':keyword, 'description':description } i+=1 sample_info['indicators'] = indicators self.share_data(sample_info) self.store_sample(sample) except Exception, e: print "Error on",sample,e
def process_file_scanexpr (container, filename, data): """ Process a single file :param container: str, path and filename of container if the file is within a zip archive, None otherwise. :param filename: str, path and filename of file on disk, or within the container. :param data: bytes, content of the file if it is in a container, None if it is a file on disk. """ #TODO: replace print by writing to a provided output file (sys.stdout by default) if container: display_filename = '%s in %s' % (filename, container) else: display_filename = filename print '='*79 print 'FILE:', display_filename all_code = '' try: #TODO: handle olefile errors, when an OLE file is malformed vba = VBA_Parser(filename, data) print 'Type:', vba.type if vba.detect_vba_macros(): #print 'Contains VBA Macros:' for (subfilename, stream_path, vba_filename, vba_code) in vba.extract_macros(): # hide attribute lines: #TODO: option to disable attribute filtering vba_code_filtered = filter_vba(vba_code) print '-'*79 print 'VBA MACRO %s ' % vba_filename print 'in file: %s - OLE stream: %s' % (subfilename, repr(stream_path)) print '- '*39 # detect empty macros: if vba_code_filtered.strip() == '': print '(empty macro)' else: # TODO: option to display code print vba_code_filtered vba_code = vba_collapse_long_lines(vba_code) all_code += '\n' + vba_code print '-'*79 print 'EVALUATED VBA EXPRESSIONS:' t = prettytable.PrettyTable(('Obfuscated expression', 'Evaluated value')) t.align = 'l' t.max_width['Obfuscated expression'] = 36 t.max_width['Evaluated value'] = 36 for expression, expr_eval in scan_expressions(all_code): t.add_row((repr(expression), repr(expr_eval))) print t else: print 'No VBA macros found.' except: #TypeError: #raise #TODO: print more info if debug mode #print sys.exc_value # display the exception with full stack trace for debugging, but do not stop: traceback.print_exc() print ''
def is_file_has_VBA_macros(self): """Check if file has VBA macros.""" file_path = self.file_path vbaparser = VBA_Parser(file_path) print('The file type is "%s"' % (vbaparser.type)) report = vbaparser.detect_vba_macros() vbaparser.close() return report
def parse_vba(self, save_path): vba = VBA_Parser(__sessions__.current.file.path) # Check for Macros if not vba.detect_vba_macros(): self.log('error', "No Macro's Detected") return self.log('info', "Macro's Detected") try: for (filename, stream_path, vba_filename, vba_code) in vba.extract_macros(): self.log('info', "Stream Details") self.log('item', "OLE Stream: {0}".format(stream_path)) self.log('item', "VBA Filename: {0}".format(vba_filename)) autoexec_keywords = detect_autoexec(vba_code) if autoexec_keywords: self.log('info', "AutoRun Macros Found") rows = [] for keyword, description in autoexec_keywords: rows.append([keyword, description]) self.log( 'table', dict(header=['KeyWord', 'Description'], rows=rows)) # Match Keyword Types suspicious_keywords = detect_suspicious(vba_code) if suspicious_keywords: self.log('info', "Suspicious Keywords Found") rows = [] for keyword, description in suspicious_keywords: rows.append([keyword, description]) self.log( 'table', dict(header=['KeyWord', 'Description'], rows=rows)) # Match IOCs patterns = detect_patterns(vba_code) if patterns: self.log('info', "Suspicious Keywords Found") rows = [] for pattern_type, value in patterns: rows.append([pattern_type, value]) self.log('table', dict(header=['Pattern', 'Value'], rows=rows)) # Save the code to external File if save_path: try: with open(save_path, 'w') as out: out.write(vba_code) self.log('info', "Writing VBA Code to {0}".format(save_path)) except: self.log('Error', "Unable to write to {0}".format(save_path)) return except: self.log('Error', "Unable to Process File") # Close the file vba.close()
def test_samples(self): if sys.version_info[0] > 2: # Unfortunately, olevba3 doesn't have extract_form_strings_extended return for sample, expected_result in SAMPLES: full_name = join(DATA_BASE_DIR, 'oleform', sample) parser = VBA_Parser(full_name) variables = list(parser.extract_form_strings_extended()) self.assertEqual(variables, expected_result)
def getVBA(self, myfile, source='filepath'): ''' Given a file, parses out the stream paths, vba code, and vba filenames for each. :param myfile: filename :param source: type of data being passed in. Either "filepath" to indicate we need to read from disk or "filecontents" meaning that the file contents are being passed as a parameter. :return: pandas Series that can be used in concert with the pandas DataFrame apply method ''' if source == 'filepath': filedata = open(myfile, 'rb').read() else: filedata = myfile entry = {} try: vbaparser = VBA_Parser('mmbot', data=filedata) allcode = '' pathnames = '' filenames = '' if vbaparser.detect_vba_macros(): filenameslist = [] pathnameslist = [] vbacodelist = [] for (filename, stream_path, filename_vba, extracted_vba) in vbaparser.extract_macros(): vbacodelist.append(extracted_vba.decode("ascii", "ignore")) #vbacodelist.append(extracted_vba.decode('utf8', 'ignore')) if pathnames is None: pathnameslist.append( stream_path.decode("ascii", "ignore")) filenameslist.append( filename_vba.decode("ascii", "ignore")) else: pathnameslist.append( stream_path.decode("ascii", "ignore")) filenameslist.append( filename_vba.decode("ascii", "ignore")) allcode = "\n\n\n\n".join(vbacodelist) filenames = ", ".join(filenameslist) pathnames = ", ".join(pathnameslist) else: pathnames = 'No VBA Macros found' filenames = 'No VBA Macros found' allcode = 'No VBA Macros found' except Exception as e: pathnames = 'Error:' + str(e) filenames = 'Error:' + str(e) allcode = 'Error:' + str(e) return pd.Series({ 'extracted_vba': allcode, 'stream_path': pathnames, 'filename_vba': filenames })
def run(self, obj, config): username = self.current_task.username filename = obj.filename filedata = obj.filedata.read() try: vbaparser = VBA_Parser(filename, data=filedata) except Exception, e: self._error("Cannot parse file: %s" % str(e)) return
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 get_macros(): extracted_macros = [] macro_analysis = [] tags = [] try: vbaparser = VBA_Parser('/sample') vbaparser.detect_vba_macros() for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): extracted_macros.append({ "stream_path": stream_path, "vba_filename": vba_filename, "vba_code": vba_code }) try: for kw_type, keyword, description in vbaparser.analyze_macros(): macro_analysis.append({ "kw_type": kw_type, "keyword": keyword, "description": description }) if keyword == 'Shell': tags.append('run-file') except TypeError: pass macro_suspicious_categories = { "nb_macros": vbaparser.nb_macros, "nb_autoexec": vbaparser.nb_autoexec, "nb_suspicious": vbaparser.nb_suspicious, "nb_iocs": vbaparser.nb_iocs, "nb_hexstrings": vbaparser.nb_hexstrings, "nb_base64strings": vbaparser.nb_base64strings, "nb_dridexstrings": vbaparser.nb_dridexstrings, "nb_vbastrings": vbaparser.nb_vbastrings, } if vbaparser.nb_macros: tags.append('macros') if vbaparser.nb_hexstrings or vbaparser.nb_base64strings: tags.append('obfuscated') except FileOpenError: return None, tags return { "extracted_macros": extracted_macros, "macro_analysis": macro_analysis, "macro_suspicious_categories": macro_suspicious_categories }, tags
def vbaparsing(filename): vbafile = VBA_Parser(filename) results = "" for (filename, stream_path, vba_filename, vba_code) in vbafile.extract_macros(): results = results + vba_code result = vbafile.analyze_macros() for kw_type, keyword, description in result: results = results + 'type=%s - keyword=%s - description=%s' % ( kw_type, keyword, description) return results
def extract_src_codes(file): dic = {} parser = VBA_Parser(file) for (_, sname, _, code) in parser.extract_macros(): sname = sname.split("/")[-1] if sname not in dic: lines = code.split("\n")[1: ] dic[sname] = "\n".join(lines) # remove the first line else: printError(f"Error in src_codes: repeat {sname}") return dic
def vba2graph_from_vba_object(filepath): logging.info("Extracting macros from file") full_vba_code = "" vba_parser = VBA_Parser(filepath) for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_macros(): # workaround till oletools version 0.56 if isinstance(vba_code, bytes): vba_code = vba_code.decode('latin1', errors='replace') full_vba_code += vba_code vba_parser.close() return full_vba_code
def parse(file_path): vba_folder = 'src' vba_parser = VBA_Parser(file_path) for _, _, vba_filename, vba_code in vba_parser.extract_macros(): if not os.path.isdir(vba_folder): os.makedirs(vba_folder) with open(os.path.join(vba_folder, vba_filename), 'w', encoding='utf-8', newline='\n') as file: file.write(vba_code) vba_parser.close()
def writeVBA(workbookName): vbaparser = VBA_Parser('./'+workbookName) VBA_path = './src/VBA' if os.path.exists(VBA_path): shutil.rmtree(VBA_path) os.mkdir(VBA_path) for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): f = open('./src/VBA/' + vba_filename, "w") f.write(vba_code) f.close() vbaparser.close()
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 check_macros(doc_path, filename) -> dict: try: vbaparser = VBA_Parser(doc_path) if not vbaparser.detect_vba_macros(): return "" logging.warning("VBA macros in \"%s\"" % filename) details = "Macro Results\n" suspicious_count = 0 suspicious_list = [] ioc_list = [] ioc_count = 0 mal_score = 0 logging.disable(level=logging.CRITICAL) results = vbaparser.analyze_macros() logging.disable(level=logging.NOTSET) for kw_type, keyword, description in results: details += "\t - " + kw_type + " - (" + keyword + ") - " + description + "\n" if kw_type.lower() == "suspicious": suspicious_count += 1 suspicious_list.append(keyword) elif kw_type.lower() == "ioc": ioc_count += 1 ioc_list.append(keyword) if suspicious_count != 0: logging.warning("Found %d suspicious items in \"%s\"" % (suspicious_count, filename)) mal_score += suspicious_count if ioc_count != 0: logging.warning("Found %d IOCs: %s, in \"%s\"" % (ioc_count, ioc_list, filename)) mal_score += ioc_count * 2 return {'details': details, 'mal_score': mal_score} except Exception as e: logging.error("Failed to parse macros for: {} - {}".format( filename, e)) return
def get_vba_source_from_excel(filename): vbaparser = VBA_Parser(filename) if vbaparser.detect_vba_macros(): print('VBA Macros found') else: print('No VBA Macros found') for (filename, stream_path, vba_filename, vba_code) in vbaparser.extract_macros(): print('-' * 79) print('Filename :', filename) print('OLE stream :', stream_path) print('VBA filename:', vba_filename) print('- ' * 39) print(vba_code)
def get_all_macros(filename_wchar): """ Open a file and extract the source code of all VBA modules by calling oletools.VBA_Parser.get_vba_code_all_modules() :param filename_wchar: file to be opened (unicode wchar_t string) :return: source code of all VBA modules (unicode wchar_t string) """ # print(wchar_string) filename_str = ffi.string(filename_wchar) print("filename: {}".format(filename_str)) ovba = VBA_Parser(filename_str) # TODO: check if there are macros vba_code_str = ovba.get_vba_code_all_modules() # convert python str to C string return ffi.new("wchar_t[]", vba_code_str)
def _ole_analysis(full_targ_path): # This function calls a number of tools / scripts to run against document samples containing OLE data and extracts data and/or performs analysis as needed. try: vba_parse_Obj = VBA_Parser(full_targ_path) except AttributeError: return ("ERROR_PARSING", "ERROR_PARSING", "ERROR_PARSING", "ERROR_PARSING") macro_analysis_over = [] macro_analysis_info = [] if vba_parse_Obj.detect_vba_macros(): vba_macro = "Present" # Utilizing oletools to perform analysis. # Grabbing info from each macro. MA_CNT = 1 for (file_name, ole_stream, vba_filename, vba_code) in vba_parse_Obj.extract_macros(): macro_analysis_over.append(str(MA_CNT) + ':' + str(full_targ_path)) macro_analysis_over.append( str(MA_CNT) + ":Filename :" + file_name) macro_analysis_over.append( str(MA_CNT) + ":OLE Stream :" + ole_stream) macro_analysis_over.append( str(MA_CNT) + ":VBA Filename :" + vba_filename) macro_analysis_over.append(str(MA_CNT) + ':' + vba_code) MA_CNT += 1 # Grabbing some overall VBA analysis info. macro_flag_types = [] macro_analysis_res = vba_parse_Obj.analyze_macros() if isinstance(macro_analysis_res, list): for iocType in macro_analysis_res: if str(iocType) not in macro_flag_types: macro_flag_types.append(str(iocType[0])) if len(macro_flag_types) > 0: iocs = ':'.join(list(set(macro_flag_types))) else: iocs = "None" else: vba_macro = "None" iocs = "None" macro_analysis_res = "None" vba_parse_Obj.close() return (vba_macro, macro_analysis_over, str(macro_analysis_res), iocs)