Commit 6641ac1ab37ac2842ceed687143f50f6a91002d1

Authored by Christian Herdtweck
1 parent 8b21d586

created exception ProcessingError, raise from process_... functions and handle in main

Showing 1 changed file with 101 additions and 88 deletions
oletools/olevba.py
@@ -214,7 +214,6 @@ import optparse @@ -214,7 +214,6 @@ import optparse
214 import os.path 214 import os.path
215 import binascii 215 import binascii
216 import base64 216 import base64
217 -import traceback  
218 import zlib 217 import zlib
219 import email # for MHTML parsing 218 import email # for MHTML parsing
220 import string # for printable 219 import string # for printable
@@ -304,6 +303,16 @@ class FileOpenError(Exception): @@ -304,6 +303,16 @@ class FileOpenError(Exception):
304 self.filename = filename 303 self.filename = filename
305 304
306 305
  306 +class ProcessingError(Exception):
  307 + """ raised by VBA_Parser.process_file* functions """
  308 +
  309 + def __init__(self, filename, orig_exception):
  310 + super(ProcessingError, self).__init__(
  311 + 'Error processing file %s (%s)' % (filename, orig_exception))
  312 + self.filename = filename
  313 + self.orig_exception = orig_exception
  314 +
  315 +
307 class MsoExtractionError(RuntimeError): 316 class MsoExtractionError(RuntimeError):
308 """ raised by mso_file_extract if parsing MSO/ActiveMIME data failed """ 317 """ raised by mso_file_extract if parsing MSO/ActiveMIME data failed """
309 318
@@ -2643,12 +2652,11 @@ class VBA_Parser_CLI(VBA_Parser): @@ -2643,12 +2652,11 @@ class VBA_Parser_CLI(VBA_Parser):
2643 print self.reveal() 2652 print self.reveal()
2644 else: 2653 else:
2645 print 'No VBA macros found.' 2654 print 'No VBA macros found.'
2646 - except Exception: #TypeError:  
2647 - #raise  
2648 - #TODO: print more info if debug mode  
2649 - #print sys.exc_value  
2650 - # display the exception with full stack trace for debugging, but do not stop:  
2651 - traceback.print_exc() 2655 + except Exception as exc:
  2656 + # display the exception with full stack trace for debugging
  2657 + log.exception('Error processing file %s (%s)' % (self.filename, exc))
  2658 + log.debug('Traceback:', exc_info=True)
  2659 + raise ProcessingError(self.filename, exc)
2652 print '' 2660 print ''
2653 2661
2654 2662
@@ -2710,12 +2718,11 @@ class VBA_Parser_CLI(VBA_Parser): @@ -2710,12 +2718,11 @@ class VBA_Parser_CLI(VBA_Parser):
2710 result['code_deobfuscated'] = self.reveal() 2718 result['code_deobfuscated'] = self.reveal()
2711 result['macros'] = macros 2719 result['macros'] = macros
2712 result['json_conversion_successful'] = True 2720 result['json_conversion_successful'] = True
2713 - except Exception: #TypeError:  
2714 - #raise  
2715 - #TODO: print more info if debug mode  
2716 - #print sys.exc_value  
2717 - # display the exception with full stack trace for debugging, but do not stop:  
2718 - traceback.print_exc() 2721 + except Exception as exc:
  2722 + # display the exception with full stack trace for debugging
  2723 + log.exception('Error processing file %s (%s)' % (self.filename, exc))
  2724 + log.debug('Traceback:', exc_info=True)
  2725 + raise ProcessingError(self.filename, exc)
