Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

olevba: add projectcompatversion record #723

Merged
merged 3 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions oletools/olevba.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 234,7 @@
# 2020-09-28 PL: - added VBA_Parser.get_vba_code_all_modules (partial fix
# for issue #619)
# 2021-04-14 PL: - added detection of Workbook_BeforeClose (issue #518)
# 2021-11-09 KJ: - added PROJECTCOMPATVERSION Record on dir Stream

__version__ = '0.60.1.dev3'

Expand Down Expand Up @@ -1720,9 1721,25 @@ def __init__(self, ole, vba_root, project_path, dir_path, relaxed=True):
if self.syskind not in SYSKIND_NAME:
log.error("invalid PROJECTSYSKIND_SysKind {0:04X}".format(self.syskind))

# PROJECTLCID Record
# PROJECTLCID Record or PROJECTCOMPATVERSION Record
project_id = struct.unpack("<H", dir_stream.read(2))[0]
if project_id == 0x004A:
# PROJECTCOMPATVERSION Record
# Specifies the VBA project's compat version.
projectcompatversion_id = project_id
self.check_value('PROJETCOMPATVERSION_Id', 0x004A, projectcompatversion_id)
projectcompatversion_size = struct.unpack("<L", dir_stream.read(4))[0]
self.check_value('PROJECTCOMPATVERSION_Size', 0x0004, projectcompatversion_size)
projectcompatversion_compatversion = struct.unpack("<L", dir_stream.read(4))[0]
# compat version: A 32-bit number that identifies the Office Model version used by a VBA project.
log.debug("compat version: {compat_version}".format(compat_version=projectcompatversion_compatversion))

# PROJECTLCID Record
project_id = struct.unpack("<H", dir_stream.read(2))[0]

projectlcid_id = project_id

# Specifies the VBA project's LCID.
projectlcid_id = struct.unpack("<H", dir_stream.read(2))[0]
self.check_value('PROJECTLCID_Id', 0x0002, projectlcid_id)
projectlcid_size = struct.unpack("<L", dir_stream.read(4))[0]
self.check_value('PROJECTLCID_Size', 0x0004, projectlcid_size)
Expand Down
9 changes: 8 additions & 1 deletion tests/oleid/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 67,11 @@ def test_properties(self):
'949: ANSI/OEM Korean (Unified Hangul Code)')
self.assertEqual(value_dict['author'],
b'\xb1\xe8\xb1\xe2\xc1\xa4;kijeong')
elif 'olevba/sample_with_vba.ppt' in filename:
self.assertEqual(value_dict['codepage'],
'949: ANSI/OEM Korean (Unified Hangul Code)')
self.assertEqual(value_dict['author'],
b'\xb1\xe8 \xb1\xe2\xc1\xa4')
else:
self.assertEqual(value_dict['codepage'],
'1252: ANSI Latin 1; Western European (Windows)')
Expand Down Expand Up @@ -120,7 125,9 @@ def test_macros(self):
'msodde/dde-in-excel2003.xml', # same as above
'oleform/oleform-PR314.docm',
'basic/empty', # WTF?
'basic/text'): # no macros!
'basic/text', # no macros!
'olevba/sample_with_vba.ppt',
):
self.assertEqual(value_dict['vba'], 'Yes')
else:
self.assertEqual(value_dict['vba'], 'No')
Expand Down
18 changes: 18 additions & 0 deletions tests/olevba/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 103,24 @@ def test_crypt_return(self):
msg='Wrong return code {} for args {}'\
.format(ret_code, args [filename, ]))

def test_dir_stream_record_project_compat_version(self):
"""Test PROJECTCOMPATVERSION record on dir stream with a ppt file."""
input_file = join(DATA_BASE_DIR, 'olevba', 'sample_with_vba.ppt')
output, ret_code = call_and_capture('olevba', args=(input_file, "--loglevel", "debug"))

# check return code
self.assertEqual(ret_code, 0)

# not expected string:
self.assertNotIn('invalid value for PROJECTLCID_Id expected 0002 got', output)
self.assertNotIn('Error in _extract_vba', output)

# compat version in debug mode:
self.assertIn('compat version: 2', output)

# vba contents:
self.assertIn('Sub Action_Click()\n MsgBox "The action button clicked!"\nEnd Sub', output)


# just in case somebody calls this file as a script
if __name__ == '__main__':
Expand Down
Binary file added tests/test-data/olevba/sample_with_vba.ppt
Binary file not shown.