Commit 7b3697b3c5795794bd016fde463aae9ec46db3fc

Authored by decalage2
1 parent 1892bb00

olevba: added option --pcode to disassemble and display the VBA P-Code using pcodedmp

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
@@ -3,3 +3,4 @@ olefile>=0.46 @@ -3,3 +3,4 @@ olefile>=0.46
3 easygui 3 easygui
4 colorclass 4 colorclass
5 msoffcrypto-tool 5 msoffcrypto-tool
  6 +pcodedmp>=1.2.4
6 \ No newline at end of file 7 \ No newline at end of file
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