Commit 2394f6191156016ae979a32319633fa6e702a220

Authored by decalage2
1 parent 40faecbf

olevba: added VBA_Parser.get_vba_code_all_modules, partial fix for issue #619, u…

…pdated mraptor to use it
oletools/mraptor.py
... ... @@ -62,7 +62,7 @@ http://www.decalage.info/python/oletools
62 62 # 2019-11-06 v0.55 PL: - added SetTimer
63 63 # 2020-04-20 v0.56 PL: - added keywords RUN and CALL for XLM macros (issue #562)
64 64  
65   -__version__ = '0.56dev5'
  65 +__version__ = '0.56dev12'
66 66  
67 67 #------------------------------------------------------------------------------
68 68 # TODO:
... ... @@ -318,8 +318,7 @@ def main():
318 318 if vba_parser.detect_vba_macros():
319 319 vba_code_all_modules = ''
320 320 try:
321   - for (subfilename, stream_path, vba_filename, vba_code) in vba_parser.extract_all_macros():
322   - vba_code_all_modules += vba_code + '\n'
  321 + vba_code_all_modules = vba_parser.get_vba_code_all_modules()
323 322 except Exception as e:
324 323 # log.error('Error when parsing VBA macros from file %r' % full_name)
325 324 result = Result_Error
... ...
oletools/olevba.py
... ... @@ -231,8 +231,10 @@ from __future__ import print_function
231 231 # 2020-09-16 PL: - enabled relaxed mode by default (issues #477, #593)
232 232 # - fixed detect_vba_macros to always return VBA code as
233 233 # unicode on Python 3 (issues #455, #477, #587, #593)
  234 +# 2020-09-28 PL: - added VBA_Parser.get_vba_code_all_modules (partial fix
  235 +# for issue #619)
234 236  
235   -__version__ = '0.56dev11'
  237 +__version__ = '0.56dev12'
236 238  
237 239 #------------------------------------------------------------------------------
238 240 # TODO:
... ... @@ -3401,6 +3403,7 @@ class VBA_Parser(object):
3401 3403 by calling extract_macros(), store the results as a list of tuples
3402 3404 (filename, stream_path, vba_filename, vba_code) in self.modules.
3403 3405 See extract_macros for details.
  3406 + :returns: list of tuples (filename, stream_path, vba_filename, vba_code)
3404 3407 """
3405 3408 if self.modules is None:
3406 3409 self.modules = []
... ... @@ -3410,6 +3413,23 @@ class VBA_Parser(object):
3410 3413 return self.modules
3411 3414  
3412 3415  
  3416 + def get_vba_code_all_modules(self):
  3417 + """
  3418 + Extract the VBA macro source code from all modules, and return it
  3419 + as a single string (str) with all modules concatenated.
  3420 + If an exception is triggered when decompressing a VBA module, it
  3421 + will not be included. The error is logged but the exception is not
  3422 + raised further.
  3423 + :return: str
  3424 + """
  3425 + vba_code_all_modules = ''
  3426 + for (_, _, _, vba_code) in self.extract_all_macros():
  3427 + if not isinstance(vba_code, str):
  3428 + log.error('VBA code returned by extract_all_macros is not a string')
  3429 + else:
  3430 + vba_code_all_modules += vba_code + '\n'
  3431 + return vba_code_all_modules
  3432 +
3413 3433  
3414 3434 def analyze_macros(self, show_decoded_strings=False, deobfuscate=False):
3415 3435 """
... ... @@ -3424,10 +3444,7 @@ class VBA_Parser(object):
3424 3444 return self.analysis_results
3425 3445 # variable to merge source code from all modules:
3426 3446 if self.vba_code_all_modules is None:
3427   - self.vba_code_all_modules = ''
3428   - for (_, _, _, vba_code) in self.extract_all_macros():
3429   - #TODO: filter code? (each module)
3430   - self.vba_code_all_modules += vba_code + '\n'
  3447 + self.vba_code_all_modules = self.get_vba_code_all_modules()
3431 3448 for (_, _, form_string) in self.extract_form_strings():
3432 3449 self.vba_code_all_modules += form_string + '\n'
3433 3450 # Analyze the whole code at once:
... ... @@ -3749,10 +3766,8 @@ class VBA_Parser(object):
3749 3766 keywords.add(s)
3750 3767 log.debug('Keywords extracted from P-code: ' + repr(sorted(keywords)))
3751 3768 self.vba_stomping_detected = False
3752   - # TODO: add a method to get all VBA code as one string
3753   - vba_code_all_modules = ''
3754   - for (_, _, _, vba_code) in self.extract_all_macros():
3755   - vba_code_all_modules += vba_code + '\n'
  3769 + # get all VBA code as one string
  3770 + vba_code_all_modules = self.get_vba_code_all_modules()
3756 3771 for keyword in keywords:
3757 3772 if keyword not in vba_code_all_modules:
3758 3773 log.debug('Keyword {!r} not found in VBA code'.format(keyword))
... ...
setup.py
... ... @@ -52,7 +52,7 @@ import os, fnmatch
52 52 #--- METADATA -----------------------------------------------------------------
53 53  
54 54 name = "oletools"
55   -version = '0.56dev11'
  55 +version = '0.56dev12'
56 56 desc = "Python tools to analyze security characteristics of MS Office and OLE files (also called Structured Storage, Compound File Binary Format or Compound Document File Format), for Malware Analysis and Incident Response #DFIR"
57 57 long_desc = open('oletools/README.rst').read()
58 58 author = "Philippe Lagadec"
... ...