Commit ce3c92cf276c6048cd06f3ad04ac44f87d77d002

Authored by decalage2
1 parent 6f3de117

rtfobj: table output with tablestream

Showing 1 changed file with 57 additions and 37 deletions
oletools/rtfobj.py
@@ -59,6 +59,7 @@ http://www.decalage.info/python/oletools @@ -59,6 +59,7 @@ http://www.decalage.info/python/oletools
59 # 2016-07-19 PL: - fixed Python 2.6-2.7 support 59 # 2016-07-19 PL: - fixed Python 2.6-2.7 support
60 # 2016-07-30 PL: - new API with class RtfObject 60 # 2016-07-30 PL: - new API with class RtfObject
61 # - backward-compatible API rtf_iter_objects (fixed issue #70) 61 # - backward-compatible API rtf_iter_objects (fixed issue #70)
  62 +# 2016-07-31 PL: - table output with tablestream
62 63
63 __version__ = '0.50' 64 __version__ = '0.50'
64 65
@@ -76,6 +77,8 @@ from thirdparty.xglob import xglob @@ -76,6 +77,8 @@ from thirdparty.xglob import xglob
76 from oleobj import OleObject, OleNativeStream 77 from oleobj import OleObject, OleNativeStream
77 import oleobj 78 import oleobj
78 79
  80 +from thirdparty.tablestream import tablestream
  81 +
79 82
80 # === LOGGING ================================================================= 83 # === LOGGING =================================================================
81 84
@@ -601,6 +604,12 @@ def sanitize_filename(filename, replacement='_', max_length=200): @@ -601,6 +604,12 @@ def sanitize_filename(filename, replacement='_', max_length=200):
601 604
602 605
603 def process_file(container, filename, data, output_dir=None): 606 def process_file(container, filename, data, output_dir=None):
  607 + tstream = tablestream.TableStream(
  608 + column_width=(3, 10, 31, 31),
  609 + header_row=('id', 'index', 'OLE Object', 'OLE Package'),
  610 + style=tablestream.TableStyleSlim
  611 + )
  612 +
604 if output_dir: 613 if output_dir:
605 if not os.path.isdir(output_dir): 614 if not os.path.isdir(output_dir):
606 log.info('creating output directory %s' % output_dir) 615 log.info('creating output directory %s' % output_dir)
@@ -616,50 +625,62 @@ def process_file(container, filename, data, output_dir=None): @@ -616,50 +625,62 @@ def process_file(container, filename, data, output_dir=None):
616 # TODO: option to extract objects to files (false by default) 625 # TODO: option to extract objects to files (false by default)
617 if data is None: 626 if data is None:
618 data = open(filename, 'rb').read() 627 data = open(filename, 'rb').read()
619 - print('='*79)  
620 - print('File: %r - %d bytes' % (filename, len(data))) 628 + # print('='*79)
  629 + # print('File: %r - %d bytes' % (filename, len(data)))
621 rtfp = RtfObjParser(data) 630 rtfp = RtfObjParser(data)
622 rtfp.parse() 631 rtfp.parse()
623 for rtfobj in rtfp.objects: 632 for rtfobj in rtfp.objects:
624 - print('-'*79)  
625 - print('found object size %d at index %08X - end %08X'  
626 - % (len(rtfobj.rawdata), rtfobj.start, rtfobj.end))  
627 - fname = '%s_object_%08X.raw' % (fname_prefix, rtfobj.start)  
628 - print('saving object to file %s' % fname)  
629 - open(fname, 'wb').write(rtfobj.rawdata) 633 + # print('-'*79)
  634 + # print('found object size %d at index %08X - end %08X'
  635 + # % (len(rtfobj.rawdata), rtfobj.start, rtfobj.end))
  636 + # fname = '%s_object_%08X.raw' % (fname_prefix, rtfobj.start)
  637 + # print('saving object to file %s' % fname)
  638 + # open(fname, 'wb').write(rtfobj.rawdata)
630 if rtfobj.is_ole: 639 if rtfobj.is_ole:
631 - print('extract file embedded in OLE object:')  
632 - print('format_id = %d' % rtfobj.format_id)  
633 - print('class name = %r' % rtfobj.class_name)  
634 - print('data size = %d' % rtfobj.oledata_size) 640 + ole_column = 'format_id: %d\n' % rtfobj.format_id
  641 + ole_column += 'class name: %r\n' % rtfobj.class_name
  642 + ole_column += 'data size: %d' % rtfobj.oledata_size
  643 + # print('extract file embedded in OLE object:')
  644 + # print('format_id = %d' % rtfobj.format_id)
  645 + # print('class name = %r' % rtfobj.class_name)
  646 + # print('data size = %d' % rtfobj.oledata_size)