2719 2726
2720 return result 2727 return result
2721 2728
@@ -2725,54 +2732,46 @@ class VBA_Parser_CLI(VBA_Parser): @@ -2725,54 +2732,46 @@ class VBA_Parser_CLI(VBA_Parser):
2725 Process a file in triage mode, showing only summary results on one line. 2732 Process a file in triage mode, showing only summary results on one line.
2726 """ 2733 """
2727 #TODO: replace print by writing to a provided output file (sys.stdout by default) 2734 #TODO: replace print by writing to a provided output file (sys.stdout by default)
2728 - message = ''  
2729 try: 2735 try:
2730 - if self.type is not None:  
2731 - #TODO: handle olefile errors, when an OLE file is malformed  
2732 - if self.detect_vba_macros():  
2733 - # print a waiting message only if the output is not redirected to a file:  
2734 - if sys.stdout.isatty():  
2735 - print 'Analysis...\r',  
2736 - sys.stdout.flush()  
2737 - self.analyze_macros(show_decoded_strings=show_decoded_strings,  
2738 - deobfuscate=deobfuscate)  
2739 - flags = TYPE2TAG[self.type]  
2740 - macros = autoexec = suspicious = iocs = hexstrings = base64obf = dridex = vba_obf = '-'  
2741 - if self.contains_macros: macros = 'M'  
2742 - if self.nb_autoexec: autoexec = 'A'  
2743 - if self.nb_suspicious: suspicious = 'S'  
2744 - if self.nb_iocs: iocs = 'I'  
2745 - if self.nb_hexstrings: hexstrings = 'H'  
2746 - if self.nb_base64strings: base64obf = 'B'  
2747 - if self.nb_dridexstrings: dridex = 'D'  
2748 - if self.nb_vbastrings: vba_obf = 'V'  
2749 - flags += '%s%s%s%s%s%s%s%s' % (macros, autoexec, suspicious, iocs, hexstrings,  
2750 - base64obf, dridex, vba_obf)  
2751 - # old table display:  
2752 - # macros = autoexec = suspicious = iocs = hexstrings = 'no'  
2753 - # if nb_macros: macros = 'YES:%d' % nb_macros  
2754 - # if nb_autoexec: autoexec = 'YES:%d' % nb_autoexec  
2755 - # if nb_suspicious: suspicious = 'YES:%d' % nb_suspicious  
2756 - # if nb_iocs: iocs = 'YES:%d' % nb_iocs  
2757 - # if nb_hexstrings: hexstrings = 'YES:%d' % nb_hexstrings  
2758 - # # 2nd line = info  
2759 - # print '%-8s %-7s %-7s %-7s %-7s %-7s' % (self.type, macros, autoexec, suspicious, iocs, hexstrings)  
2760 - else:  
2761 - # self.type==None  
2762 - # file type not OLE nor OpenXML  
2763 - flags = '?'  
2764 - message = 'File format not supported'  
2765 - except Exception:  
2766 - # another error occurred  
2767 - #raise  
2768 - #TODO: print more info if debug mode  
2769 - #TODO: distinguish real errors from incorrect file types  
2770 - flags = '!ERROR'  
2771 - message = sys.exc_value  
2772 - line = '%-12s %s' % (flags, self.filename)  
2773 - if message:  
2774 - line += ' - %s' % message  
2775 - print line 2736 + #TODO: handle olefile errors, when an OLE file is malformed
  2737 + if self.detect_vba_macros():
  2738 + # print a waiting message only if the output is not redirected to a file:
  2739 + if sys.stdout.isatty():
  2740 + print 'Analysis...\r',
  2741 + sys.stdout.flush()
  2742 + self.analyze_macros(show_decoded_strings=show_decoded_strings,
  2743 + deobfuscate=deobfuscate)
  2744 + flags = TYPE2TAG[self.type]
  2745 + macros = autoexec = suspicious = iocs = hexstrings = base64obf = dridex = vba_obf = '-'
  2746 + if self.contains_macros: macros = 'M'
  2747 + if self.nb_autoexec: autoexec = 'A'
  2748 + if self.nb_suspicious: suspicious = 'S'
  2749 + if self.nb_iocs: iocs = 'I'
  2750 + if self.nb_hexstrings: hexstrings = 'H'
  2751 + if self.nb_base64strings: base64obf = 'B'
  2752 + if self.nb_dridexstrings: dridex = 'D'
  2753 + if self.nb_vbastrings: vba_obf = 'V'
  2754 + flags += '%s%s%s%s%s%s%s%s' % (macros, autoexec, suspicious, iocs, hexstrings,
  2755 + base64obf, dridex, vba_obf)
  2756 +
  2757 + line = '%-12s %s' % (flags, self.filename)
  2758 + print line
  2759 +
  2760 + # old table display:
  2761 + # macros = autoexec = suspicious = iocs = hexstrings = 'no'
  2762 + # if nb_macros: macros = 'YES:%d' % nb_macros
  2763 + # if nb_autoexec: autoexec = 'YES:%d' % nb_autoexec
  2764 + # if nb_suspicious: suspicious = 'YES:%d' % nb_suspicious
  2765 + # if nb_iocs: iocs = 'YES:%d' % nb_iocs
  2766 + # if nb_hexstrings: hexstrings = 'YES:%d' % nb_hexstrings
  2767 + # # 2nd line = info
  2768 + # print '%-8s %-7s %-7s %-7s %-7s %-7s' % (self.type, macros, autoexec, suspicious, iocs, hexstrings)
  2769 + except Exception as exc:
  2770 + # display the exception with full stack trace for debugging only
  2771 + log.debug('Error processing file %s (%s)' % (self.filename, exc),
  2772 + exc_info=True)
  2773 + raise ProcessingError(self.filename, exc)
  2774 +
