Commit 5c03a4af1ac7a7b7a568ee92245042d60c9d215f
Merge remote-tracking branch 'kijeong/add/projectcompatversion_record'
# Conflicts: # tests/olevba/test_basic.py
Showing
4 changed files
with
45 additions
and
3 deletions
oletools/olevba.py
| @@ -234,6 +234,7 @@ from __future__ import print_function | @@ -234,6 +234,7 @@ from __future__ import print_function | ||
| 234 | # 2020-09-28 PL: - added VBA_Parser.get_vba_code_all_modules (partial fix | 234 | # 2020-09-28 PL: - added VBA_Parser.get_vba_code_all_modules (partial fix |
| 235 | # for issue #619) | 235 | # for issue #619) |
| 236 | # 2021-04-14 PL: - added detection of Workbook_BeforeClose (issue #518) | 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 | __version__ = '0.60.2dev1' | 239 | __version__ = '0.60.2dev1' |
| 239 | 240 | ||
| @@ -1701,9 +1702,25 @@ class VBA_Project(object): | @@ -1701,9 +1702,25 @@ class VBA_Project(object): | ||
| 1701 | if self.syskind not in SYSKIND_NAME: | 1702 | if self.syskind not in SYSKIND_NAME: |
| 1702 | log.error("invalid PROJECTSYSKIND_SysKind {0:04X}".format(self.syskind)) | 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 | # Specifies the VBA project's LCID. | 1723 | # Specifies the VBA project's LCID. |
| 1706 | - projectlcid_id = struct.unpack("<H", dir_stream.read(2))[0] | ||
| 1707 | self.check_value('PROJECTLCID_Id', 0x0002, projectlcid_id) | 1724 | self.check_value('PROJECTLCID_Id', 0x0002, projectlcid_id) |
| 1708 | projectlcid_size = struct.unpack("<L", dir_stream.read(4))[0] | 1725 | projectlcid_size = struct.unpack("<L", dir_stream.read(4))[0] |
| 1709 | self.check_value('PROJECTLCID_Size', 0x0004, projectlcid_size) | 1726 | self.check_value('PROJECTLCID_Size', 0x0004, projectlcid_size) |
tests/oleid/test_basic.py
| @@ -67,6 +67,11 @@ class TestOleIDBasic(unittest.TestCase): | @@ -67,6 +67,11 @@ class TestOleIDBasic(unittest.TestCase): | ||
| 67 | '949: ANSI/OEM Korean (Unified Hangul Code)') | 67 | '949: ANSI/OEM Korean (Unified Hangul Code)') |
| 68 | self.assertEqual(value_dict['author'], | 68 | self.assertEqual(value_dict['author'], |
| 69 | b'\xb1\xe8\xb1\xe2\xc1\xa4;kijeong') | 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 | else: | 75 | else: |
| 71 | self.assertEqual(value_dict['codepage'], | 76 | self.assertEqual(value_dict['codepage'], |
| 72 | '1252: ANSI Latin 1; Western European (Windows)') | 77 | '1252: ANSI Latin 1; Western European (Windows)') |
| @@ -120,7 +125,9 @@ class TestOleIDBasic(unittest.TestCase): | @@ -120,7 +125,9 @@ class TestOleIDBasic(unittest.TestCase): | ||
| 120 | 'msodde/dde-in-excel2003.xml', # same as above | 125 | 'msodde/dde-in-excel2003.xml', # same as above |
| 121 | 'oleform/oleform-PR314.docm', | 126 | 'oleform/oleform-PR314.docm', |
| 122 | 'basic/empty', # WTF? | 127 | 'basic/empty', # WTF? |
| 123 | - 'basic/text'): # no macros! | 128 | + 'basic/text', # no macros! |
| 129 | + 'olevba/sample_with_vba.ppt', | ||
| 130 | + ): | ||
| 124 | self.assertEqual(value_dict['vba'], 'Yes') | 131 | self.assertEqual(value_dict['vba'], 'Yes') |
| 125 | else: | 132 | else: |
| 126 | self.assertEqual(value_dict['vba'], 'No') | 133 | self.assertEqual(value_dict['vba'], 'No') |
tests/olevba/test_basic.py
| @@ -147,6 +147,24 @@ class TestOlevbaBasic(unittest.TestCase): | @@ -147,6 +147,24 @@ class TestOlevbaBasic(unittest.TestCase): | ||
| 147 | self.assertIn('AutoExec', types) | 147 | self.assertIn('AutoExec', types) |
| 148 | self.assertIn('Suspicious', types) | 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 | # just in case somebody calls this file as a script | 169 | # just in case somebody calls this file as a script |
| 152 | if __name__ == '__main__': | 170 | if __name__ == '__main__': |
tests/test-data/olevba/sample_with_vba.ppt
0 → 100644
No preview for this file type