Commit 8b1381cd12b8e9e94e2cc9df9fafa08f07b192b1

Authored by Christian Herdtweck
1 parent 6641ac1a

wrap most of main into big try-except; changed return codes

Showing 1 changed file with 92 additions and 79 deletions
oletools/olevba.py
@@ -324,11 +324,14 @@ class MsoExtractionError(RuntimeError): @@ -324,11 +324,14 @@ class MsoExtractionError(RuntimeError):
324 #--- CONSTANTS ---------------------------------------------------------------- 324 #--- CONSTANTS ----------------------------------------------------------------
325 325
326 # return codes 326 # return codes
327 -RETURN_OK = 0  
328 -RETURN_PARSE_ERROR = 1  
329 -RETURN_OPEN_ERROR = 2  
330 -RETURN_FILE_NOT_FOUND = 3  
331 -RETURN_UNEXPECTED = 4 327 +RETURN_OK = 0
  328 +RETURN_WARNINGS = 1 # (reserved, not used yet)
  329 +RETURN_WRONG_ARGS = 2 # (fixed, built into optparse)
  330 +RETURN_OPEN_ERROR = 3
  331 +RETURN_PARSE_ERROR = 4
  332 +RETURN_FILE_NOT_FOUND = 5
  333 +RETURN_SEVERAL_ERRS = 6
  334 +RETURN_UNEXPECTED = 7
332 335
333 # URL and message to report issues: 336 # URL and message to report issues:
334 URL_OLEVBA_ISSUES = 'https://bitbucket.org/decalage/oletools/issues' 337 URL_OLEVBA_ISSUES = 'https://bitbucket.org/decalage/oletools/issues'
@@ -2849,7 +2852,7 @@ def main(): @@ -2849,7 +2852,7 @@ def main():
2849 if len(args) == 0: 2852 if len(args) == 0:
2850 print __doc__ 2853 print __doc__
2851 parser.print_help() 2854 parser.print_help()
2852 - sys.exit() 2855 + sys.exit(RETURN_WRONG_ARGS)
2853 2856
2854 # provide info about tool and its version 2857 # provide info about tool and its version
2855 if options.output_mode == 'json': 2858 if options.output_mode == 'json':
@@ -2882,85 +2885,95 @@ def main(): @@ -2882,85 +2885,95 @@ def main():
2882 container = filename = data = None 2885 container = filename = data = None
2883 vba_parser = None 2886 vba_parser = None
2884 return_code = RETURN_OK 2887 return_code = RETURN_OK
2885 - for container, filename, data in xglob.iter_files(args, recursive=options.recursive,  
2886 - zip_password=options.zip_password, zip_fname=options.zip_fname):  
2887 - # ignore directory names stored in zip files:  
2888 - if container and filename.endswith('/'):  
2889 - continue  
2890 -  
2891 - try:  
2892 - # Open the file  
2893 - vba_parser = VBA_Parser_CLI(filename, data=data, container=container) 2888 + try:
  2889 + for container, filename, data in xglob.iter_files(args, recursive=options.recursive,
  2890 + zip_password=options.zip_password, zip_fname=options.zip_fname):
  2891 + # ignore directory names stored in zip files:
  2892 + if container and filename.endswith('/'):
  2893 + continue
