Commit 8b1381cd12b8e9e94e2cc9df9fafa08f07b192b1
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() | ... | ... |