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 process_file (container, filename, data, altparser=False, strip_useless=False): """ 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 vm = ViperMonkey() try: #TODO: handle olefile errors, when an OLE file is malformed vba = VBA_Parser(filename, data, relaxed=True) print 'Type:', vba.type if vba.detect_vba_macros(): # Read in document metadata. try: ole = olefile.OleFileIO(filename) vba_library.meta = ole.get_metadata() except: vba_library.meta = {} # Parse the VBA streams. comp_modules = parse_streams(vba, strip_useless) for m in comp_modules: vm.add_compiled_module(m) # Pull out form variables. for (subfilename, stream_path, form_variables) in vba.extract_form_strings_extended(): if form_variables is not None: var_name = form_variables['name'] macro_name = stream_path if ("/" in macro_name): start = macro_name.rindex("/") + 1 macro_name = macro_name[start:] global_var_name = (macro_name + "." + var_name).encode('ascii', 'ignore') val = form_variables['value'] vm.globals[global_var_name.lower()] = val log.debug("Added VBA form variable %r = %r to globals." % (global_var_name, val)) print '-'*79 print 'TRACING VBA CODE (entrypoint = Auto*):' vm.trace() # print table of all recorded actions print('Recorded Actions:') print(vm.dump_actions()) 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 process_file(container, filename, data, altparser=False, strip_useless=False, entry_points=None): """ 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. :return A list of actions if actions found, an empty list if no actions found, and None if there was an error. """ #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 vm = ViperMonkey() if (entry_points is not None): for entry_point in entry_points: vm.entry_points.append(entry_point) try: #TODO: handle olefile errors, when an OLE file is malformed vba = VBA_Parser(filename, data, relaxed=True) print 'Type:', vba.type if vba.detect_vba_macros(): # Read in document metadata. try: ole = olefile.OleFileIO(filename) vba_library.meta = ole.get_metadata() vba_object.meta = vba_library.meta except: log.error("Reading in metadata failed.") vba_library.meta = {} # Set the output directory in which to put dumped files generated by # the macros. out_dir = filename + "_artifacts" if ("/" in out_dir): start = out_dir.rindex("/") + 1 out_dir = out_dir[start:] out_dir = out_dir.replace(".", "").strip() out_dir = "./" + out_dir + "/" vba_library.out_dir = out_dir # Parse the VBA streams. comp_modules = parse_streams(vba, strip_useless) if (comp_modules is None): return None for m in comp_modules: if (m != "empty"): vm.add_compiled_module(m) # Pull out form variables. try: for (subfilename, stream_path, form_variables) in vba.extract_form_strings_extended(): if form_variables is not None: var_name = form_variables['name'] macro_name = stream_path if ("/" in macro_name): start = macro_name.rindex("/") + 1 macro_name = macro_name[start:] global_var_name = (macro_name + "." + var_name).encode( 'ascii', 'ignore') val = form_variables['value'] if (val is None): val = '' name = global_var_name.lower() vm.globals[name] = val log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name, val)) vm.globals[name + ".tag"] = val log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name + ".Tag", val)) vm.globals[name + ".text"] = val log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name + ".Text", val)) except Exception as e: log.error("Cannot read form strings. " + str(e)) print '-' * 79 print 'TRACING VBA CODE (entrypoint = Auto*):' if (entry_points is not None): log.info("Starting emulation from function(s) " + str(entry_points)) vm.trace() # print table of all recorded actions print('Recorded Actions:') print(vm.dump_actions()) print '' return vm.actions else: print 'No VBA macros found.' print '' return [] except Exception as e: if ("SystemExit" not in str(e)): traceback.print_exc() return None
def process_file(container, filename, data, altparser=False, strip_useless=False, entry_points=None, time_limit=None): """ 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. :return A list of actions if actions found, an empty list if no actions found, and None if there was an error. """ # Increase Python call depth. sys.setrecursionlimit(13000) # Set the emulation time limit. if (time_limit is not None): vba_object.max_emulation_time = datetime.now() + timedelta( minutes=time_limit) #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 vm = ViperMonkey() if (entry_points is not None): for entry_point in entry_points: vm.entry_points.append(entry_point) try: #TODO: handle olefile errors, when an OLE file is malformed if (isinstance(data, Exception)): data = None vba = VBA_Parser(filename, data, relaxed=True) if vba.detect_vba_macros(): # Read in document metadata. try: ole = olefile.OleFileIO(filename) vba_library.meta = ole.get_metadata() vba_object.meta = vba_library.meta except Exception as e: log.error("Reading in metadata failed. " + str(e)) vba_library.meta = {} # If this is an Excel spreadsheet, read it in with xlrd. try: log.debug("Trying to load " + filename + " with xlrd...") vm.loaded_excel = xlrd.open_workbook(filename) except Exception as e: log.error("Reading in file as Excel failed. " + str(e)) # Set the output directory in which to put dumped files generated by # the macros. out_dir = filename + "_artifacts" if ("/" in out_dir): start = out_dir.rindex("/") + 1 out_dir = out_dir[start:] out_dir = out_dir.replace(".", "").strip() out_dir = "./" + out_dir + "/" vba_context.out_dir = out_dir # Parse the VBA streams. comp_modules = parse_streams(vba, strip_useless) if (comp_modules is None): return None for m in comp_modules: if (m != "empty"): vm.add_compiled_module(m) # Pull out document variables. for (var_name, var_val) in _read_doc_vars(filename): vm.doc_vars[var_name.lower()] = var_val log.debug( "Added potential VBA doc variable %r = %r to doc_vars." % (var_name, var_val)) # Pull out custom document properties. for (var_name, var_val) in _read_custom_doc_props(filename): vm.doc_vars[var_name.lower()] = var_val log.debug( "Added potential VBA custom doc prop variable %r = %r to doc_vars." % (var_name, var_val)) # Pull out the document text. vm.doc_text = _read_doc_text(filename) try: # Pull out form variables. for (subfilename, stream_path, form_variables) in vba.extract_form_strings_extended(): if form_variables is not None: var_name = form_variables['name'] macro_name = stream_path if ("/" in macro_name): start = macro_name.rindex("/") + 1 macro_name = macro_name[start:] global_var_name = (macro_name + "." + var_name).encode( 'ascii', 'ignore').replace("\x00", "") tag = form_variables['tag'] if (tag is None): tag = '' tag = tag.replace('\xb1', '').replace('\x03', '') caption = form_variables['caption'] if (caption is None): caption = '' caption = caption.replace('\xb1', '').replace('\x03', '') val = form_variables['value'] if (val is None): val = caption control_tip_text = form_variables['control_tip_text'] if (control_tip_text is None): control_tip_text = '' control_tip_text = control_tip_text.replace( '\xb1', '').replace('\x03', '') # Save full form variable names. name = global_var_name.lower() vm.globals[name] = val log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name, val)) vm.globals[name + ".tag"] = tag log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name + ".Tag", tag)) vm.globals[name + ".caption"] = caption log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name + ".Caption", caption)) vm.globals[name + ".controltiptext"] = control_tip_text log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name + ".ControlTipText", control_tip_text)) vm.globals[name + ".text"] = val log.debug( "Added VBA form variable %r = %r to globals." % (global_var_name + ".Text", val)) # Save short form variable names. short_name = global_var_name.lower() if ("." in short_name): short_name = short_name[short_name.rindex(".") + 1:] vm.globals[short_name] = val log.debug( "Added VBA form variable %r = %r to globals." % (short_name, val)) vm.globals[short_name + ".tag"] = tag log.debug( "Added VBA form variable %r = %r to globals." % (short_name + ".Tag", tag)) vm.globals[short_name + ".caption"] = caption log.debug( "Added VBA form variable %r = %r to globals." % (short_name + ".Caption", caption)) vm.globals[short_name + ".controltiptext"] = control_tip_text log.debug( "Added VBA form variable %r = %r to globals." % (short_name + ".ControlTipText", control_tip_text)) vm.globals[short_name + ".text"] = val log.debug( "Added VBA form variable %r = %r to globals." % (short_name + ".Text", val)) except Exception as e: log.error("Cannot read form strings. " + str(e)) #traceback.print_exc() #raise e print '-' * 79 print 'TRACING VBA CODE (entrypoint = Auto*):' if (entry_points is not None): log.info("Starting emulation from function(s) " + str(entry_points)) vm.trace() # print table of all recorded actions print('Recorded Actions:') print(vm.dump_actions()) print('') print('VBA Builtins Called: ' + str(vm.external_funcs)) print('') return (vm.actions, vm.external_funcs) else: print 'No VBA macros found.' print '' return ([], []) except Exception as e: if ("SystemExit" not in str(e)): traceback.print_exc() return None