Commit 9d2795aa1a3b3af0d7255da9b63e7171e65af843
1 parent
425a038a
WIP: oleform: implement other types of stored controls
Showing
1 changed file
with
158 additions
and
3 deletions
oletools/oleform.py
| ... | ... | @@ -52,6 +52,52 @@ class MorphDataPropMask(Mask): |
| 52 | 52 | 'fBorderColor', 'fSpecialEffect', 'fMouseIcon', 'fPicture', 'fAccelerator', |
| 53 | 53 | 'UnusedBits2', 'Reserved', 'fGroupName'] |
| 54 | 54 | |
| 55 | +class ImagePropMask(Mask): | |
| 56 | + """ImagePropMask: [MS-OFORMS] 2.2.3.2""" | |
| 57 | + _size = 15 | |
| 58 | + _names = ['UnusedBits1_1', 'UnusedBits1_2', 'fAutoSize', 'fBorderColor', 'fBackColor', | |
| 59 | + 'fBorderStyle', 'fMousePointer', 'fPictureSizeMode', 'fSpecialEffect', 'fSize', | |
| 60 | + 'fPicture', 'fPictureAlignment', 'fPictureTiling', 'fVariousPropertyBits', | |
| 61 | + 'fMouseIcon'] | |
| 62 | + | |
| 63 | +class CommandButtonPropMask(Mask): | |
| 64 | + """CommandButtonPropMask: [MS-OFORMS] 2.2.1.2""" | |
| 65 | + _size = 11 | |
| 66 | + _names = ['fForeColor', 'fBackColor', 'fVariousPropertyBits', 'fCaption', 'fPicturePosition', | |
| 67 | + 'fSize', 'fMousePointer', 'fPicture', 'fAccelerator', 'fTakeFocusOnClick', | |
| 68 | + 'fMouseIcon'] | |
| 69 | + | |
| 70 | +class SpinButtonPropMask(Mask): | |
| 71 | + """SpinButtonPropMask: [MS-OFORMS] 2.2.8.2""" | |
| 72 | + _size = 15 | |
| 73 | + _names = ['fForeColor', 'fBackColor', 'fVariousPropertyBits', 'fSize', 'UnusedBits1', | |
| 74 | + 'fMin', 'fMax', 'fPosition', 'fPrevEnabled', 'fNextEnabled', 'fSmallChange', | |
| 75 | + 'fOrientation', 'fDelay', 'fMouseIcon', 'fMousePointer'] | |
| 76 | + | |
| 77 | +class TabStripPropMask(Mask): | |
| 78 | + """TabStripPropMask: [MS-OFORMS] 2.2.9.2""" | |
| 79 | + _size = 25 | |
| 80 | + _names = ['fListIndex', 'fBackColor', 'fForeColor', 'Unused1', 'fSize', 'fItems', | |
| 81 | + 'fMousePointer', 'Unused2', 'fTabOrientation', 'fTabStyle', 'fMultiRow', | |
| 82 | + 'fTabFixedWidth', 'fTabFixedHeight', 'fTooltips', 'Unused3', 'fTipStrings', | |
| 83 | + 'Unused4', 'fNames', 'fVariousPropertyBits', 'fNewVersion', 'fTabsAllocated', | |
| 84 | + 'fTags', 'fTabData', 'fAccelerator', 'fMouseIcon'] | |
| 85 | + | |
| 86 | +class LabelPropMask(Mask): | |
| 87 | + """LabelPropMask: [MS-OFORMS] 2.2.4.2""" | |
| 88 | + _size = 13 | |
| 89 | + _names = ['fForeColor', 'fBackColor', 'fVariousPropertyBits', 'fCaption', | |
| 90 | + 'fPicturePosition', 'fSize', 'fMousePointer', 'fBorderColor', 'fBorderStyle', | |
| 91 | + 'fSpecialEffect', 'fPicture', 'fAccelerator', 'fMouseIcon'] | |
| 92 | + | |
| 93 | +class ScrollBarPropMask(Mask): | |
| 94 | + """ScrollBarPropMask: [MS-OFORMS] 2.2.7.2""" | |
| 95 | + _size = 17 | |
| 96 | + _names = ['fForeColor', 'fBackColor', 'fVariousPropertyBits', 'fSize', 'fMousePointer', | |
| 97 | + 'fMin', 'fMax', 'fPosition', 'UnusedBits1', 'fPrevEnabled', 'fNextEnabled', | |
| 98 | + 'fSmallChange', 'fLargeChange', 'fOrientation', 'fProportionalThumb', | |
| 99 | + 'fDelay', 'fMouseIcon'] | |
| 100 | + | |
| 55 | 101 | class ExtendedStream(object): |
| 56 | 102 | def __init__(self, stream, path): |
| 57 | 103 | self._pos = 0 |
| ... | ... | @@ -287,16 +333,125 @@ def consume_MorphDataControl(stream): |
| 287 | 333 | consume_TextProps(stream) |
| 288 | 334 | return value |
| 289 | 335 | |
| 336 | +def consume_ImageControl(stream): | |
| 337 | + # ImageControl: [MS-OFORMS] 2.2.3.1 | |
| 338 | + stream.check_values('ImageControl (versions)', '<BB', 2, (0, 2)) | |
| 339 | + cbImage = stream.unpack('<H', 2) | |
| 340 | + with stream.will_jump_to(cbImage): | |
| 341 | + propmask = ImagePropMask(stream.unpack('<L', 4)) | |
| 342 | + # Skip the DataBlock and the ExtraDataBlock | |
| 343 | + # ImageStreamData: [MS-OFORMS] 2.2.3.5 | |
| 344 | + if propmask.fPicture: | |
| 345 | + consume_GuidAndPicture(stream) | |
| 346 | + if propmask.fMouseIcon: | |
| 347 | + consume_GuidAndPicture(stream) | |
| 348 | + | |
| 349 | +def consume_CommandButtonControl(stream): | |
| 350 | + # CommandButtonControl: [MS-OFORMS] 2.2.1.1 | |
| 351 | + stream.check_values('CommandButtonControl (versions)', '<BB', 2, (0, 2)) | |
| 352 | + cbCommandButton = stream.unpack('<H', 2) | |
| 353 | + with stream.will_jump_to(cbCommandButton): | |
| 354 | + propmask = CommandButtonPropMask(stream.unpack('<L', 4)) | |
| 355 | + # Skip the DataBlock and the ExtraDataBlock | |
| 356 | + # ImageStreamData: [MS-OFORMS] 2.2.1.5 | |
| 357 | + if propmask.fPicture: | |
| 358 | + consume_GuidAndPicture(stream) | |
| 359 | + if propmask.fMouseIcon: | |
| 360 | + consume_GuidAndPicture(stream) | |
| 361 | + consume_TextProps(stream) | |
| 362 | + | |
| 363 | +def consume_SpinButtonControl(stream): | |
| 364 | + # SpinButtonControl: [MS-OFORMS] 2.2.8.1 | |
| 365 | + stream.check_values('SpinButtonControl (versions)', '<BB', 2, (0, 2)) | |
| 366 | + cbSpinButton = stream.unpack('<H', 2) | |
| 367 | + with stream.will_jump_to(cbSpinButton): | |
| 368 | + propmask = SpinButtonPropMask(stream.unpack('<L', 4)) | |
| 369 | + # Skip the DataBlock and the ExtraDataBlock | |
| 370 | + # SpinButtonStreamData: [MS-OFORMS] 2.2.8.5 | |
| 371 | + if propmask.fMouseIcon: | |
| 372 | + consume_GuidAndPicture(stream) | |
| 373 | + | |
| 374 | +def consume_TabStripControl(stream): | |
| 375 | + # TabStripControl: [MS-OFORMS] 2.2.9.1 | |
| 376 | + stream.check_values('TabStripControl (versions)', '<BB', 2, (0, 2)) | |
| 377 | + cbTabStrip = stream.unpack('<H', 2) | |
| 378 | + with stream.will_jump_to(cbTabStrip): | |
| 379 | + propmask = TabStripPropMask(stream.unpack('<L', 4)) | |
| 380 | + # TabStripDataBlock: [MS-OFORMS] 2.2.9.3 | |
| 381 | + # All are 4B (or 4B + pad = 4B), except MousePointer, which is 1B + pad = 4b | |
| 382 | + for prop in ['fListIndex', 'fBackColor', 'fForeColor', 'fSize', 'fTabOrientation' | |
| 383 | + 'fTabStyle', 'fTabFixedWidth', 'fTabFixedHeight', 'fTipStrings', | |
| 384 | + 'fNames', 'fVariousPropertyBits', 'fTabsAllocated', 'fTags']: | |
| 385 | + if propmask[prop]: | |
| 386 | + stream.read(4) | |
| 387 | + tabData = 0 | |
| 388 | + if propmask['fTabData']: | |
| 389 | + tabData = stream.unpack('<L', 4) | |
| 390 | + # Skip the ExtraDataBlock | |
| 391 | + # TabStripStreamData: [MS-OFORMS] 2.2.9.5 | |
| 392 | + if propmask.fMouseIcon: | |
| 393 | + consume_GuidAndPicture(stream) | |
| 394 | + # TextProps | |
| 395 | + consume_TextProps(stream) | |
| 396 | + # TabStripTabFlagData: [MS-OFORMS] 2.2.9.6 | |
| 397 | + for i in range(tabData): | |
| 398 | + stream.read(4) | |
| 399 | + | |
| 400 | +def consume_LabelControl(stream): | |
| 401 | + # LabelControl: [MS-OFORMS] 2.2.4.1 | |
| 402 | + stream.check_values('LabelControl (versions)', '<BB', 2, (0, 2)) | |
| 403 | + cbLabel = stream.unpack('<H', 2) | |
| 404 | + with stream.will_jump_to(cbLabel): | |
| 405 | + propmask = LabelPropMask(stream.unpack('<L', 4)) | |
| 406 | + # Skip the DataBlock and the ExtraDataBlock | |
| 407 | + # LabelStreamData: [MS-OFORMS] 2.2.4.5 | |
| 408 | + if propmask.fPicture: | |
| 409 | + consume_GuidAndPicture(stream) | |
| 410 | + if propmask.fMouseIcon: | |
| 411 | + consume_GuidAndPicture(stream) | |
| 412 | + # TextProps | |
| 413 | + consume_TextProps(stream) | |
| 414 | + | |
| 415 | +def consume_ScrollBarControl(stream): | |
| 416 | + # ScrollBarControl: [MS-OFORMS] 2.2.7.1 | |
| 417 | + stream.check_values('LabelControl (versions)', '<BB', 2, (0, 2)) | |
| 418 | + cbScrollBar = stream.unpack('<H', 2) | |
| 419 | + with stream.will_jump_to(cbScrollBar): | |
| 420 | + propmask = ScrollBarPropMask(stream.unpack('<L', 4)) | |
| 421 | + # Skip the DataBlock and the ExtraDataBlock | |
| 422 | + # ScrollBarStreamData: [MS-OFORMS] 2.2.7.5 | |
| 423 | + if propmask.fMouseIcon: | |
| 424 | + consume_GuidAndPicture(stream) | |
| 425 | + | |
| 290 | 426 | def extract_OleFormVariables(ole_file, stream_dir): |
| 291 | 427 | control = ExtendedStream.open(ole_file, '/'.join(stream_dir + ['f'])) |
| 292 | 428 | variables = list(consume_FormControl(control)) |
| 293 | 429 | # print('/'.join(stream_dir + ['o'])) |
| 294 | 430 | data = ExtendedStream.open(ole_file, '/'.join(stream_dir + ['o'])) |
| 295 | 431 | for var in variables: |
| 296 | - if var['ClsidCacheIndex'] != 23: | |
| 432 | + # See FormEmbeddedActiveXControlCached for type definition: [MS-OFORMS] 2.4.5 | |
| 433 | + if var['ClsidCacheIndex'] == 7: | |
| 434 | + raise OleFormParsingError('Malformed document: Forms should be stored in the f stream') | |
| 435 | + elif var['ClsidCacheIndex'] == 12: | |
| 436 | + consume_ImageControl(data) | |
| 437 | + elif var['ClsidCacheIndex'] == 14: | |
| 438 | + raise OleFormParsingError('Malformed document: Frames should be stored in the f stream') | |
| 439 | + elif var['ClsidCacheIndex'] in [15, 23, 24, 25, 26, 27, 28]: | |
| 440 | + var['value'] = consume_MorphDataControl(data) | |
| 441 | + elif var['ClsidCacheIndex'] == 16: | |
| 442 | + consume_SpinButtonControl(data) | |
| 443 | + elif var['ClsidCacheIndex'] == 17: | |
| 444 | + consume_CommandButtonControl(data) | |
| 445 | + elif var['ClsidCacheIndex'] == 18: | |
| 446 | + consume_TabStripControl(data) | |
| 447 | + elif var['ClsidCacheIndex'] == 21: | |
| 448 | + consume_LabelControl(data) | |
| 449 | + elif var['ClsidCacheIndex'] == 47: | |
| 450 | + consume_ScrollBarControl(data) | |
| 451 | + elif var['ClsidCacheIndex'] == 57: | |
| 452 | + raise OleFormParsingError('Malformed document: MultiPages should be stored in a x stream') | |
| 453 | + else: | |
| 297 | 454 | # TODO: use logging instead of print |
| 298 | 455 | print('ERROR: Unsupported stored type in user form: {0}'.format(str(var['ClsidCacheIndex']))) |
| 299 | 456 | break |
| 300 | - else: | |
| 301 | - var['value'] = consume_MorphDataControl(data) | |
| 302 | 457 | return variables | ... | ... |