Commit 5c03a4af1ac7a7b7a568ee92245042d60c9d215f

Authored by decalage2
2 parents fd821f0f 5f333b04

Merge remote-tracking branch 'kijeong/add/projectcompatversion_record'

# Conflicts:
#	tests/olevba/test_basic.py
oletools/olevba.py
... ... @@ -234,6 +234,7 @@ from __future__ import print_function
234 234 # 2020-09-28 PL: - added VBA_Parser.get_vba_code_all_modules (partial fix
235 235 # for issue #619)
236 236 # 2021-04-14 PL: - added detection of Workbook_BeforeClose (issue #518)
  237 +# 2021-11-09 KJ: - added PROJECTCOMPATVERSION Record on dir Stream
237 238  
238 239 __version__ = '0.60.2dev1'
239 240  
... ... @@ -1701,9 +1702,25 @@ class VBA_Project(object):
1701 1702 if self.syskind not in SYSKIND_NAME:
1702 1703 log.error("invalid PROJECTSYSKIND_SysKind {0:04X}".format(self.syskind))
1703 1704  
1704   - # PROJECTLCID Record
  1705 + # PROJECTLCID Record or PROJECTCOMPATVERSION Record
  1706 + project_id = struct.unpack("<H", dir_stream.read(2))[0]
  1707 + if project_id == 0x004A:
  1708 + # PROJECTCOMPATVERSION Record
  1709 + # Specifies the VBA project's compat version.
  1710 + projectcompatversion_id = project_id
  1711 + self.check_value('PROJETCOMPATVERSION_Id', 0x004A, projectcompatversion_id)
  1712 + projectcompatversion_size = struct.unpack("<L", dir_stream.read(4))[0]
  1713 + self.check_value('PROJECTCOMPATVERSION_Size', 0x0004, projectcompatversion_size)
  1714 + projectcompatversion_compatversion = struct.unpack("<L", dir_stream.read(4))[0]
  1715 + # compat version: A 32-bit number that identifies the Office Model version used by a VBA project.
  1716 + log.debug("compat version: {compat_version}".format(compat_version=projectcompatversion_compatversion))
  1717 +
  1718 + # PROJECTLCID Record
  1719 + project_id = struct.unpack("<H", dir_stream.read(2))[0]
  1720 +
  1721 + projectlcid_id = project_id
  1722 +
1705 1723 # Specifies the VBA project's LCID.
1706   - projectlcid_id = struct.unpack("<H", dir_stream.read(2))[0]
1707 1724 self.check_value('PROJECTLCID_Id', 0x0002, projectlcid_id)
1708 1725 projectlcid_size = struct.unpack("<L", dir_stream.read(4))[0]
1709 1726 self.check_value('PROJECTLCID_Size', 0x0004, projectlcid_size)
... ...
tests/oleid/test_basic.py
... ... @@ -67,6 +67,11 @@ class TestOleIDBasic(unittest.TestCase):
67 67 '949: ANSI/OEM Korean (Unified Hangul Code)')
68 68 self.assertEqual(value_dict['author'],
69 69 b'\xb1\xe8\xb1\xe2\xc1\xa4;kijeong')
  70 + elif 'olevba/sample_with_vba.ppt' in filename:
  71 + self.assertEqual(value_dict['codepage'],
  72 + '949: ANSI/OEM Korean (Unified Hangul Code)')
  73 + self.assertEqual(value_dict['author'],
  74 + b'\xb1\xe8 \xb1\xe2\xc1\xa4')
70 75 else:
71 76 self.assertEqual(value_dict['codepage'],
72 77 '1252: ANSI Latin 1; Western European (Windows)')
... ... @@ -120,7 +125,9 @@ class TestOleIDBasic(unittest.TestCase):
120 125 'msodde/dde-in-excel2003.xml', # same as above
121 126 'oleform/oleform-PR314.docm',
122 127 'basic/empty', # WTF?
123   - 'basic/text'): # no macros!
  128 + 'basic/text', # no macros!
  129 + 'olevba/sample_with_vba.ppt',
  130 + ):
124 131 self.assertEqual(value_dict['vba'], 'Yes')
125 132 else:
126 133 self.assertEqual(value_dict['vba'], 'No')
... ...
tests/olevba/test_basic.py
... ... @@ -147,6 +147,24 @@ class TestOlevbaBasic(unittest.TestCase):
147 147 self.assertIn('AutoExec', types)
148 148 self.assertIn('Suspicious', types)
149 149  
  150 + def test_dir_stream_record_project_compat_version(self):
  151 + """Test PROJECTCOMPATVERSION record on dir stream with a ppt file."""
  152 + input_file = join(DATA_BASE_DIR, 'olevba', 'sample_with_vba.ppt')
  153 + output, ret_code = call_and_capture('olevba', args=(input_file, "--loglevel", "debug"))
  154 +
  155 + # check return code
  156 + self.assertEqual(ret_code, 0)
  157 +
  158 + # not expected string:
  159 + self.assertNotIn('invalid value for PROJECTLCID_Id expected 0002 got', output)
  160 + self.assertNotIn('Error in _extract_vba', output)
  161 +
  162 + # compat version in debug mode:
  163 + self.assertIn('compat version: 2', output)
  164 +
  165 + # vba contents:
  166 + self.assertIn('Sub Action_Click()\n MsgBox "The action button clicked!"\nEnd Sub', output)
  167 +
150 168  
151 169 # just in case somebody calls this file as a script
152 170 if __name__ == '__main__':
... ...
tests/test-data/olevba/sample_with_vba.ppt 0 → 100644
No preview for this file type