Commit f2f6134ab04faf6c19fb7396467c9e4c50fc755a

Authored by Jürgen Löhel
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>
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:
... ...