def process_maybe_encrypted(filepath, passwords=None, crypto_nesting=0, **kwargs): """ Process a file that might be encrypted. Calls :py:func:`process_file` and if that fails tries to decrypt and process the result. Based on recommendation in module doc string of :py:mod:`oletools.crypto`. :param str filepath: path to file on disc. :param passwords: list of passwords (str) to try for decryption or None :param int crypto_nesting: How many decryption layers were already used to get the given file. :param kwargs: same as :py:func:`process_file` :returns: same as :py:func:`process_file` """ # TODO: here filepath may also be a file in memory, it's not necessarily on disk result = u'' try: result = process_file(filepath, **kwargs) if not crypto.is_encrypted(filepath): return result except Exception: logger.debug('Ignoring exception:', exc_info=True) if not crypto.is_encrypted(filepath): raise # we reach this point only if file is encrypted # check if this is an encrypted file in an encrypted file in an ... if crypto_nesting >= crypto.MAX_NESTING_DEPTH: raise crypto.MaxCryptoNestingReached(crypto_nesting, filepath) decrypted_file = None if passwords is None: passwords = crypto.DEFAULT_PASSWORDS else: passwords = list(passwords) + crypto.DEFAULT_PASSWORDS try: logger.debug('Trying to decrypt file') decrypted_file = crypto.decrypt(filepath, passwords) if not decrypted_file: logger.error( 'Decrypt failed, run with debug output to get details') raise crypto.WrongEncryptionPassword(filepath) logger.info('Analyze decrypted file') result = process_maybe_encrypted(decrypted_file, passwords, crypto_nesting + 1, **kwargs) finally: # clean up try: # (maybe file was not yet created) os.unlink(decrypted_file) except Exception: logger.debug('Ignoring exception closing decrypted file:', exc_info=True) return result
def process_maybe_encrypted(filepath, passwords=None, crypto_nesting=0, **kwargs): """ Process a file that might be encrypted. Calls :py:func:`process_file` and if that fails tries to decrypt and process the result. Based on recommendation in module doc string of :py:mod:`oletools.crypto`. :param str filepath: path to file on disc. :param passwords: list of passwords (str) to try for decryption or None :param int crypto_nesting: How many decryption layers were already used to get the given file. :param kwargs: same as :py:func:`process_file` :returns: same as :py:func:`process_file` """ result = u'' try: result = process_file(filepath, **kwargs) if not crypto.is_encrypted(filepath): return result except Exception: if not crypto.is_encrypted(filepath): raise # we reach this point only if file is encrypted # check if this is an encrypted file in an encrypted file in an ... if crypto_nesting >= crypto.MAX_NESTING_DEPTH: raise crypto.MaxCryptoNestingReached(crypto_nesting, filepath) decrypted_file = None if passwords is None: passwords = [ crypto.WRITE_PROTECT_ENCRYPTION_PASSWORD, ] else: passwords = list(passwords) + \ [crypto.WRITE_PROTECT_ENCRYPTION_PASSWORD, ] try: logger.debug('Trying to decrypt file') decrypted_file = crypto.decrypt(filepath, passwords) logger.info('Analyze decrypted file') result = process_maybe_encrypted(decrypted_file, passwords, crypto_nesting + 1, **kwargs) finally: # clean up try: # (maybe file was not yet created) os.unlink(decrypted_file) except Exception: pass return result
def analyze_vba(self, path): """Analyze a given sample for malicious vba.""" try: if is_encrypted(path): path = decrypt(path) vba_parser = VBA_Parser_CLI(path, relaxed=True) vbaparser_result = vba_parser.process_file_json( show_decoded_strings=True, display_code=True, hide_attributes=False, vba_code_only=False, show_deobfuscated_code=True, deobfuscate=True) self.add_result_subsection('Olevba', vbaparser_result) except TypeError: self.add_result_subsection( 'Oletools VBA Analysis failed', 'Analysis failed due to an filetype error.' 'The file does not seem to be a valid MS-Office ' 'file.')