Commit c556697486817d399f1f5f825e23792f3eff24b1
1 parent
977cdd30
olevba: KeyboardInterrupt is now raised properly in every function
Showing
1 changed file
with
53 additions
and
1 deletions
oletools/olevba.py
| @@ -160,13 +160,13 @@ https://github.com/unixfreak0037/officeparser | @@ -160,13 +160,13 @@ https://github.com/unixfreak0037/officeparser | ||
| 160 | # - improved logging, added -l option | 160 | # - improved logging, added -l option |
| 161 | # 2016-01-31 PL: - fixed issue #31 in VBA_Parser.open_mht | 161 | # 2016-01-31 PL: - fixed issue #31 in VBA_Parser.open_mht |
| 162 | # - fixed issue #32 by monkeypatching email.feedparser | 162 | # - fixed issue #32 by monkeypatching email.feedparser |
| 163 | +# 2016-02-07 PL: - KeyboardInterrupt is now raised properly | ||
| 163 | 164 | ||
| 164 | __version__ = '0.42' | 165 | __version__ = '0.42' |
| 165 | 166 | ||
| 166 | #------------------------------------------------------------------------------ | 167 | #------------------------------------------------------------------------------ |
| 167 | # TODO: | 168 | # TODO: |
| 168 | # + option --fast to disable VBA expressions parsing | 169 | # + option --fast to disable VBA expressions parsing |
| 169 | -# + do not use logging, but a provided logger (null logger by default) | ||
| 170 | # + setup logging (common with other oletools) | 170 | # + setup logging (common with other oletools) |
| 171 | # + add xor bruteforcing like bbharvest | 171 | # + add xor bruteforcing like bbharvest |
| 172 | # + options -a and -c should imply -d | 172 | # + options -a and -c should imply -d |
| @@ -187,6 +187,7 @@ __version__ = '0.42' | @@ -187,6 +187,7 @@ __version__ = '0.42' | ||
| 187 | # - extract_macros: convert to a class, split long function into smaller methods | 187 | # - extract_macros: convert to a class, split long function into smaller methods |
| 188 | # - extract_macros: read bytes from stream file objects instead of strings | 188 | # - extract_macros: read bytes from stream file objects instead of strings |
| 189 | # - extract_macros: use combined struct.unpack instead of many calls | 189 | # - extract_macros: use combined struct.unpack instead of many calls |
| 190 | +# - all except clauses should target specific exceptions | ||
| 190 | 191 | ||
| 191 | #------------------------------------------------------------------------------ | 192 | #------------------------------------------------------------------------------ |
| 192 | # REFERENCES: | 193 | # REFERENCES: |
| @@ -778,6 +779,9 @@ def mso_file_extract(data): | @@ -778,6 +779,9 @@ def mso_file_extract(data): | ||
| 778 | try: | 779 | try: |
| 779 | offset = struct.unpack_from('<H', data, offset=0x1E)[0] + 46 | 780 | offset = struct.unpack_from('<H', data, offset=0x1E)[0] + 46 |
| 780 | log.debug('Parsing MSO file: data offset = 0x%X' % offset) | 781 | log.debug('Parsing MSO file: data offset = 0x%X' % offset) |
| 782 | + except KeyboardInterrupt: | ||
| 783 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 784 | + raise | ||
| 781 | except: | 785 | except: |
| 782 | log.exception('Unable to parse MSO/ActiveMime file header') | 786 | log.exception('Unable to parse MSO/ActiveMime file header') |
| 783 | raise RuntimeError('Unable to parse MSO/ActiveMime file header') | 787 | raise RuntimeError('Unable to parse MSO/ActiveMime file header') |
| @@ -790,6 +794,9 @@ def mso_file_extract(data): | @@ -790,6 +794,9 @@ def mso_file_extract(data): | ||
| 790 | log.debug('Attempting zlib decompression from MSO file offset 0x%X' % start) | 794 | log.debug('Attempting zlib decompression from MSO file offset 0x%X' % start) |
| 791 | extracted_data = zlib.decompress(data[start:]) | 795 | extracted_data = zlib.decompress(data[start:]) |
| 792 | return extracted_data | 796 | return extracted_data |
| 797 | + except KeyboardInterrupt: | ||
| 798 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 799 | + raise | ||
| 793 | except: | 800 | except: |
| 794 | log.exception('zlib decompression failed') | 801 | log.exception('zlib decompression failed') |
| 795 | # None of the guessed offsets worked, let's try brute-forcing by looking | 802 | # None of the guessed offsets worked, let's try brute-forcing by looking |
| @@ -801,6 +808,9 @@ def mso_file_extract(data): | @@ -801,6 +808,9 @@ def mso_file_extract(data): | ||
| 801 | log.debug('Attempting zlib decompression from MSO file offset 0x%X' % start) | 808 | log.debug('Attempting zlib decompression from MSO file offset 0x%X' % start) |
| 802 | extracted_data = zlib.decompress(data[start:]) | 809 | extracted_data = zlib.decompress(data[start:]) |
| 803 | return extracted_data | 810 | return extracted_data |
| 811 | + except KeyboardInterrupt: | ||
| 812 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 813 | + raise | ||
| 804 | except: | 814 | except: |
| 805 | log.exception('zlib decompression failed') | 815 | log.exception('zlib decompression failed') |
| 806 | raise RuntimeError('Unable to decompress data from a MSO/ActiveMime file') | 816 | raise RuntimeError('Unable to decompress data from a MSO/ActiveMime file') |
| @@ -1506,6 +1516,9 @@ def detect_base64_strings(vba_code): | @@ -1506,6 +1516,9 @@ def detect_base64_strings(vba_code): | ||
| 1506 | decoded = base64.b64decode(value) | 1516 | decoded = base64.b64decode(value) |
| 1507 | results.append((value, decoded)) | 1517 | results.append((value, decoded)) |
| 1508 | found.add(value) | 1518 | found.add(value) |
| 1519 | + except KeyboardInterrupt: | ||
| 1520 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1521 | + raise | ||
| 1509 | except: | 1522 | except: |
| 1510 | # if an exception occurs, it is likely not a base64-encoded string | 1523 | # if an exception occurs, it is likely not a base64-encoded string |
| 1511 | pass | 1524 | pass |
| @@ -1533,6 +1546,9 @@ def detect_dridex_strings(vba_code): | @@ -1533,6 +1546,9 @@ def detect_dridex_strings(vba_code): | ||
| 1533 | decoded = DridexUrlDecode(value) | 1546 | decoded = DridexUrlDecode(value) |
| 1534 | results.append((value, decoded)) | 1547 | results.append((value, decoded)) |
| 1535 | found.add(value) | 1548 | found.add(value) |
| 1549 | + except KeyboardInterrupt: | ||
| 1550 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1551 | + raise | ||
| 1536 | except: | 1552 | except: |
| 1537 | # if an exception occurs, it is likely not a dridex-encoded string | 1553 | # if an exception occurs, it is likely not a dridex-encoded string |
| 1538 | pass | 1554 | pass |
| @@ -1858,6 +1874,9 @@ class VBA_Parser(object): | @@ -1858,6 +1874,9 @@ class VBA_Parser(object): | ||
| 1858 | # TODO: raise TypeError if this is a Powerpoint 97 file, since VBA macros cannot be detected yet | 1874 | # TODO: raise TypeError if this is a Powerpoint 97 file, since VBA macros cannot be detected yet |
| 1859 | # set type only if parsing succeeds | 1875 | # set type only if parsing succeeds |
| 1860 | self.type = TYPE_OLE | 1876 | self.type = TYPE_OLE |
| 1877 | + except KeyboardInterrupt: | ||
| 1878 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1879 | + raise | ||
| 1861 | except: | 1880 | except: |
| 1862 | # TODO: handle OLE parsing exceptions | 1881 | # TODO: handle OLE parsing exceptions |
| 1863 | log.exception('Failed OLE parsing for file %r' % self.filename) | 1882 | log.exception('Failed OLE parsing for file %r' % self.filename) |
| @@ -1887,12 +1906,18 @@ class VBA_Parser(object): | @@ -1887,12 +1906,18 @@ class VBA_Parser(object): | ||
| 1887 | ole_data = z.open(subfile).read() | 1906 | ole_data = z.open(subfile).read() |
| 1888 | try: | 1907 | try: |
| 1889 | self.ole_subfiles.append(VBA_Parser(filename=subfile, data=ole_data)) | 1908 | self.ole_subfiles.append(VBA_Parser(filename=subfile, data=ole_data)) |
| 1909 | + except KeyboardInterrupt: | ||
| 1910 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1911 | + raise | ||
| 1890 | except: | 1912 | except: |
| 1891 | log.debug('%s is not a valid OLE file' % subfile) | 1913 | log.debug('%s is not a valid OLE file' % subfile) |
| 1892 | continue | 1914 | continue |
| 1893 | z.close() | 1915 | z.close() |
| 1894 | # set type only if parsing succeeds | 1916 | # set type only if parsing succeeds |
| 1895 | self.type = TYPE_OpenXML | 1917 | self.type = TYPE_OpenXML |
| 1918 | + except KeyboardInterrupt: | ||
| 1919 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1920 | + raise | ||
| 1896 | except: | 1921 | except: |
| 1897 | # TODO: handle parsing exceptions | 1922 | # TODO: handle parsing exceptions |
| 1898 | log.exception('Failed Zip/OpenXML parsing for file %r' % self.filename) | 1923 | log.exception('Failed Zip/OpenXML parsing for file %r' % self.filename) |
| @@ -1923,12 +1948,18 @@ class VBA_Parser(object): | @@ -1923,12 +1948,18 @@ class VBA_Parser(object): | ||
| 1923 | ole_data = mso_file_extract(mso_data) | 1948 | ole_data = mso_file_extract(mso_data) |
| 1924 | try: | 1949 | try: |
| 1925 | self.ole_subfiles.append(VBA_Parser(filename=fname, data=ole_data)) | 1950 | self.ole_subfiles.append(VBA_Parser(filename=fname, data=ole_data)) |
| 1951 | + except KeyboardInterrupt: | ||
| 1952 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1953 | + raise | ||
| 1926 | except: | 1954 | except: |
| 1927 | log.error('%s does not contain a valid OLE file' % fname) | 1955 | log.error('%s does not contain a valid OLE file' % fname) |
| 1928 | else: | 1956 | else: |
| 1929 | log.error('%s is not a valid MSO file' % fname) | 1957 | log.error('%s is not a valid MSO file' % fname) |
| 1930 | # set type only if parsing succeeds | 1958 | # set type only if parsing succeeds |
| 1931 | self.type = TYPE_Word2003_XML | 1959 | self.type = TYPE_Word2003_XML |
| 1960 | + except KeyboardInterrupt: | ||
| 1961 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 1962 | + raise | ||
| 1932 | except: | 1963 | except: |
| 1933 | # TODO: differentiate exceptions for each parsing stage | 1964 | # TODO: differentiate exceptions for each parsing stage |
| 1934 | log.exception('Failed XML parsing for file %r' % self.filename) | 1965 | log.exception('Failed XML parsing for file %r' % self.filename) |
| @@ -1979,8 +2010,14 @@ class VBA_Parser(object): | @@ -1979,8 +2010,14 @@ class VBA_Parser(object): | ||
| 1979 | # TODO: check if it is actually an OLE file | 2010 | # TODO: check if it is actually an OLE file |
| 1980 | # TODO: get the MSO filename from content_location? | 2011 | # TODO: get the MSO filename from content_location? |
| 1981 | self.ole_subfiles.append(VBA_Parser(filename=fname, data=ole_data)) | 2012 | self.ole_subfiles.append(VBA_Parser(filename=fname, data=ole_data)) |
| 2013 | + except KeyboardInterrupt: | ||
| 2014 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2015 | + raise | ||
| 1982 | except: | 2016 | except: |
| 1983 | log.debug('%s does not contain a valid OLE file' % fname) | 2017 | log.debug('%s does not contain a valid OLE file' % fname) |
| 2018 | + except KeyboardInterrupt: | ||
| 2019 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2020 | + raise | ||
| 1984 | except: | 2021 | except: |
| 1985 | log.exception('Failed decompressing an MSO container in %r - %s' | 2022 | log.exception('Failed decompressing an MSO container in %r - %s' |
| 1986 | % (fname, MSG_OLEVBA_ISSUES)) | 2023 | % (fname, MSG_OLEVBA_ISSUES)) |
| @@ -1989,10 +2026,16 @@ class VBA_Parser(object): | @@ -1989,10 +2026,16 @@ class VBA_Parser(object): | ||
| 1989 | try: | 2026 | try: |
| 1990 | log.debug('type(part_data) = %s' % type(part_data)) | 2027 | log.debug('type(part_data) = %s' % type(part_data)) |
| 1991 | log.debug('part_data[0:20] = %r' % part_data[0:20]) | 2028 | log.debug('part_data[0:20] = %r' % part_data[0:20]) |
| 2029 | + except KeyboardInterrupt: | ||
| 2030 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2031 | + raise | ||
| 1992 | except: | 2032 | except: |
| 1993 | pass | 2033 | pass |
| 1994 | # set type only if parsing succeeds | 2034 | # set type only if parsing succeeds |
| 1995 | self.type = TYPE_MHTML | 2035 | self.type = TYPE_MHTML |
| 2036 | + except KeyboardInterrupt: | ||
| 2037 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2038 | + raise | ||
| 1996 | except: | 2039 | except: |
| 1997 | log.exception('Failed MIME parsing for file %r - %s' | 2040 | log.exception('Failed MIME parsing for file %r - %s' |
| 1998 | % (self.filename, MSG_OLEVBA_ISSUES)) | 2041 | % (self.filename, MSG_OLEVBA_ISSUES)) |
| @@ -2012,6 +2055,9 @@ class VBA_Parser(object): | @@ -2012,6 +2055,9 @@ class VBA_Parser(object): | ||
| 2012 | self.contains_macros = True | 2055 | self.contains_macros = True |
| 2013 | # set type only if parsing succeeds | 2056 | # set type only if parsing succeeds |
| 2014 | self.type = TYPE_TEXT | 2057 | self.type = TYPE_TEXT |
| 2058 | + except KeyboardInterrupt: | ||
| 2059 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2060 | + raise | ||
| 2015 | except: | 2061 | except: |
| 2016 | log.exception('Failed text parsing for file %r - %s' | 2062 | log.exception('Failed text parsing for file %r - %s' |
| 2017 | % (self.filename, MSG_OLEVBA_ISSUES)) | 2063 | % (self.filename, MSG_OLEVBA_ISSUES)) |
| @@ -2364,6 +2410,9 @@ class VBA_Parser_CLI(VBA_Parser): | @@ -2364,6 +2410,9 @@ class VBA_Parser_CLI(VBA_Parser): | ||
| 2364 | print self.reveal() | 2410 | print self.reveal() |
| 2365 | else: | 2411 | else: |
| 2366 | print 'No VBA macros found.' | 2412 | print 'No VBA macros found.' |
| 2413 | + except KeyboardInterrupt: | ||
| 2414 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2415 | + raise | ||
| 2367 | except: #TypeError: | 2416 | except: #TypeError: |
| 2368 | #raise | 2417 | #raise |
| 2369 | #TODO: print more info if debug mode | 2418 | #TODO: print more info if debug mode |
| @@ -2414,6 +2463,9 @@ class VBA_Parser_CLI(VBA_Parser): | @@ -2414,6 +2463,9 @@ class VBA_Parser_CLI(VBA_Parser): | ||
| 2414 | # file type not OLE nor OpenXML | 2463 | # file type not OLE nor OpenXML |
| 2415 | flags = '?' | 2464 | flags = '?' |
| 2416 | message = 'File format not supported' | 2465 | message = 'File format not supported' |
| 2466 | + except KeyboardInterrupt: | ||
| 2467 | + # do not ignore exceptions when the user presses Ctrl+C/Pause: | ||
| 2468 | + raise | ||
| 2417 | except: | 2469 | except: |
| 2418 | # another error occurred | 2470 | # another error occurred |
| 2419 | #raise | 2471 | #raise |