diff --git a/oletools/mraptor.py b/oletools/mraptor.py index b7f2343..f2d8b47 100755 --- a/oletools/mraptor.py +++ b/oletools/mraptor.py @@ -233,16 +233,16 @@ def main(): # Print help if no arguments are passed if len(args) == 0: - print __doc__ + print(__doc__) parser.print_help() - print '\nAn exit code is returned based on the analysis result:' + print('\nAn exit code is returned based on the analysis result:') for result in (Result_NoMacro, Result_NotMSOffice, Result_MacroOK, Result_Error, Result_Suspicious): - print ' - %d: %s' % (result.exit_code, result.name) + print(' - %d: %s' % (result.exit_code, result.name)) sys.exit() # print banner with version - print 'MacroRaptor %s - http://decalage.info/python/oletools' % __version__ - print 'This is work in progress, please report issues at %s' % URL_ISSUES + print('MacroRaptor %s - http://decalage.info/python/oletools' % __version__) + print('This is work in progress, please report issues at %s' % URL_ISSUES) logging.basicConfig(level=LOG_LEVELS[options.loglevel], format='%(levelname)-8s %(message)s') # enable logging in the modules: @@ -292,7 +292,7 @@ def main(): vba_code_all_modules = '' try: for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros(): - vba_code_all_modules += vba_code + '\n' + vba_code_all_modules += vba_code.decode('utf-8','replace') + '\n' except Exception as e: # log.error('Error when parsing VBA macros from file %r' % full_name) result = Result_Error @@ -319,9 +319,9 @@ def main(): global_result = result exitcode = result.exit_code - print '' - print 'Flags: A=AutoExec, W=Write, X=Execute' - print 'Exit code: %d - %s' % (exitcode, global_result.name) + print('') + print('Flags: A=AutoExec, W=Write, X=Execute') + print('Exit code: %d - %s' % (exitcode, global_result.name)) sys.exit(exitcode) if __name__ == '__main__': diff --git a/oletools/olemap.py b/oletools/olemap.py index e7b410d..74ff92c 100755 --- a/oletools/olemap.py +++ b/oletools/olemap.py @@ -90,14 +90,14 @@ FAT_COLORS = { if __name__ == '__main__': # print banner with version - print 'olemap %s - http://decalage.info/python/oletools' % __version__ + print('olemap %s - http://decalage.info/python/oletools' % __version__) fname = sys.argv[1] ole = olefile.OleFileIO(fname) - print 'FAT:' + print('FAT:') t = tablestream.TableStream([8, 12, 8, 8], header_row=['Sector #', 'Type', 'Offset', 'Next #']) - for i in xrange(ole.nb_sect): + for i in range(ole.nb_sect): fat_value = ole.fat[i] fat_type = FAT_TYPES.get(fat_value, '') color_type = FAT_COLORS.get(fat_value, FAT_COLORS['default']) @@ -106,15 +106,15 @@ if __name__ == '__main__': # print '%8X: %-12s offset=%08X next=%8X' % (i, fat_type, 0, fat_value) t.write_row(['%8X' % i, fat_type, '%08X' % offset, '%8X' % fat_value], colors=[None, color_type, None, None]) - print '' + print('') - print 'MiniFAT:' + print('MiniFAT:') # load MiniFAT if it wasn't already done: ole.loadminifat() - for i in xrange(len(ole.minifat)): + for i in range(len(ole.minifat)): fat_value = ole.minifat[i] fat_type = FAT_TYPES.get(fat_value, 'Data') - print '%8X: %-12s offset=%08X next=%8X' % (i, fat_type, 0, fat_value) + print('%8X: %-12s offset=%08X next=%8X' % (i, fat_type, 0, fat_value)) ole.close() diff --git a/oletools/oletimes.py b/oletools/oletimes.py index 3321e89..3419b87 100755 --- a/oletools/oletimes.py +++ b/oletools/oletimes.py @@ -94,6 +94,6 @@ for obj in ole.listdir(streams=True, storages=True): #print '- %s: mtime=%s ctime=%s' % (repr('/'.join(obj)), ole.getmtime(obj), ole.getctime(obj)) t.add_row((repr('/'.join(obj)), dt2str(ole.getmtime(obj)), dt2str(ole.getctime(obj)))) -print t +print(t) ole.close() diff --git a/oletools/olevba.py b/oletools/olevba.py index 4bd9998..9fb0e76 100755 --- a/oletools/olevba.py +++ b/oletools/olevba.py @@ -215,7 +215,7 @@ __version__ = '0.50' import sys, logging import struct -import cStringIO +from _io import StringIO,BytesIO import math import zipfile import re @@ -240,9 +240,9 @@ except ImportError: # Python <2.5: standalone ElementTree install import elementtree.cElementTree as ET except ImportError: - raise ImportError, "lxml or ElementTree are not installed, " \ + raise(ImportError, "lxml or ElementTree are not installed, " \ + "see http://codespeak.net/lxml " \ - + "or http://effbot.org/zone/element-index.htm" + + "or http://effbot.org/zone/element-index.htm") import thirdparty.olefile as olefile from thirdparty.prettytable import prettytable @@ -421,7 +421,7 @@ TYPE2TAG = { # MSO files ActiveMime header magic -MSO_ACTIVEMIME_HEADER = 'ActiveMime' +MSO_ACTIVEMIME_HEADER = b'ActiveMime' MODULE_EXTENSION = "bas" CLASS_EXTENSION = "cls" @@ -630,7 +630,7 @@ re_dridex_string = re.compile(r'"[0-9A-Za-z]{20,}"') re_nothex_check = re.compile(r'[G-Zg-z]') # regex to extract printable strings (at least 5 chars) from VBA Forms: -re_printable_string = re.compile(r'[\t\r\n\x20-\xFF]{5,}') +re_printable_string = re.compile(rb'[\t\r\n\x20-\xFF]{5,}') # === PARTIAL VBA GRAMMAR ==================================================== @@ -1060,10 +1060,10 @@ def decompress_stream(compressed_container): # DecompressedChunkStart: The location of the first byte of the DecompressedChunk (section 2.4.1.1.3) within the # DecompressedBuffer (section 2.4.1.1.2). - decompressed_container = '' # result + decompressed_container = b'' # result compressed_current = 0 - sig_byte = ord(compressed_container[compressed_current]) + sig_byte = compressed_container[compressed_current] if sig_byte != 0x01: raise ValueError('invalid signature byte {0:02X}'.format(sig_byte)) @@ -1109,7 +1109,7 @@ def decompress_stream(compressed_container): # MS-OVBA 2.4.1.3.3 Decompressing a RawChunk # uncompressed chunk: read the next 4096 bytes as-is #TODO: check if there are at least 4096 bytes left - decompressed_container += compressed_container[compressed_current:compressed_current + 4096] + decompressed_container += bytes([compressed_container[compressed_current:compressed_current + 4096]]) compressed_current += 4096 else: # MS-OVBA 2.4.1.3.2 Decompressing a CompressedChunk @@ -1120,9 +1120,9 @@ def decompress_stream(compressed_container): # log.debug('compressed_current = %d / compressed_end = %d' % (compressed_current, compressed_end)) # FlagByte: 8 bits indicating if the following 8 tokens are either literal (1 byte of plain text) or # copy tokens (reference to a previous literal token) - flag_byte = ord(compressed_container[compressed_current]) + flag_byte = compressed_container[compressed_current] compressed_current += 1 - for bit_index in xrange(0, 8): + for bit_index in range(0, 8): # log.debug('bit_index=%d / compressed_current=%d / compressed_end=%d' % (bit_index, compressed_current, compressed_end)) if compressed_current >= compressed_end: break @@ -1132,7 +1132,7 @@ def decompress_stream(compressed_container): #log.debug('bit_index=%d: flag_bit=%d' % (bit_index, flag_bit)) if flag_bit == 0: # LiteralToken # copy one byte directly to output - decompressed_container += compressed_container[compressed_current] + decompressed_container += bytes([compressed_container[compressed_current]]) compressed_current += 1 else: # CopyToken # MS-OVBA 2.4.1.3.19.2 Unpack CopyToken @@ -1147,8 +1147,8 @@ def decompress_stream(compressed_container): offset = (temp1 >> temp2) + 1 #log.debug('offset=%d length=%d' % (offset, length)) copy_source = len(decompressed_container) - offset - for index in xrange(copy_source, copy_source + length): - decompressed_container += decompressed_container[index] + for index in range(copy_source, copy_source + length): + decompressed_container += bytes([decompressed_container[index]]) compressed_current += 2 return decompressed_container @@ -1191,7 +1191,7 @@ def _extract_vba(ole, vba_root, project_path, dir_path, relaxed=False): code_modules = {} for line in project: - line = line.strip() + line = line.strip().decode('utf-8','ignore') if '=' in line: # split line at the 1st equal sign: name, value = line.split('=', 1) @@ -1222,7 +1222,7 @@ def _extract_vba(ole, vba_root, project_path, dir_path, relaxed=False): else: raise UnexpectedDataError(dir_path, name, expected, value) - dir_stream = cStringIO.StringIO(decompress_stream(dir_compressed)) + dir_stream = BytesIO(decompress_stream(dir_compressed)) # PROJECTSYSKIND Record projectsyskind_id = struct.unpack(" need these headers) if options.output_mode in ('triage', 'unspecified'): - print '%-12s %-65s' % ('Flags', 'Filename') - print '%-12s %-65s' % ('-' * 11, '-' * 65) + print('%-12s %-65s' % ('Flags', 'Filename')) + print('%-12s %-65s' % ('-' * 11, '-' * 65)) previous_container = None count = 0 @@ -3248,14 +3257,14 @@ def main(): if isinstance(data, Exception): if isinstance(data, PathNotFoundException): if options.output_mode in ('triage', 'unspecified'): - print '%-12s %s - File not found' % ('?', filename) + print('%-12s %s - File not found' % ('?', filename)) elif options.output_mode != 'json': log.error('Given path %r does not exist!' % filename) return_code = RETURN_FILE_NOT_FOUND if return_code == 0 \ else RETURN_SEVERAL_ERRS else: if options.output_mode in ('triage', 'unspecified'): - print '%-12s %s - Failed to read from zip file %s' % ('?', filename, container) + print('%-12s %s - Failed to read from zip file %s' % ('?', filename, container)) elif options.output_mode != 'json': log.error('Exception opening/reading %r from zip file %r: %s' % (filename, container, data)) @@ -3282,7 +3291,7 @@ def main(): # print container name when it changes: if container != previous_container: if container is not None: - print '\nFiles in %s:' % container + print('\nFiles in %s:' % container) previous_container = container # summarized output for triage: vba_parser.process_file_triage(show_decoded_strings=options.show_decoded_strings, @@ -3300,8 +3309,8 @@ def main(): except (SubstreamOpenError, UnexpectedDataError) as exc: if options.output_mode in ('triage', 'unspecified'): - print '%-12s %s - Error opening substream or uenxpected ' \ - 'content' % ('?', filename) + print('%-12s %s - Error opening substream or uenxpected ' \ + 'content' % ('?', filename)) elif options.output_mode == 'json': print_json(file=filename, type='error', error=type(exc).__name__, message=str(exc)) @@ -3312,7 +3321,7 @@ def main(): else RETURN_SEVERAL_ERRS except FileOpenError as exc: if options.output_mode in ('triage', 'unspecified'): - print '%-12s %s - File format not supported' % ('?', filename) + print('%-12s %s - File format not supported' % ('?', filename)) elif options.output_mode == 'json': print_json(file=filename, type='error', error=type(exc).__name__, message=str(exc)) @@ -3322,7 +3331,7 @@ def main(): else RETURN_SEVERAL_ERRS except ProcessingError as exc: if options.output_mode in ('triage', 'unspecified'): - print '%-12s %s - %s' % ('!ERROR', filename, exc.orig_exc) + print('%-12s %s - %s' % ('!ERROR', filename, exc.orig_exc)) elif options.output_mode == 'json': print_json(file=filename, type='error', error=type(exc).__name__, @@ -3337,9 +3346,9 @@ def main(): vba_parser.close() if options.output_mode == 'triage': - print '\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \ + print('\n(Flags: OpX=OpenXML, XML=Word2003XML, MHT=MHTML, TXT=Text, M=Macros, ' \ 'A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, ' \ - 'B=Base64 strings, D=Dridex strings, V=VBA strings, ?=Unknown)\n' + 'B=Base64 strings, D=Dridex strings, V=VBA strings, ?=Unknown)\n') if count == 1 and options.output_mode == 'unspecified': # if options -t, -d and -j were not specified and it's a single file, print details: diff --git a/oletools/ppt_parser.py b/oletools/ppt_parser.py index eb6d1c2..2f8ecd4 100644 --- a/oletools/ppt_parser.py +++ b/oletools/ppt_parser.py @@ -1570,4 +1570,4 @@ def iterative_decompress(stream, size, chunk_size=4096): if __name__ == '__main__': - print 'nothing here to run!' + print('nothing here to run!') diff --git a/oletools/thirdparty/olefile/olefile.py b/oletools/thirdparty/olefile/olefile.py index cd40472..6b5c149 100755 --- a/oletools/thirdparty/olefile/olefile.py +++ b/oletools/thirdparty/olefile/olefile.py @@ -1030,10 +1030,11 @@ class OleDirectoryEntry: #[PL] this method was added to use simple recursion instead of a complex # algorithm. # if this is not a storage or a leaf of the tree, nothing to do: + if child_sid == NOSTREAM: return # check if child SID is in the proper range: - if child_sid<0 or child_sid>=len(self.olefile.direntries): + if child_sid <= 0 or child_sid >= len(self.olefile.direntries): self.olefile._raise_defect(DEFECT_INCORRECT, 'OLE DirEntry index out of range') else: # get child direntry: diff --git a/oletools/thirdparty/olefile/olefile2.py b/oletools/thirdparty/olefile/olefile2.py index 7f5ab0e..c57a82b 100644 --- a/oletools/thirdparty/olefile/olefile2.py +++ b/oletools/thirdparty/olefile/olefile2.py @@ -1004,7 +1004,7 @@ class OleFileIO: TIFF files). """ - def __init__(self, filename = None, raise_defects=DEFECT_FATAL): + def __init__(self, filename = None, raise_defects=DEFECT_FATAL): """ Constructor for OleFileIO class. diff --git a/oletools/thirdparty/tablestream/tablestream.py b/oletools/thirdparty/tablestream/tablestream.py index 518d229..2daa2f8 100644 --- a/oletools/thirdparty/tablestream/tablestream.py +++ b/oletools/thirdparty/tablestream/tablestream.py @@ -236,7 +236,7 @@ class TableStream(object): assert len(row) == self.num_columns columns = [] max_lines = 0 - for i in xrange(self.num_columns): + for i in range(self.num_columns): cell = row[i] # Convert to string: # TODO: handle unicode properly @@ -245,7 +245,7 @@ class TableStream(object): # encode to UTF8, avoiding errors cell = cell.decode('utf-8', errors='replace') else: - cell = unicode(cell) + cell = cell # Wrap cell text according to the column width # TODO: use a TextWrapper object for each column instead # split the string if it contains newline characters, otherwise @@ -257,16 +257,16 @@ class TableStream(object): if colors is not None and self.outfile.isatty(): color = colors[i] if color: - for j in xrange(len(column)): + for j in range(len(column)): # print '%r: %s' % (column[j], type(column[j])) column[j] = colorclass.Color('{auto%s}%s{/%s}' % (color, column[j], color)) columns.append(column) # determine which column has the highest number of lines max_lines = max(len(columns[i]), max_lines) # transpose: write output line by line - for j in xrange(max_lines): + for j in range(max_lines): self.write(self.style.vertical_left) - for i in xrange(self.num_columns): + for i in range(self.num_columns): column = columns[i] if j