2894 2894
2895 - if options.output_mode == 'detailed':  
2896 - # fully detailed output  
2897 - vba_parser.process_file(show_decoded_strings=options.show_decoded_strings, 2895 + try:
  2896 + # Open the file
  2897 + vba_parser = VBA_Parser_CLI(filename, data=data, container=container)
  2898 +
  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 +
  2925 + except FileOpenError as exc:
  2926 + if options.output_mode in ('triage', 'unspecified'):
  2927 + print '%-12s %s - File format not supported' % ('?', filename)
  2928 + else:
  2929 + log.exception('Failed to open %s -- probably not supported!' % filename)
  2930 + return_code = RETURN_OPEN_ERROR if return_code == 0 else RETURN_SEVERAL_ERRS
  2931 + except ProcessingError as exc:
  2932 + if options.output_mode in ('triage', 'unspecified'):
  2933 + print '%-12s %s - %s' % ('!ERROR', filename, exc.orig_exception)
  2934 + else:
  2935 + log.exception('Error processing file %s (%s)!'
  2936 + % (filename, exc.orig_exception))
  2937 + return_code = RETURN_PARSE_ERROR if return_code == 0 else RETURN_SEVERAL_ERRS
  2938 + finally:
  2939 + vba_parser.close()
  2940 +
  2941 + if options.output_mode == 'triage':
  2942 + print '\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \
  2943 + 'A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, ' \
  2944 + 'B=Base64 strings, D=Dridex strings, V=VBA strings, ?=Unknown)\n'
  2945 +
  2946 + if count == 1 and options.output_mode == 'unspecified':
  2947 + # if options -t, -d and -j were not specified and it's a single file, print details:
  2948 + vba_parser.process_file(show_decoded_strings=options.show_decoded_strings,
2898 display_code=options.display_code, 2949 display_code=options.display_code,
2899 hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only, 2950 hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,
2900 show_deobfuscated_code=options.show_deobfuscated_code, 2951 show_deobfuscated_code=options.show_deobfuscated_code,
2901 deobfuscate=options.deobfuscate) 2952 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 -  
2921 - except FileOpenError as 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)  
2926 - return_code = max(return_code, RETURN_OPEN_ERROR)  
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()  
2936 -  
2937 - if options.output_mode == 'triage':  
2938 - print '\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \  
2939 - 'A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, ' \  
2940 - 'B=Base64 strings, D=Dridex strings, V=VBA strings, ?=Unknown)\n'  
2941 -  
2942 - if count == 1 and options.output_mode == 'unspecified':  
2943 - # if options -t, -d and -j were not specified and it's a single file, print details:  
2944 - vba_parser.process_file(show_decoded_strings=options.show_decoded_strings,  
2945 - display_code=options.display_code,  
2946 - hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,  
2947 - show_deobfuscated_code=options.show_deobfuscated_code,  
2948 - deobfuscate=options.deobfuscate)  
2949 -  
2950 - if options.output_mode == 'json':  
2951 - json_options = dict(check_circular=False, indent=4, ensure_ascii=False)  
2952 -  
2953 - # json.dump[s] cannot deal with unicode objects that are not properly  
2954 - # encoded --> encode in own function:  
2955 - json_results = json2ascii(json_results)  
2956 - #print_json(json_results)  
2957 -  
2958 - # if False: # options.outfile: # (option currently commented out)  
2959 - # with open(outfile, 'w') as write_handle:  
2960 - # json.dump(write_handle, **json_options)  
2961 - # else:  
2962 - print json.dumps(json_results, **json_options)  
2963 2953
  2954 + if options.output_mode == 'json':
  2955 + json_options = dict(check_circular=False, indent=4, ensure_ascii=False)
  2956 +
  2957 + # json.dump[s] cannot deal with unicode objects that are not properly
  2958 + # encoded --> encode in own function:
  2959 + json_results = json2ascii(json_results)
  2960 + #print_json(json_results)
  2961 +
  2962 + # if False: # options.outfile: # (option currently commented out)
  2963 + # with open(outfile, 'w') as write_handle:
  2964 + # json.dump(write_handle, **json_options)
  2965 + # else:
  2966 + print json.dumps(json_results, **json_options)
  2967 +
  2968 + except Exception as exc:
  2969 + # some unexpected error, maybe some of the types caught in except clauses
  2970 + # above were not sufficient. This is very bad, so log complete trace at exception level
  2971 + log.exception('Unhandled exception in main: %s' % exc, exc_info=True)
  2972 + return_code = RETURN_UNEXPECTED # even if there were others before -- this is more important
  2973 +
  2974 + # done. exit
  2975 + log.debug('will exit now with code %s' % return_code)
  2976 + sys.exit(return_code)
2964 2977
2965 if __name__ == '__main__': 2978 if __name__ == '__main__':
2966 main() 2979 main()