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,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() |