Commit aee53f45d53eb5027d1b89253c19ad4c1305ce74

Authored by Christian Herdtweck
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,
... ...