2776 2775
2777 # t = prettytable.PrettyTable(('filename', 'type', 'macros', 'autoexec', 'suspicious', 'ioc', 'hexstrings'), 2776 # t = prettytable.PrettyTable(('filename', 'type', 'macros', 'autoexec', 'suspicious', 'ioc', 'hexstrings'),
2778 # header=False, border=False) 2777 # header=False, border=False)
@@ -2888,39 +2887,53 @@ def main(): @@ -2888,39 +2887,53 @@ def main():
2888 # ignore directory names stored in zip files: 2887 # ignore directory names stored in zip files:
2889 if container and filename.endswith('/'): 2888 if container and filename.endswith('/'):
2890 continue 2889 continue
2891 - # Open the file 2890 +
2892 try: 2891 try:
  2892 + # Open the file
2893 vba_parser = VBA_Parser_CLI(filename, data=data, container=container) 2893 vba_parser = VBA_Parser_CLI(filename, data=data, container=container)
  2894 +
  2895 + if options.output_mode == 'detailed':
  2896 + # fully detailed output
  2897 + vba_parser.process_file(show_decoded_strings=options.show_decoded_strings,
  2898 + display_code=options.display_code,
  2899 + hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,
  2900 + show_deobfuscated_code=options.show_deobfuscated_code,
  2901 + deobfuscate=options.deobfuscate)
  2902 + elif options.output_mode in ('triage', 'unspecified'):
  2903 + # print container name when it changes:
  2904 + if container != previous_container:
  2905 + if container is not None:
  2906 + print '\nFiles in %s:' % container
  2907 + previous_container = container
  2908 + # summarized output for triage:
  2909 + vba_parser.process_file_triage(show_decoded_strings=options.show_decoded_strings,
  2910 + deobfuscate=options.deobfuscate)
  2911 + elif options.output_mode == 'json':
  2912 + json_results.append(
  2913 + vba_parser.process_file_json(show_decoded_strings=options.show_decoded_strings,
  2914 + display_code=options.display_code,
  2915 + hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,
  2916 + show_deobfuscated_code=options.show_deobfuscated_code))
  2917 + else: # (should be impossible)
  2918 + raise ValueError('unexpected output mode: "{0}"!'.format(options.output_mode))
  2919 + count += 1
  2920 +
2894 except FileOpenError as exc: 2921 except FileOpenError as exc:
2895 - log.exception('Failed to open %s (%s)!' % (filename, exc)) 2922 + if options.output_mode in ('triage', 'unspecified'):
  2923 + print '%-12s %s - File format not supported' % ('?', filename)
  2924 + else:
  2925 + log.exception('Failed to open %s -- probably not supported!' % filename)
2896 return_code = max(return_code, RETURN_OPEN_ERROR) 2926 return_code = max(return_code, RETURN_OPEN_ERROR)
2897 - continue 2927 + except ProcessingError as exc:
  2928 + if options.output_mode in ('triage', 'unspecified'):
  2929 + print '%-12s %s - %s' % ('!ERROR', filename, exc.orig_exception)
  2930 + else:
  2931 + log.exception('Error processing file %s (%s)!'
  2932 + % (filename, exc.orig_exception))
  2933 + return_code = max(return_code, RETURN_PARSE_ERROR)
  2934 + finally:
  2935 + vba_parser.close()
2898 2936
2899 - if options.output_mode == 'detailed':  
2900 - # fully detailed output  
2901 - vba_parser.process_file(show_decoded_strings=options.show_decoded_strings,  
2902 - display_code=options.display_code,  
2903 - hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,  
2904 - show_deobfuscated_code=options.show_deobfuscated_code,  
2905 - deobfuscate=options.deobfuscate)  
2906 - elif options.output_mode in ('triage', 'unspecified'):  
2907 - # print container name when it changes:  
2908 - if container != previous_container:  
2909 - if container is not None:  
2910 - print '\nFiles in %s:' % container  
2911 - previous_container = container  
2912 - # summarized output for triage:  
2913 - vba_parser.process_file_triage(show_decoded_strings=options.show_decoded_strings,  
2914 - deobfuscate=options.deobfuscate)  
2915 - elif options.output_mode == 'json':  
2916 - json_results.append(  
2917 - vba_parser.process_file_json(show_decoded_strings=options.show_decoded_strings,  
2918 - display_code=options.display_code,  
2919 - hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,  
2920 - show_deobfuscated_code=options.show_deobfuscated_code))  
2921 - else: # (should be impossible)  
2922 - raise ValueError('unexpected output mode: "{0}"!'.format(options.output_mode))  
2923 - count += 1  
2924 if options.output_mode == 'triage': 2937 if options.output_mode == 'triage':
2925 print '\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \ 2938 print '\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \
2926 'A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, ' \ 2939 'A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, ' \