635 # set a file extension according to the class name: 647 # set a file extension according to the class name:
636 - class_name = rtfobj.class_name.lower()  
637 - if class_name.startswith(b'word'):  
638 - ext = 'doc'  
639 - elif class_name.startswith(b'package'):  
640 - ext = 'package'  
641 - else:  
642 - ext = 'bin'  
643 - fname = '%s_object_%08X.%s' % (fname_prefix, rtfobj.start, ext)  
644 - print('saving to file %s' % fname)  
645 - open(fname, 'wb').write(rtfobj.oledata) 648 + # class_name = rtfobj.class_name.lower()
  649 + # if class_name.startswith(b'word'):
  650 + # ext = 'doc'
  651 + # elif class_name.startswith(b'package'):
  652 + # ext = 'package'
  653 + # else:
  654 + # ext = 'bin'
  655 + # fname = '%s_object_%08X.%s' % (fname_prefix, rtfobj.start, ext)
  656 + # print('saving to file %s' % fname)
  657 + # open(fname, 'wb').write(rtfobj.oledata)
646 if rtfobj.is_package: 658 if rtfobj.is_package:
647 - print('Parsing OLE Package')  
648 - print('Filename = %r' % rtfobj.filename)  
649 - print('Source path = %r' % rtfobj.src_path)  
650 - print('Temp path = %r' % rtfobj.temp_path)  
651 - if rtfobj.filename:  
652 - fname = '%s_%s' % (fname_prefix,  
653 - sanitize_filename(rtfobj.filename))  
654 - else:  
655 - fname = '%s_object_%08X.noname' % (fname_prefix, rtfobj.start)  
656 - print('saving to file %s' % fname)  
657 - open(fname, 'wb').write(rtfobj.olepkgdata) 659 + pkg_column = 'Filename: %r\n' % rtfobj.filename
  660 + pkg_column += 'Source path: %r\n' % rtfobj.src_path
  661 + pkg_column += 'Temp path = %r' % rtfobj.temp_path
  662 + # print('Parsing OLE Package')
  663 + # print('Filename = %r' % rtfobj.filename)
  664 + # print('Source path = %r' % rtfobj.src_path)
  665 + # print('Temp path = %r' % rtfobj.temp_path)
  666 + # if rtfobj.filename:
  667 + # fname = '%s_%s' % (fname_prefix,
  668 + # sanitize_filename(rtfobj.filename))
  669 + # else:
  670 + # fname = '%s_object_%08X.noname' % (fname_prefix, rtfobj.start)
  671 + # print('saving to file %s' % fname)
  672 + # open(fname, 'wb').write(rtfobj.olepkgdata)
658 else: 673 else:
659 - print('Not an OLE Package') 674 + pkg_column = 'Not an OLE Package'
660 else: 675 else:
661 - print('Not a well-formed OLE object')  
662 - 676 + ole_column = 'Not a well-formed OLE object'
  677 + tstream.write_row((
  678 + rtfp.objects.index(rtfobj),
  679 + # filename,
  680 + '%08Xh' % rtfobj.start,
  681 + ole_column,
  682 + pkg_column
  683 + ))
663 684
664 685
665 #=== MAIN ================================================================= 686 #=== MAIN =================================================================
@@ -714,7 +735,6 @@ def main(): @@ -714,7 +735,6 @@ def main():
714 log.setLevel(logging.NOTSET) 735 log.setLevel(logging.NOTSET)
715 oleobj.log.setLevel(logging.NOTSET) 736 oleobj.log.setLevel(logging.NOTSET)
716 737
717 -  
718 for container, filename, data in xglob.iter_files(args, recursive=options.recursive, 738 for container, filename, data in xglob.iter_files(args, recursive=options.recursive,
719 zip_password=options.zip_password, zip_fname=options.zip_fname): 739 zip_password=options.zip_password, zip_fname=options.zip_fname):
720 # ignore directory names stored in zip files: 740 # ignore directory names stored in zip files: