Commit 7b3697b3c5795794bd016fde463aae9ec46db3fc
1 parent
1892bb00
olevba: added option --pcode to disassemble and display the VBA P-Code using pcodedmp
Showing
3 changed files
with
28 additions
and
3 deletions
oletools/olevba.py
| @@ -216,8 +216,9 @@ from __future__ import print_function | @@ -216,8 +216,9 @@ from __future__ import print_function | ||
| 216 | # 2019-03-18 PL: - added XLM/XLF macros detection for Excel OLE files | 216 | # 2019-03-18 PL: - added XLM/XLF macros detection for Excel OLE files |
| 217 | # 2019-03-25 CH: - added decryption of password-protected files | 217 | # 2019-03-25 CH: - added decryption of password-protected files |
| 218 | # 2019-04-09 PL: - decompress_stream accepts bytes (issue #422) | 218 | # 2019-04-09 PL: - decompress_stream accepts bytes (issue #422) |
| 219 | +# 2019-05-23 v0.55 PL: - added option --pcode to call pcodedmp and display P-code | ||
| 219 | 220 | ||
| 220 | -__version__ = '0.54.2' | 221 | +__version__ = '0.55.dev1' |
| 221 | 222 | ||
| 222 | #------------------------------------------------------------------------------ | 223 | #------------------------------------------------------------------------------ |
| 223 | # TODO: | 224 | # TODO: |
| @@ -285,6 +286,7 @@ except ImportError: | @@ -285,6 +286,7 @@ except ImportError: | ||
| 285 | + "or http://effbot.org/zone/element-index.htm") | 286 | + "or http://effbot.org/zone/element-index.htm") |
| 286 | 287 | ||
| 287 | import colorclass | 288 | import colorclass |
| 289 | +from pcodedmp import pcodedmp | ||
| 288 | 290 | ||
| 289 | # On Windows, colorclass needs to be enabled: | 291 | # On Windows, colorclass needs to be enabled: |
| 290 | if os.name == 'nt': | 292 | if os.name == 'nt': |
| @@ -3518,7 +3520,7 @@ class VBA_Parser_CLI(VBA_Parser): | @@ -3518,7 +3520,7 @@ class VBA_Parser_CLI(VBA_Parser): | ||
| 3518 | def process_file(self, show_decoded_strings=False, | 3520 | def process_file(self, show_decoded_strings=False, |
| 3519 | display_code=True, hide_attributes=True, | 3521 | display_code=True, hide_attributes=True, |
| 3520 | vba_code_only=False, show_deobfuscated_code=False, | 3522 | vba_code_only=False, show_deobfuscated_code=False, |
| 3521 | - deobfuscate=False): | 3523 | + deobfuscate=False, pcode=False): |
| 3522 | """ | 3524 | """ |
| 3523 | Process a single file | 3525 | Process a single file |
| 3524 | 3526 | ||
| @@ -3530,6 +3532,7 @@ class VBA_Parser_CLI(VBA_Parser): | @@ -3530,6 +3532,7 @@ class VBA_Parser_CLI(VBA_Parser): | ||
| 3530 | otherwise each module is analyzed separately (old behaviour) | 3532 | otherwise each module is analyzed separately (old behaviour) |
| 3531 | :param hide_attributes: bool, if True the first lines starting with "Attribute VB" are hidden (default) | 3533 | :param hide_attributes: bool, if True the first lines starting with "Attribute VB" are hidden (default) |
| 3532 | :param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow) | 3534 | :param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow) |
| 3535 | + :param pcode bool: if True, call pcodedmp to disassemble P-code and display it | ||
| 3533 | """ | 3536 | """ |
| 3534 | #TODO: replace print by writing to a provided output file (sys.stdout by default) | 3537 | #TODO: replace print by writing to a provided output file (sys.stdout by default) |
| 3535 | # fix conflicting parameters: | 3538 | # fix conflicting parameters: |
| @@ -3599,6 +3602,23 @@ class VBA_Parser_CLI(VBA_Parser): | @@ -3599,6 +3602,23 @@ class VBA_Parser_CLI(VBA_Parser): | ||
| 3599 | # display the exception with full stack trace for debugging | 3602 | # display the exception with full stack trace for debugging |
| 3600 | log.info('Error parsing form: %s' % exc) | 3603 | log.info('Error parsing form: %s' % exc) |
| 3601 | log.debug('Traceback:', exc_info=True) | 3604 | log.debug('Traceback:', exc_info=True) |
| 3605 | + if pcode: | ||
| 3606 | + print('-' * 79) | ||
| 3607 | + print('P-CODE disassembly:') | ||
| 3608 | + # save sys.stdout, then modify it to capture pcodedmp's output | ||
| 3609 | + stdout = sys.stdout | ||
| 3610 | + output = BytesIO() | ||
| 3611 | + sys.stdout = output | ||
| 3612 | + class args: | ||
| 3613 | + disasmOnly = True | ||
| 3614 | + verbose = False | ||
| 3615 | + try: | ||
| 3616 | + # TODO: handle files in memory too | ||
| 3617 | + pcodedmp.processFile(self.filename, args) | ||
| 3618 | + except Exception: | ||
| 3619 | + log.error('Error while running pcodedmp') | ||
| 3620 | + sys.stdout = stdout | ||
| 3621 | + print(output.getvalue()) | ||
| 3602 | 3622 | ||
| 3603 | if not vba_code_only: | 3623 | if not vba_code_only: |
| 3604 | # analyse the code from all modules at once: | 3624 | # analyse the code from all modules at once: |
| @@ -3786,6 +3806,8 @@ def parse_args(cmd_line_args=None): | @@ -3786,6 +3806,8 @@ def parse_args(cmd_line_args=None): | ||
| 3786 | help="Attempt to deobfuscate VBA expressions (slow)") | 3806 | help="Attempt to deobfuscate VBA expressions (slow)") |
| 3787 | parser.add_option('--relaxed', dest="relaxed", action="store_true", default=False, | 3807 | parser.add_option('--relaxed', dest="relaxed", action="store_true", default=False, |
| 3788 | help="Do not raise errors if opening of substream fails") | 3808 | help="Do not raise errors if opening of substream fails") |
| 3809 | + parser.add_option('--pcode', dest="pcode", action="store_true", default=False, | ||
| 3810 | + help="Disassemble and display the P-code (using pcodedmp)") | ||
| 3789 | 3811 | ||
| 3790 | (options, args) = parser.parse_args(cmd_line_args) | 3812 | (options, args) = parser.parse_args(cmd_line_args) |
| 3791 | 3813 | ||
| @@ -3823,7 +3845,7 @@ def process_file(filename, data, container, options, crypto_nesting=0): | @@ -3823,7 +3845,7 @@ def process_file(filename, data, container, options, crypto_nesting=0): | ||
| 3823 | display_code=options.display_code, | 3845 | display_code=options.display_code, |
| 3824 | hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only, | 3846 | hide_attributes=options.hide_attributes, vba_code_only=options.vba_code_only, |
| 3825 | show_deobfuscated_code=options.show_deobfuscated_code, | 3847 | show_deobfuscated_code=options.show_deobfuscated_code, |
| 3826 | - deobfuscate=options.deobfuscate) | 3848 | + deobfuscate=options.deobfuscate, pcode=options.pcode) |
| 3827 | elif options.output_mode == 'triage': | 3849 | elif options.output_mode == 'triage': |
| 3828 | # summarized output for triage: | 3850 | # summarized output for triage: |
| 3829 | vba_parser.process_file_triage(show_decoded_strings=options.show_decoded_strings, | 3851 | vba_parser.process_file_triage(show_decoded_strings=options.show_decoded_strings, |
requirements.txt
setup.py
| @@ -30,6 +30,7 @@ to install this package. | @@ -30,6 +30,7 @@ to install this package. | ||
| 30 | # 2018-10-27 PL: - fixed issue #359 (bug when importing log_helper) | 30 | # 2018-10-27 PL: - fixed issue #359 (bug when importing log_helper) |
| 31 | # 2019-02-26 CH: - add optional dependency msoffcrypto for decryption | 31 | # 2019-02-26 CH: - add optional dependency msoffcrypto for decryption |
| 32 | # 2019-05-22 PL: - 'msoffcrypto-tool' is now a required dependency | 32 | # 2019-05-22 PL: - 'msoffcrypto-tool' is now a required dependency |
| 33 | +# 2019-05-23 v0.55 PL: - added pcodedmp as dependency | ||
| 33 | 34 | ||
| 34 | #--- TODO --------------------------------------------------------------------- | 35 | #--- TODO --------------------------------------------------------------------- |
| 35 | 36 | ||
| @@ -319,6 +320,7 @@ def main(): | @@ -319,6 +320,7 @@ def main(): | ||
| 319 | "easygui", | 320 | "easygui", |
| 320 | 'colorclass', | 321 | 'colorclass', |
| 321 | 'msoffcrypto-tool', | 322 | 'msoffcrypto-tool', |
| 323 | + 'pcodedmp>=1.2.4', | ||
| 322 | ], | 324 | ], |
| 323 | ) | 325 | ) |
| 324 | 326 |