Commit aee53f45d53eb5027d1b89253c19ad4c1305ce74
1 parent
485c9edb
added option --json to olevba; make output modes mutually exclusive
Showing
1 changed file
with
27 additions
and
11 deletions
oletools/olevba.py
| ... | ... | @@ -2520,10 +2520,19 @@ def main(): |
| 2520 | 2520 | help='if the file is a zip archive, open all files from it, using the provided password (requires Python 2.6+)') |
| 2521 | 2521 | parser.add_option("-f", "--zipfname", dest='zip_fname', type='str', default='*', |
| 2522 | 2522 | help='if the file is a zip archive, file(s) to be opened within the zip. Wildcards * and ? are supported. (default:*)') |
| 2523 | - parser.add_option("-t", '--triage', action="store_true", dest="triage_mode", | |
| 2524 | - help='triage mode, display results as a summary table (default for multiple files)') | |
| 2525 | - parser.add_option("-d", '--detailed', action="store_true", dest="detailed_mode", | |
| 2526 | - help='detailed mode, display full results (default for single file)') | |
| 2523 | + # output mode; could make this even simpler with add_option(type='choice') but that would make | |
| 2524 | + # cmd line interface incompatible... | |
| 2525 | + modes = optparse.OptionGroup(parser, title='Output mode (mutually exclusive)') | |
| 2526 | + modes.add_option("-t", '--triage', action="store_const", dest="output_mode", | |
| 2527 | + const='triage', default='unspecified', | |
| 2528 | + help='triage mode, display results as a summary table (default for multiple files)') | |
| 2529 | + modes.add_option("-d", '--detailed', action="store_const", dest="output_mode", | |
| 2530 | + const='detailed', default='unspecified', | |
| 2531 | + help='detailed mode, display full results (default for single file)') | |
| 2532 | + modes.add_option("-j", '--json', action="store_const", dest="output_mode", | |
| 2533 | + const='json', default='unspecified', | |
| 2534 | + help='json mode, detailed in json format (never default)') | |
| 2535 | + parser.add_option_group(modes) | |
| 2527 | 2536 | parser.add_option("-a", '--analysis', action="store_false", dest="display_code", default=True, |
| 2528 | 2537 | help='display only analysis results, not the macro source code') |
| 2529 | 2538 | parser.add_option("-c", '--code', action="store_true", dest="vba_code_only", default=False, |
| ... | ... | @@ -2546,6 +2555,8 @@ def main(): |
| 2546 | 2555 | # TODO: --novba to disable VBA expressions parsing |
| 2547 | 2556 | |
| 2548 | 2557 | (options, args) = parser.parse_args() |
| 2558 | + print options.output_mode | |
| 2559 | + sys.exit() | |
| 2549 | 2560 | |
| 2550 | 2561 | # Print help if no arguments are passed |
| 2551 | 2562 | if len(args) == 0: |
| ... | ... | @@ -2573,8 +2584,9 @@ def main(): |
| 2573 | 2584 | # print '%-8s %-7s %-7s %-7s %-7s %-7s' % ('Type', 'Macros', 'AutoEx', 'Susp.', 'IOCs', 'HexStr') |
| 2574 | 2585 | # print '%-8s %-7s %-7s %-7s %-7s %-7s' % ('-'*8, '-'*7, '-'*7, '-'*7, '-'*7, '-'*7) |
| 2575 | 2586 | |
| 2576 | - # Column headers (except if detailed mode) | |
| 2577 | - if not options.detailed_mode or options.triage_mode: | |
| 2587 | + # Column headers (do not know how many files there will be yet, so if no output_mode | |
| 2588 | + # was specified, we will print triage for first file --> need these headers) | |
| 2589 | + if options.output_mode in ('triage', 'unspecified'): | |
| 2578 | 2590 | print '%-12s %-65s' % ('Flags', 'Filename') |
| 2579 | 2591 | print '%-12s %-65s' % ('-' * 11, '-' * 65) |
| 2580 | 2592 | |
| ... | ... | @@ -2589,13 +2601,13 @@ def main(): |
| 2589 | 2601 | continue |
| 2590 | 2602 | # Open the file |
| 2591 | 2603 | vba_parser = VBA_Parser_CLI(filename, data=data, container=container) |
| 2592 | - if options.detailed_mode and not options.triage_mode: | |
| 2604 | + if options.output_mode == 'detailed': | |
| 2593 | 2605 | # fully detailed output |
| 2594 | 2606 | vba_parser.process_file(show_decoded_strings=options.show_decoded_strings, |
| 2595 | 2607 | display_code=options.display_code, global_analysis=True, #options.global_analysis, |
| 2596 | 2608 | hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only, |
| 2597 | 2609 | show_deobfuscated_code=options.show_deobfuscated_code) |
| 2598 | - else: | |
| 2610 | + elif options.output_mode in ('triage', 'unspecified'): | |
| 2599 | 2611 | # print container name when it changes: |
| 2600 | 2612 | if container != previous_container: |
| 2601 | 2613 | if container is not None: |
| ... | ... | @@ -2603,14 +2615,18 @@ def main(): |
| 2603 | 2615 | previous_container = container |
| 2604 | 2616 | # summarized output for triage: |
| 2605 | 2617 | vba_parser.process_file_triage(show_decoded_strings=options.show_decoded_strings) |
| 2618 | + elif options.output_mode == 'json': | |
| 2619 | + raise NotImplementedError('about to add json output!') | |
| 2620 | + else: # (should be impossible) | |
| 2621 | + raise ValueError('unexpected output mode: "{0}"!'.format(options.output_mode)) | |
| 2606 | 2622 | count += 1 |
| 2607 | - if not options.detailed_mode or options.triage_mode: | |
| 2623 | + if options.output_mode == 'triage': | |
| 2608 | 2624 | print '\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \ |
| 2609 | 2625 | 'A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, ' \ |
| 2610 | 2626 | 'B=Base64 strings, D=Dridex strings, V=VBA strings, ?=Unknown)\n' |
| 2611 | 2627 | |
| 2612 | - if count == 1 and not options.triage_mode and not options.detailed_mode: | |
| 2613 | - # if options -t and -d were not specified and it's a single file, print details: | |
| 2628 | + if count == 1 and options.output_mode == 'unspecified': | |
| 2629 | + # if options -t, -d and -j were not specified and it's a single file, print details: | |
| 2614 | 2630 | vba_parser.process_file(show_decoded_strings=options.show_decoded_strings, |
| 2615 | 2631 | display_code=options.display_code, global_analysis=True, #options.global_analysis, |
| 2616 | 2632 | hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only, | ... | ... |