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 324 #--- CONSTANTS ----------------------------------------------------------------
325 325  
326 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 336 # URL and message to report issues:
334 337 URL_OLEVBA_ISSUES = 'https://bitbucket.org/decalage/oletools/issues'
... ... @@ -2849,7 +2852,7 @@ def main():
2849 2852 if len(args) == 0:
2850 2853 print __doc__
2851 2854 parser.print_help()
2852   - sys.exit()
  2855 + sys.exit(RETURN_WRONG_ARGS)
2853 2856  
2854 2857 # provide info about tool and its version
2855 2858 if options.output_mode == 'json':
... ... @@ -2882,85 +2885,95 @@ def main():
2882 2885 container = filename = data = None
2883 2886 vba_parser = None
2884 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 2949 display_code=options.display_code,
2899 2950 hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only,
2900 2951 show_deobfuscated_code=options.show_deobfuscated_code,
2901 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 2978 if __name__ == '__main__':
2966 2979 main()
... ...