From 1b2cf45f7d40413d73a7c30b9660a45c0d5cf636 Mon Sep 17 00:00:00 2001 From: Navdeep <18656134+nvdp01@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:00:25 +0530 Subject: [PATCH 1/4] Update oleform.py to account for string padding Account for padding of String values as described in MS-OFORMS Section 2.1.1.2.4 --- oletools/oleform.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/oletools/oleform.py b/oletools/oleform.py index d1fc69101..b91949848 100644 --- a/oletools/oleform.py +++ b/oletools/oleform.py @@ -310,20 +310,20 @@ def consume_OleSiteConcreteControl(stream): # SiteExtraDataBlock: [MS-OFORMS] 2.2.10.12.4 name = None if (name_len > 0): - name = stream.read(name_len) - # Consume 2 null bytes between name and tag. - #if ((tag_len > 0) or (control_tip_text_len > 0)): - # stream.read(2) - # # Sometimes it looks like 2 extra null bytes go here whether or not there is a tag. + with stream.will_pad(): + name = stream.read(name_len) tag = None if (tag_len > 0): - tag = stream.read(tag_len) + with stream.will_pad(): + tag = stream.read(tag_len) # Skip SitePosition. if propmask.fPosition: stream.read(8) - control_tip_text = stream.read(control_tip_text_len) - if (len(control_tip_text) == 0): + if (control_tip_text_len == 0): control_tip_text = None + else: + with stream.will_pad(): + control_tip_text = stream.read(control_tip_text_len) return {'name': name, 'tag': tag, 'id': id, 'tabindex': tabindex, 'ClsidCacheIndex': ClsidCacheIndex, 'value': None, 'caption': None, 'control_tip_text':control_tip_text} @@ -400,15 +400,20 @@ def consume_MorphDataControl(stream): # MorphDataExtraDataBlock: [MS-OFORMS] 2.2.5.4 # Discard Size stream.read(8) - value = stream.read(value_size) + value = "" + if (value_size > 0): + with stream.will_pad(): + value = stream.read(value_size) # Read caption text. caption = "" if (caption_size > 0): - caption = stream.read(caption_size) + with stream.will_pad(): + caption = stream.read(caption_size) # Read groupname text. group_name = "" if (group_name_size > 0): - group_name = stream.read(group_name_size) + with stream.will_pad(): + group_name = stream.read(group_name_size) # MorphDataStreamData: [MS-OFORMS] 2.2.5.5 if propmask.fMouseIcon: @@ -502,7 +507,10 @@ def consume_LabelControl(stream): ('fSpecialEffect', 2), ('fPicture', 2), ('fAccelerator', 2), ('fMouseIcon', 2)]) # LabelExtraDataBlock: [MS-OFORMS] 2.2.4.4 - caption = stream.read(caption_size) + caption = "" + if (caption_size > 0): + with stream.will_pad(): + caption = stream.read(caption_size) stream.read(8) # LabelStreamData: [MS-OFORMS] 2.2.4.5 if propmask.fPicture: From bc7c53f038c69b2aa707e319639c7d5f479fba08 Mon Sep 17 00:00:00 2001 From: Navdeep <18656134+nvdp01@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:08:10 +0530 Subject: [PATCH 2/4] Fix mask names in FormPropMask Updated FormPropMask _names list to remove duplicated 'fBooleanProperties' and add missing 'fBorderStyle' --- oletools/oleform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oletools/oleform.py b/oletools/oleform.py index b91949848..c9153153f 100644 --- a/oletools/oleform.py +++ b/oletools/oleform.py @@ -73,7 +73,7 @@ class FormPropMask(Mask): """FormPropMask: [MS-OFORMS] 2.2.10.2""" _size = 28 _names = ['Unused1', 'fBackColor', 'fForeColor', 'fNextAvailableID', 'Unused2_0', 'Unused2_1', - 'fBooleanProperties', 'fBooleanProperties', 'fMousePointer', 'fScrollBars', + 'fBooleanProperties', 'fBorderStyle', 'fMousePointer', 'fScrollBars', 'fDisplayedSize', 'fLogicalSize', 'fScrollPosition', 'fGroupCnt', 'Reserved', 'fMouseIcon', 'fCycle', 'fSpecialEffect', 'fBorderColor', 'fCaption', 'fFont', 'fPicture', 'fZoom', 'fPictureAlignment', 'fPictureTiling', 'fPictureSizeMode', From fd0f0c5bba5e9dd0742ee49ac672d114609587f5 Mon Sep 17 00:00:00 2001 From: Navdeep <18656134+nvdp01@users.noreply.github.com> Date: Wed, 29 Jun 2022 18:13:41 +0530 Subject: [PATCH 3/4] Add handling for Frame controls Add a function consume_EmbeddedFormControl() which extracts and returns caption value from an i sub-stream for Frame controls (having ClsidCacheIndex = 14) --- oletools/oleform.py | 47 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/oletools/oleform.py b/oletools/oleform.py index c9153153f..dabec2006 100644 --- a/oletools/oleform.py +++ b/oletools/oleform.py @@ -532,6 +532,39 @@ def consume_ScrollBarControl(stream): if propmask.fMouseIcon: consume_GuidAndPicture(stream) +def consume_EmbeddedFormControl(stream): + # FormControl: [MS-OFORMS] 2.2.10.1 + stream.check_values('FormControl (versions)', ' 0): + with stream.will_pad(): + caption = stream.read(caption_size) + # Ignore rest of the stream + return caption + def extract_OleFormVariables(ole_file, stream_dir): control = ExtendedStream.open(ole_file, '/'.join(stream_dir + ['f'])) variables = list(consume_FormControl(control)) @@ -543,7 +576,19 @@ def extract_OleFormVariables(ole_file, stream_dir): elif var['ClsidCacheIndex'] == 12: consume_ImageControl(data) elif var['ClsidCacheIndex'] == 14: - consume_FormControl(data) + # Frame Control: [MS-OFORMS] 2.2.2 + # Also see Embedded Parents : [MS-OFORMS] 2.1.2.2.2 + if var['id'] < 10: + embedded_fstream_dir = '/'.join(stream_dir + ['i0'+str(var['id'])] + ['f']) + else: + embedded_fstream_dir = '/'.join(stream_dir + ['i'+str(var['id'])] + ['f']) + + try: + embedded_form_control = ExtendedStream.open(ole_file, embedded_fstream_dir) + except: + pass + else: + var['caption'] = consume_EmbeddedFormControl(embedded_form_control) elif var['ClsidCacheIndex'] in [15, 23, 24, 25, 26, 27, 28]: var['value'], var['caption'], var['group_name'] = consume_MorphDataControl(data) elif var['ClsidCacheIndex'] == 16: From cddce22e8e70c5da92576f61bb9e7ec262ff0129 Mon Sep 17 00:00:00 2001 From: Navdeep <18656134+nvdp01@users.noreply.github.com> Date: Sat, 16 Jul 2022 16:10:32 +0530 Subject: [PATCH 4/4] Extract caption from CommandButton controls Update consume_CommandButtonControl() to extract Caption value --- oletools/oleform.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/oletools/oleform.py b/oletools/oleform.py index dabec2006..16b49dfb3 100644 --- a/oletools/oleform.py +++ b/oletools/oleform.py @@ -442,13 +442,31 @@ def consume_CommandButtonControl(stream): cbCommandButton = stream.unpack(' 0): + with stream.will_pad(): + caption = stream.read(caption_size) + stream.read(8) + # CommandButtonStreamData: [MS-OFORMS] 2.2.1.5 if propmask.fPicture: consume_GuidAndPicture(stream) if propmask.fMouseIcon: consume_GuidAndPicture(stream) + # TextProps consume_TextProps(stream) + return caption def consume_SpinButtonControl(stream): # SpinButtonControl: [MS-OFORMS] 2.2.8.1 @@ -579,7 +597,7 @@ def extract_OleFormVariables(ole_file, stream_dir): # Frame Control: [MS-OFORMS] 2.2.2 # Also see Embedded Parents : [MS-OFORMS] 2.1.2.2.2 if var['id'] < 10: - embedded_fstream_dir = '/'.join(stream_dir + ['i0'+str(var['id'])] + ['f']) + embedded_fstream_dir = '/'.join(stream_dir + ['i0'+str(var['id'])] + ['f']) else: embedded_fstream_dir = '/'.join(stream_dir + ['i'+str(var['id'])] + ['f']) @@ -594,7 +612,7 @@ def extract_OleFormVariables(ole_file, stream_dir): elif var['ClsidCacheIndex'] == 16: consume_SpinButtonControl(data) elif var['ClsidCacheIndex'] == 17: - consume_CommandButtonControl(data) + var['caption'] = consume_CommandButtonControl(data) elif var['ClsidCacheIndex'] == 18: consume_TabStripControl(data) elif var['ClsidCacheIndex'] == 21: