<commit_before>"""FileInfo oletools submodule; WIP"""
from .submodule_base import SubmoduleBaseclass
from oletools.olevba3 import VBA_Parser, VBA_Scanner, ProcessingError


class OLEToolsSubmodule(SubmoduleBaseclass):
    """Try to inspect files using python oletools."""

    def __init__(self):
        SubmoduleBaseclass.__init__(self)
        self.name = 'OLETools Submodule'
        self.fileextension = None

    def check_file(self, **kwargs):
        """Oletools accepts MS office documents."""
        try:
            self.fileextension = kwargs.get('filename').rsplit('.', 1)[1]
            if self.fileextension in [
                'doc',
                'docx',
                'xls',
                'xlsx',
                'ppt',
                'pptx'
            ]:
                return True
        except KeyError:
            return False
        return False

    def analyze_file(self, path):
        # Run the analyze functions
        self.analyze_vba(path)

        return self.results

    def analyze_vba(self, path):
        """Analyze a given sample for malicios vba."""
        try:
            parsed = VBA_Parser(path)

            if parsed.detect_vba_macros():
                for idx, (filename, stream_path, vba_filename, vba_code) in enumerate(parsed.extract_all_macros()):
                    # Decode strings often produces errors
                    scanner = VBA_Scanner(vba_code)
                    scan_results_to_report = []
                    try:
                        scan_results = scanner.scan(include_decoded_strings=True)
                    except ProcessingError:
                        scan_results = scanner.scan(include_decoded_strings=False)

                    for type, keyword, description in scan_results:
                        scan_results_to_report.append({
                            'type': type,
                            'keyword': keyword,
                            'description': description
                        })

                    self.add_result_subsection(
                        'OLE stream: {}'.format(stream_path),
                        {
                            'olevba_filename': vba_filename,
                            'olevba_code': vba_code.decode('unicode-escape'),
                            'olevba_results': scan_results_to_report
                        }
                    )

        except TypeError:
            self.add_result_subsection('OLEVBA Analysis failed', 'Analysis failed due to an filetype error.'
                                                                 'The file does not seem to be a valid MS-Office file.')

<commit_msg>Added DDE scan and OleID<commit_after>"""FileInfo oletools submodule; WIP"""
from .submodule_base import SubmoduleBaseclass
from oletools.oleid import OleID
from oletools.olevba3 import VBA_Parser, VBA_Scanner, ProcessingError
from oletools.msodde import process_file


class OLEToolsSubmodule(SubmoduleBaseclass):
    """Try to inspect files using python oletools."""

    def __init__(self):
        SubmoduleBaseclass.__init__(self)
        self.name = 'Oletools Submodule'
        self.fileextension = None

    def check_file(self, **kwargs):
        """Oletools accepts MS office documents."""
        try:
            self.fileextension = kwargs.get('filename').rsplit('.', 1)[1]
            if self.fileextension in [
                'doc',
                'docx',
                'xls',
                'xlsx',
                'ppt',
                'pptx'
            ]:
                return True
        except KeyError:
            return False
        return False

    def analyze_file(self, path):
        # Run the analyze functions
        self.analyze_oleid(path)
        self.analyze_vba(path)
        self.analyze_dde(path)

        return self.results

    def analyze_oleid(self, path):
        indicators = OleID(path).check()
        results = {}

        for indicator in indicators:
            if indicator.id == 'appname':
                continue
            results.update({indicator.name: indicator.value})
        self.add_result_subsection('Oletools OleID Results', results)

    def analyze_vba(self, path):
        """Analyze a given sample for malicios vba."""
        try:
            parser = VBA_Parser(path)

            if parser.detect_vba_macros():
                for idx, (filename, stream_path, vba_filename, vba_code) in enumerate(parser.extract_all_macros()):
                    # Decode strings often produces errors
                    scanner = VBA_Scanner(vba_code)
                    scan_results_to_report = []
                    try:
                        scan_results = scanner.scan(include_decoded_strings=True)
                    except ProcessingError:
                        scan_results = scanner.scan(include_decoded_strings=False)

                    for type, keyword, description in scan_results:
                        scan_results_to_report.append({
                            'type': type,
                            'keyword': keyword,
                            'description': description
                        })

                    self.add_result_subsection(
                        'OLE stream: {}'.format(stream_path),
                        {
                            'olevba_filename': vba_filename,
                            'olevba_code': vba_code.decode('unicode-escape'),
                            'olevba_results': scan_results_to_report
                        }
                    )

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

    def analyze_dde(self, path):
        results = process_file(path)
        if len(results) > 0:
            self.add_result_subsection('Oletools DDE Analysis', {'DDEUrl': results})
        else:
            self.add_result_subsection('Oletools DDE Analysis', {'Info': 'No URLs found.'})

{'fraction_non_alphanumeric': 0.08194308145240432, 'fraction_numerical': 0.001144913313706248, 'mean_word_length': 1.5082034454470878, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6265865', 'n_tokens_mistral': 1594, 'n_tokens_neox': 1495, 'n_words': 364}