Commit f2f6134ab04faf6c19fb7396467c9e4c50fc755a
1 parent
be57af2f
plugin_biff: updated to v0.0.17
New version of the BIFF plugin from Didier Stevens. Changelog: - 2020/05/26: 0.0.16 added logic for reserved bits in BOUNDSHEET - 2020/07/17: 0.0.17 added option --statistics Signed-off-by: Jürgen Löhel <juergen.loehel@inlyse.com>
Showing
1 changed file
with
41 additions
and
10 deletions
oletools/thirdparty/oledump/plugin_biff.py
| ... | ... | @@ -2,8 +2,8 @@ |
| 2 | 2 | |
| 3 | 3 | __description__ = 'BIFF plugin for oledump.py' |
| 4 | 4 | __author__ = 'Didier Stevens' |
| 5 | -__version__ = '0.0.15' | |
| 6 | -__date__ = '2020/05/22' | |
| 5 | +__version__ = '0.0.17' | |
| 6 | +__date__ = '2020/07/17' | |
| 7 | 7 | |
| 8 | 8 | # Slightly modified version by Philippe Lagadec to be imported into olevba |
| 9 | 9 | |
| ... | ... | @@ -41,7 +41,9 @@ History: |
| 41 | 41 | 2020/05/18: continue |
| 42 | 42 | 2020/05/20: 0.0.13 option -j |
| 43 | 43 | 2020/05/21: 0.0.14 improved parsing for a83890bbc081b9ec839c9a32ec06eae6f549a0f85fe0a30751ef229a58e440af, bc39d3bb128f329d95393bf0a4f6ec813356e847a00794c18258bfa48df6937f, 002a8371570487bc81eec4aeea9fdfb7 |
| 44 | - 2020/05/22: Python 3 fix STRING record 0x207 | |
| 44 | + 2020/05/22: 0.0.15 Python 3 fix STRING record 0x207 | |
| 45 | + 2020/05/26: 0.0.16 added logic for reserved bits in BOUNDSHEET | |
| 46 | + 2020/07/17: 0.0.17 added option --statistics | |
| 45 | 47 | |
| 46 | 48 | |
| 47 | 49 | Todo: |
| ... | ... | @@ -55,7 +57,14 @@ import json |
| 55 | 57 | # Modifications for olevba: |
| 56 | 58 | import sys |
| 57 | 59 | import binascii |
| 58 | -from .oledump_extract import * | |
| 60 | +from .oledump_extract import( | |
| 61 | + cPluginParent, | |
| 62 | + AddPlugin, | |
| 63 | + CIC, | |
| 64 | + IFF, | |
| 65 | + P23Ord, | |
| 66 | + P23Chr | |
| 67 | +) | |
| 59 | 68 | # end modifications |
| 60 | 69 | |
| 61 | 70 | DEFAULT_SEPARATOR = ',' |
| ... | ... | @@ -1301,8 +1310,6 @@ def DecodeRKValue(data): |
| 1301 | 1310 | if number & 0x01: |
| 1302 | 1311 | divider = 100.0 |
| 1303 | 1312 | if number & 0x02: |
| 1304 | - print(repr(data)) | |
| 1305 | - raise Exception('DecodeRKValue') | |
| 1306 | 1313 | return (struct.unpack('<i', data)[0] >> 2) / divider |
| 1307 | 1314 | else: |
| 1308 | 1315 | return struct.unpack('<d', b'\x00\x00\x00\x00' + data)[0] / divider |
| ... | ... | @@ -1607,6 +1614,7 @@ class cBIFF(cPluginParent): |
| 1607 | 1614 | oParser.add_option('-c', '--csv', action='store_true', default=False, help='Produce CSV') |
| 1608 | 1615 | oParser.add_option('-j', '--json', action='store_true', default=False, help='Produce JSON') |
| 1609 | 1616 | oParser.add_option('-r', '--cellrefformat', type=str, default='rc', help='Cell reference format (RC, LN)') |
| 1617 | + oParser.add_option('-S', '--statistics', action='store_true', default=False, help='Produce BIFF record statistics') | |
| 1610 | 1618 | (options, args) = oParser.parse_args(self.options.split(' ')) |
| 1611 | 1619 | |
| 1612 | 1620 | if options.find.startswith('0x'): |
| ... | ... | @@ -1619,12 +1627,14 @@ class cBIFF(cPluginParent): |
| 1619 | 1627 | sheetNames = [] |
| 1620 | 1628 | definesNames = [] |
| 1621 | 1629 | currentSheetname = '' |
| 1630 | + dOpcodeStatistics = {} | |
| 1622 | 1631 | while position < len(stream): |
| 1623 | 1632 | formatcodes = 'HH' |
| 1624 | 1633 | formatsize = struct.calcsize(formatcodes) |
| 1625 | 1634 | if len(stream[position:position + formatsize]) < formatsize: |
| 1626 | 1635 | break |
| 1627 | 1636 | opcode, length = struct.unpack(formatcodes, stream[position:position + formatsize]) |
| 1637 | + dOpcodeStatistics[opcode] = [dOpcodeStatistics.get(opcode, [0, 0])[0] + 1, dOpcodeStatistics.get(opcode, [0, 0])[1] + length] | |
| 1628 | 1638 | data = stream[position + formatsize:position + formatsize + length] |
| 1629 | 1639 | positionBIFFRecord = position |
| 1630 | 1640 | position = position + formatsize + length |
| ... | ... | @@ -1674,7 +1684,10 @@ class cBIFF(cPluginParent): |
| 1674 | 1684 | definesNames.append(name) |
| 1675 | 1685 | if flags & 0x01: |
| 1676 | 1686 | line += ' hidden' |
| 1677 | - parsedExpression, stack = ParseExpression(data[offset+lnName:offset+lnName+szFormula], definesNames, sheetNames, options.cellrefformat) | |
| 1687 | + try: | |
| 1688 | + parsedExpression, stack = ParseExpression(data[offset+lnName:offset+lnName+szFormula], definesNames, sheetNames, options.cellrefformat) | |
| 1689 | + except IndexError: | |
| 1690 | + parsedExpression = '*PARSING ERROR*' | |
| 1678 | 1691 | line += ' len=%d %s' % (szFormula, parsedExpression) |
| 1679 | 1692 | |
| 1680 | 1693 | # FILEPASS record |
| ... | ... | @@ -1689,11 +1702,17 @@ class cBIFF(cPluginParent): |
| 1689 | 1702 | dSheetType = {0: 'worksheet or dialog sheet', 1: 'Excel 4.0 macro sheet', 2: 'chart', 6: 'Visual Basic module'} |
| 1690 | 1703 | if sheetType == 1: |
| 1691 | 1704 | macros4Found = True |
| 1692 | - dSheetState = {0: 'visible', 1: 'hidden', 2: 'very hidden'} | |
| 1693 | 1705 | sheetName = ShortXLUnicodeString(data[6:]) |
| 1694 | 1706 | dSheetNames[positionBOF] = sheetName |
| 1695 | 1707 | sheetNames.append(sheetName) |
| 1696 | - line += ' - %s, %s - %s' % (dSheetType.get(sheetType, '%02x' % sheetType), dSheetState.get(sheetState, '%02x' % sheetState), sheetName) | |
| 1708 | + | |
| 1709 | + dSheetState = {0: 'visible', 1: 'hidden', 2: 'very hidden', 3: 'visibility=3'} | |
| 1710 | + visibility = '' | |
| 1711 | + if sheetState > 3: | |
| 1712 | + visibility = 'reserved bits not zero: 0x%02x ' % (sheetState & 0xFC) | |
| 1713 | + visibility += dSheetState.get(sheetState & 3, '0x%02x' % (sheetState & 3)) | |
| 1714 | + | |
| 1715 | + line += ' - %s, %s - %s' % (dSheetType.get(sheetType, '%02x' % sheetType), visibility, sheetName) | |
| 1697 | 1716 | |
| 1698 | 1717 | # BOF record |
| 1699 | 1718 | if opcode == 0x0809 and len(data) >= 4: |
| ... | ... | @@ -1715,7 +1734,6 @@ class cBIFF(cPluginParent): |
| 1715 | 1734 | if values[1] != []: |
| 1716 | 1735 | if strings != '': |
| 1717 | 1736 | strings += ' ' |
| 1718 | - print(values) | |
| 1719 | 1737 | strings += ' '.join(values[1]) |
| 1720 | 1738 | line += ' - %s' % strings |
| 1721 | 1739 | |
| ... | ... | @@ -1761,6 +1779,19 @@ class cBIFF(cPluginParent): |
| 1761 | 1779 | |
| 1762 | 1780 | if options.xlm and filepassFound: |
| 1763 | 1781 | result = ['FILEPASS record: file is password protected'] |
| 1782 | + elif options.statistics: | |
| 1783 | + stats = [] | |
| 1784 | + for opcode in sorted(dOpcodeStatistics.keys()): | |
| 1785 | + stats.append((opcode, dOpcodes.get(opcode, ''), dOpcodeStatistics[opcode][0], dOpcodeStatistics[opcode][1])) | |
| 1786 | + if options.csv: | |
| 1787 | + result = [MakeCSVLine(['opcode', 'description', 'count', 'totalsize'], DEFAULT_SEPARATOR, QUOTE)] | |
| 1788 | + else: | |
| 1789 | + result = [] | |
| 1790 | + for item in stats: | |
| 1791 | + if options.csv: | |
| 1792 | + result.append(MakeCSVLine(item, DEFAULT_SEPARATOR, QUOTE)) | |
| 1793 | + else: | |
| 1794 | + result.append('%d %s: %d %d' % item) | |
| 1764 | 1795 | elif options.xlm and not macros4Found: |
| 1765 | 1796 | result = [] |
| 1766 | 1797 | elif options.csv: | ... | ... |