
    ZiǙ                       S r SSKJr  SrSSKrSSKrSSKrSSKrSSKJ	r	J
r
  SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKr SSKJr  SSKr\R<                  S:X  a  \R>                  RA                  SS	9  SS
K!J"r"J#r#J$r$J%r%J&r&J'r'J(r(J)r)J*r*J+r+J,r,J-r-J.r.J/r/J0r0J1r1J2r2J3r3J4r4   SSK5J6r7  Sr8\Rr                  Ru                  \Rr                  Rw                  \Rr                  Ry                  \=5      5      5      r>\Rr                  Ru                  \Rr                  R                  \>S5      5      r@\@\Rr                  ;  a  \Rr                  R                  S\@5        SSKBrBSSKCJDrD  SSKEJFrFJGrG  SSKHJIrI  SSKJJKrK  SSKJJLrL  SSKJJMrM  SSKJJNrN  SSKOJPrP  SSKQJRrR  SSKJJSrS  SSKTJUrU  \R                  S   S::  a  SrW\XrYSrZOOSrWS rY\[r\\]r^\_r`SSKaJbrb  SrZ\R                  S:  a,  SSKcrc\cR                  " S5      reS rf\cR                  " S\f5        S  rhGS9S! jri\UR                  " S"5      rkS# rl " S$ S%\m5      rn " S& S'\n5      ro " S( S)\n5      rp " S* S+\q\n5      rr " S, S-\o5      rs " S. S/\n5      rtSruS0rvSrwS1rxS2ryS3rzS4r{S5r|S6r}S7r~S8S9S:S;S<S=S>S?S@SASBS:SC.rSDrSE\-  rSFrSGrSHrSIrSJrSKrSLrSMr\SN\SO\SP\SQ\SR\SS\ST\SU0rSVrSWrSXrSYrSZr\S[-   r\S\-   rS]r\S^-   r\S_-   r\S\-   r\S`-   rSar\Sb-   rScSdSeSfSgShSiSjSkSl.	rSmSnSo.r0 SpSq_SrSs_StSu_SvSw_SxSy_SzS{_S|S}_S~S_SS_SS_SS_SS_SS_SS_SS_SS_SS_0 SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_SS_ESSSSSSSSSSSSS.ErSSSSSSSS.rSS0rSrSrS\-   S-   rSrS\-   S-   \-   rS\-   S-   \-   S-   rSr\\-   rSr\S-   \-   \-   r\GRP                  " \5      rSS/rS\GRP                  " \5      4S\GRP                  " \5      4S\GRP                  " S\-   S-   5      4S\GRP                  " S5      44r\GRP                  " S5      rSr\GRP                  " S\-   S-   5      r\" / SQ5      r\GRP                  " S5      r\GRP                  " S5      r\GRP                  " S5      r\4GRh                  " 5         \-S-   r " S S\_5      r\$" \'" S5      \," \5      -   \+" \05      -   \*" \'" \+" SS0S95      5      -   5      r\GRq                  S 5        \$" \*" \&" S5      \'" \#" S5      5      -   5      \+" \2" S5      5      -   \*" \'" \+" SS0S95      5      -   5      r\GRq                  S 5        \$" \*" \#" S5      5      \+" \2" S5      5      -   \*" \'" \+" SS0S95      5      -   5      r\GRq                  S 5        \\-  \-  r\(" SSS9r\GRq                  S 5        \%" 5       r\%" 5       r\*" \$" \," \5      \#" S5      -   \'" \#" S5      \#" S5      -  5      -   \'" S5      -   5      S-   5      \-   \*" S5      -   rS r\GRq                  \5        \*" \"" S5      S-   5      \-   \*" S5      -   r\GRq                  S 5        \*" \"" S5      S-   5      \-   \*" S5      -   r\GRq                  GS  5        \*" \"" GS5      S-   5      \-   \*" S5      -   r\GRq                  GS 5        \*" \"" GS5      S-   5      \-   \*" S5      -   r\GRq                  GS 5        \+" \.\-S-   GS9r\*" S5      \$" \+" \/SS9GS-  5      -   \*" S5      -   r\GRq                  GS 5        \*" \5      \*" S5      -   \" GS5      -   \*" S5      -   r\GRq                  GS	 5        \*" S5      \)" \5      -   \*" S5      -   r\GRq                  GS
 5        \*" \5      \*" S5      -   \" GS5      -   \*" S5      -   r\GRq                  GS 5        GS r\\-  \-  \-  \-  \-  r\\3" \GSS\1GR                  \4SS\1GR                  \4/5      -  rGS rGS rGS rGS r\\-  \-  r\\3" \GSS\1GR                  \4GSS\1GR                  \4SS\1GR                  \4GSS\1GR                  \4/5      -  rGS r\GRP                  " GS5      rGS r\" \GR                  5      rGS rGS rGS r " GS GS\5      r " GS GS\5      rGS:GS jrGS  rGS! rGS;GS" jrGS;GS# jrGS;GS$ jrGS% rGS& rGS' rGS( rGS) rGS* rGS+ rGS<GS, jrGS=GS- jr " GS. GS/\5      rGS>GS0 jr " GS1 GS2\5      r " GS3 GS4\5      rGS;GS5 jrGS?GS6 jrGS;GS7 jr\GS8:X  a  \" 5         gg! \ a5     SSKJs  Jr   G	NE! \ a     SSKJr    G	NV! \ a	    \" S5      ef = ff = ff = f! \ a    Sr8 G	Nf = f(@  ao  
olevba.py

olevba is a script to parse OLE and OpenXML files such as MS Office documents
(e.g. Word, Excel), to extract VBA Macro code in clear text, deobfuscate
and analyze malicious macros.
XLM/Excel 4 Macros are also supported in Excel and SLK files.

Supported formats:
    - Word 97-2003 (.doc, .dot), Word 2007+ (.docm, .dotm)
    - Excel 97-2003 (.xls), Excel 2007+ (.xlsm, .xlsb)
    - PowerPoint 97-2003 (.ppt), PowerPoint 2007+ (.pptm, .ppsm)
    - Word/PowerPoint 2007+ XML (aka Flat OPC)
    - Word 2003 XML (.xml)
    - Word/Excel Single File Web Page / MHTML (.mht)
    - Publisher (.pub)
    - SYLK/SLK files (.slk)
    - Text file containing VBA or VBScript source code
    - Password-protected Zip archive containing any of the above
    - raises an error if run with files encrypted using MS Crypto API RC4

Author: Philippe Lagadec - http://www.decalage.info
License: BSD, see source code or documentation

olevba is part of the python-oletools package:
http://www.decalage.info/python/oletools

olevba is based on source code from officeparser by John William Davison
https://github.com/unixfreak0037/officeparser
    )print_functionz0.60.2N)BytesIOStringIOzplxml or ElementTree are not installed, see http://codespeak.net/lxml or http://effbot.org/zone/element-index.htmntT)auto_colors)CaselessKeywordCaselessLiteralCombineForwardLiteralOptionalQuotedStringRegexSuppressWord	WordStart	alphanumsalphashexnumsnumsopAssocsrangeinfixNotationParserElement)deobfuscatorFz..)tablestream)xglobPathNotFoundException)cBIFF)
ppt_parser)oleform)rtfobj)crypto)ensure_stdout_handles_unicode)	codepages)ftguess)
log_helper   utf8c                     U $ N )xs    i/var/www/eduai.edurigo.com/question_generate/ques_gen_env/lib/python3.13/site-packages/oletools/olevba.pybyte_ordr/   n  s        reduce)      backslashreplacec                     [        U [        5      (       aF  SR                  S U R                  U R                  U R
                    5       5      nXR
                  4$ [        U 5      $ )N c              3   D   #    U  H  nS R                  U5      v   M     g7f)z	\x{0:02x}Nformat).0cs     r.   	<genexpr>*backslashreplace_errors.<locals>.<genexpr>  s      Z<YqL//22<Y    )
isinstanceUnicodeDecodeErrorjoinobjectstartend_backslashreplace_errors)excus     r.   backslashreplace_errorsrI     sQ    #122GGZCJJsyyQTQXQX<YZZ''z!+C00r0   c                 <    [         (       a  U R                  SSS9$ U $ )a  
convert a unicode string to a native str:
    - on Python 3, it returns the same string
    - on Python 2, the string is encoded with UTF-8 to a bytes str
:param unicode_string: unicode string to be converted
:return: the string converted to str
:rtype: str
r)   replaceerrors)PYTHON2encode)unicode_strings    r.   unicode2strrQ     s%     w$$VI$>>r0   c                 <    [         (       a  U $ U R                  USS9$ )ad  
convert a bytes string to a native str:
    - on Python 2, it returns the same string (bytes=str)
    - on Python 3, the string is decoded using the provided encoding
      (UTF-8 by default) to a unicode str
:param bytes_string: bytes string to be converted
:param encoding: codec to be used for decoding
:return: the string converted to str
:rtype: str
rK   rL   )rN   decode)bytes_stringencodings     r.   	bytes2strrV     s%     w""8I">>r0   olevbac                      [         R                  [        R                  5        [        R
                  " 5         [        R
                  " 5         g)a  
Enable logging for this module (disabled by default).

For use by third-party libraries that import `olevba` as module.

This will set the module-specific logger level to `NOTSET`, which
means the main application controls the actual logging level.

This also enables logging for the modules used by us, but not the global
common logging mechanism (:py:mod:`oletools.common.log_helper.log_helper`).
Use :py:func:`oletools.common.log_helper.log_helper.enable_logging` for
that.
N)logsetLevelr'   NOTSETr    enable_loggingr#   r,   r0   r.   r\   r\     s.     LL""#
r0   c                   0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )OlevbaBaseExceptioni  zCBase class for exceptions produced here for simpler except clauses c                    > U(       a(  [         [        U ]
  " USR                  U5      -   40 UD6  O[         [        U ]
  " U40 UD6  Xl        X l        X0l        g )Nz ({0}))superr^   __init__r:   msgfilenameorig_exc)selfrb   rc   rd   kwargs	__class__s        r.   ra   OlevbaBaseException.__init__  sZ    %t5c6>ooh6O7P @8>@ %t5cDVD  r0   )rc   rb   rd   )NN__name__
__module____qualname____firstlineno____doc__ra   __static_attributes____classcell__rg   s   @r.   r^   r^     s    N	! 	!r0   r^   c                   0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )FileOpenErrori  zpraised by VBA_Parser constructor if all open_... attempts failed

probably means the file type is not supported
c                 4   > [         [        U ]  SU-  X5        g )NzFailed to open file %s)r`   rs   ra   re   rc   rd   rg   s      r.   ra   FileOpenError.__init__  s    mT+$x/	Er0   r,   r+   ri   rq   s   @r.   rs   rs     s    
E Er0   rs   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )ProcessingErrori  z-raised by VBA_Parser.process_file* functions c                 4   > [         [        U ]  SU-  X5        g )NzError processing file %s)r`   rx   ra   ru   s      r.   ra   ProcessingError.__init__  s    ot-&18	Gr0   r,   ri   rq   s   @r.   rx   rx     s    8G Gr0   rx   c                       \ rS rSrSrS rSrg)MsoExtractionErrori  zAraised by mso_file_extract if parsing MSO/ActiveMIME data failed c                 X    [         R                  X5        [        R                  X5        g r+   )r|   ra   r^   )re   rb   s     r.   ra   MsoExtractionError.__init__  s    ##D.$$T/r0   r,   Nrj   rk   rl   rm   rn   ra   ro   r,   r0   r.   r|   r|     s
    L0r0   r|   c                   0   ^  \ rS rSrSrSU 4S jjrSrU =r$ )SubstreamOpenErrori  zDspecial kind of FileOpenError: file is a substream of original file c                 v   > [         [        U ]  [        U5      S-   [        U5      -   U5        Xl        X l        g N/)r`   r   ra   strrc   subfilename)re   rc   r   rd   rg   s       r.   ra   SubstreamOpenError.__init__  s6     $0MC#k"22H	> &r0   )rc   r   r+   ri   rq   s   @r.   r   r     s    O' 'r0   r   c                   ,   ^  \ rS rSrSrU 4S jrSrU =r$ )UnexpectedDataErrori  zDraised when parsing is strict (=not relaxed) and data is unexpected c                   > [        U[        5      (       a  SR                  U5      nOb[        U[        5      (       a*  SR	                  S U 5       5      nSR                  U5      nO#[        SR                  [        U5      5      5      e[        [        U ]'  SR                  XXT5      5        Xl
        X l        X0l        X@l        g )N{0:04X},c              3   D   #    U  H  nS R                  U5      v   M     g7f)r   Nr9   )r;   es     r.   r=   /UnexpectedDataError.__init__.<locals>.<genexpr>  s     @x!)**1--xr?   z({0})zUnknown type encountered: {0}zIUnexpected value in {0} for variable {1}: expected {2} but found {3:04X}!)r@   intr:   tuplerB   
ValueErrortyper`   r   ra   stream_pathvariableexpectedvalue)re   r   r   r   r   esrg   s         r.   ra   UnexpectedDataError.__init__  s    h$$!!(+B%((@x@@B..$B<CCDNSTT!41.VK25	7 '  
r0   )r   r   r   r   ri   rq   s   @r.   r   r     s    O r0   r      r3      r4            	   z	mac-romanshiftjisasciigb2321big5hebrewz
mac-arabicz	mac-greekzmac-turkishthaimaccentraleurope)i'  i'  i'  i'  i'  i'  i'  i'  ia'  i%'  i-'  i'  z,https://github.com/decalage2/oletools/issueszPlease report this issue on %sOLEOpenXMLFlatOPC_XMLWord2003_XMLMHTMLTextPPTSLKzOLE:zOpX:zFlX:zXML:zMHT:zTXT:zPPT:zSLK:s
   ActiveMimebasclsfrmz6{http://schemas.microsoft.com/office/word/2003/wordml}binDatanamez5{http://schemas.microsoft.com/office/2006/xmlPackage}packagepartcontentTypez$application/vnd.ms-office.vbaProject
binaryData)AutoExecAutoOpenDocumentOpen)AutoExit	AutoCloseDocument_CloseDocumentBeforeClose)DocumentChange)AutoNewDocument_NewNewDocument)Document_Open)Document_BeforeClose)	Auto_OpenWorkbook_OpenWorkbook_ActivateAuto_Ope)
Auto_CloseWorkbook_CloseWorkbook_BeforeClose)Worksheet_Calculate)	z%Runs when the Word document is openedz%Runs when the Word document is closedz'Runs when the Word document is modifiedz(Runs when a new Word document is createdz2Runs when the Word or Publisher document is openedz*Runs when the Publisher document is closedz&Runs when the Excel Workbook is openedz&Runs when the Excel Workbook is closedz)May run when an Excel WorkSheet is opened)z\w+_Paintedz\w+_Painting)z\w+_GotFocusz\w+_LostFocusz\w+_MouseHoverz	\w+_Clickz
\w+_Changez
\w+_Resizez\w+_BeforeNavigate2z\w+_BeforeScriptExecutez\w+_DocumentCompletez\w+_DownloadBeginz\w+_DownloadCompletez\w+_FileDownloadz\w+_NavigateComplete2z\w+_NavigateErrorz\w+_ProgressChangez\w+_PropertyChangez\w+_SetSecureLockIconz\w+_StatusTextChangez\w+_TitleChangez\w+_MouseMovez\w+_MouseEnterz\w+_MouseLeavez
\w+_Layoutz\w+_OnConnectingz\w+_FollowHyperlinkz\w+_ContentControlOnEnter)z>Runs when the file is opened (using InkPicture ActiveX object)z?Runs when the file is opened and ActiveX objects trigger eventsz%May read system environment variables)EnvironWin32_EnvironmentEnvironmentExpandEnvironmentStringszHKCU\EnvironmentzHKEY_CURRENT_USER\EnvironmentzMay open a file)Openz+May write to a file (if combined with Open))WritePutOutputzPrint #z7May read or write a binary file (if combined with Open))BinaryzMay copy a file)FileCopyCopyFileCopyHere
CopyFolderzMay move a file)MoveHereMoveFile
MoveFolderzMay delete a file)KillzMay create a text file)CreateTextFilezADODB.Stream	WriteText
SaveToFilez.May run an executable file or a system command)ShellvbNormalvbNormalFocusvbHidevbMinimizedFocusvbMaximizedFocusvbNormalNoFocusvbMinimizedNoFocuszWScript.ShellRunShellExecuteShellExecuteAshell32
InvokeVerbInvokeVerbExDoItzMay run a dll)ControlPanelItemz0May execute file or a system command through WMI)Createz7May run an executable file or a system command on a Mac)	MacScriptAppleScriptzMay run PowerShell commands)

PowerShellnoexitExecutionPolicy	noprofilecommandEncodedCommandzinvoke-commandscriptblockzInvoke-ExpressionAuthorizationManagerz?May run an executable file or a system command using PowerShell)zStart-Process-May call a DLL using Excel 4 Macros (XLM/XLF))CALLzMay hide the application)zApplication.Visible
ShowWindowSW_HIDEzMay create a directory)MkDirzMay save the current workbook)zActiveWorkbook.SaveAsz<May change which directory contains files to open at startup)zApplication.AltStartupPathzMay create an OLE object)CreateObjectz-May get an OLE object with a running instance)	GetObjectz)May create an OLE object using PowerShell)z
New-Objectz6May run an application (if combined with CreateObject))zShell.Applicationz/May run an Excel 4 Macro (aka XLM/XLF) from VBA)ExecuteExcel4MacrozMMay enumerate application windows (if combined with Shell.Application object))Windows
FindWindowzMay run code from a DLL)Libz$May run code from a library on a Mac)z
libc.dylibdylibz$May inject code into another process)
CreateThreadCreateUserThreadVirtualAllocVirtualAllocExRtlMoveMemoryWriteProcessMemorySetContextThreadQueueApcThreadWriteVirtualMemoryVirtualProtectMay run a shellcode in memory)SetTimerz$May download files from the Internet)URLDownloadToFileAzMsxml2.XMLHTTPzMicrosoft.XMLHTTPzMSXML2.ServerXMLHTTPz
User-Agentz5May download files from the Internet using PowerShell)zNet.WebClientDownloadFileDownloadStringz=May control another application by simulating user keystrokes)SendKeysAppActivatez1May attempt to obfuscate malicious function calls)
CallByNamezMMay attempt to obfuscate specific strings (use option --deobf to deobfuscate))ChrChrBChrW
StrReverseXor)RegOpenKeyExARegOpenKeyExRegCloseKey)RegQueryValueExARegQueryValueExRegRead)z'SYSTEM\ControlSet001\Services\Disk\EnumVIRTUALVMWAREVBOX)GetVolumeInformationAGetVolumeInformation
1824245000zIHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductIdz76487-337-8429955-22614andyzC:\exec\exec.exepopupkiller)zSbieDll.dllSandboxieControlWndClass)zC:\file.exe)currentuser)Schmidti)zAfx:400000:0)
AccessVBOMVBAWarningsProtectedViewDisableAttachementsInPVDisableInternetFilesInPVDisableUnsafeLocationsInPV!blockcontentexecutionfrominternet)	VBProjectVBComponents
CodeModuleAddFromString)zFORMULA.FILL)zMay read or write registry keyszMay read registry keyszMay detect virtualizationzMay detect Anubis SandboxzMay detect SandboxiezMay detect Sunbelt SandboxzMay detect Norman SandboxzMay detect CW SandboxzMay detect WinJail Sandboxz<May attempt to disable VBA macro security and Protected Viewz6May attempt to modify the VBA code (self-modification)z6May modify Excel 4 Macro formulas at runtime (XLM/XLF))z\.\s*Variables)zEnumSystemLanguageGroupsW?z!EnumDateFormats(?:W|(?:Ex){1,2})?)systempopenzexec[lv][ep]?)z,(?<!Could contain following functions: )EXEC)z'Could contain following functions: EXEC)z0(?<!Could contain following functions: )REGISTER)z+Could contain following functions: REGISTER)z6May use Word Document Variables to store and hide datar  zUMay run an executable file or a system command on a Mac (if combined with libc.dylib)zMMay run an executable file or a system command using Excel 4 Macros (XLM/XLF)zqCould contain a function that allows to run an executable file or a system command using Excel 4 Macros (XLM/XLF)r   zQCould contain a function that allows to call a DLL using Excel 4 Macros (XLM/XLF)zZMay use special characters such as backspace to obfuscate code when printed on the console)z\b(?:http|ftp)s?z((?:xn--[a-zA-Z0-9]{4,20}|[a-zA-Z]{2,20})z(?:[a-zA-Z0-9\-\.]+\.)z2(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])z(?:z\.){3}|z(?:\:[0-9]{1,5})?z*(?:/[a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~]*)?z\://z"http://schemas.openxmlformats.org/zhttp://schemas.microsoft.com/URLzIPv4 addresszE-mail addressz(?i)\b[A-Z0-9._%+-]+@r=  zExecutable file namez(?i)\b\w+\.(EXE|PIF|GADGET|MSI|MSP|MSC|VBS|VBE|VB|JSE|JS|WSF|WSC|WSH|WS|BAT|CMD|DLL|SCR|HTA|CPL|CLASS|JAR|PS1XML|PS1|PS2XML|PS2|PSC1|PSC2|SCF|LNK|INF|REG)\bz(?:[0-9A-Fa-f]{2}){4,}zV(?:[A-Za-z0-9+/]{4}){1,}(?:[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/][AQgw]==)?")
thisdocumentthisworkbooktesttemphttpopenexitkernel32virtualalloccreatethreadz"[0-9A-Za-z]{20,}"z[G-Zg-z]s   [\t\r\n\x20-\xFF]{5,}_c                       \ rS rSrSrSrg)VbaExpressionStringi  a;  
Class identical to str, used to distinguish plain strings from strings
obfuscated using VBA expressions (Chr, StrReverse, etc)
Usage: each VBA expression parse action should convert strings to
VbaExpressionString.
Then isinstance(s, VbaExpressionString) is True only for VBA expressions.
 (see detect_vba_strings)
r,   N)rj   rk   rl   rm   rn   ro   r,   r0   r.   rN  rN    s     	r0   rN  -z%&^)exactc                     [        U S   5      $ Nr   r   ts    r.   <lambda>rV    s    QqTr0   &oz[0-7]c                     [        U S   SS9$ )Nr   r   baserS  rT  s    r.   rV  rV    s    s1Q4a'8r0   z&hz[0-9a-fA-F]c                     [        U S   SS9$ )Nr      rZ  rS  rT  s    r.   rV  rV    s    S1B%7r0   "")escQuotec                     [        U S   5      $ rR  r   rT  s    r.   rV  rV    s    s1Q4yr0   r  BW$(c                     U S   nUS:  a  US::  a  [        [        U5      5      $ [        [        U5      R                  SS5      5      $ ! [         a)    [
        R                  SW-  5        [        SU-  5      s $ f = f)Nr      zutf-8r5   z.ERROR: incorrect parameter value for chr(): %rzChr(%r))rN  chrunichrrO   r   rY   	exception)rU  is     r.   vba_chr_tostrrl    s}    2aDa4AsF 's1v..
 'vay'7'7AS'TUU 2FJK"9q=112s   $A #A 0A>=A>Ascc                     [        U S   5      $ rR  )ordrT  s    r.   rV  rV  +  s    QqTr0   Valc                 :    [        U S   R                  5       5      $ rR  )r   striprT  s    r.   rV  rV  3  s    QqTZZ\!2r0   r  c                 <    [        [        U S   5      S S S2   5      $ )Nr   )rN  r   rT  s    r.   rV  rV  :  s    $7AaD	$B$$Hr0   r   c                 $    [        SU S   -  5      $ )Nz%%%s%%r   )rN  rT  s    r.   rV  rV  A  s    !4X!_!Er0   )	initChars	bodyChars)r(   Nc                     [        U S   5      $ rR  ra  rT  s    r.   rV  rV  T  s    3qt9r0   
hex_stringc                 T    [        [        R                  " U R                  5      5      $ r+   )rN  binasciia2b_hexry  rT  s    r.   rV  rV  X  s    +>x?O?OPQP\P\?]+^r0   c                     [        U S   5      $ rR  ra  rT  s    r.   rV  rV  b  s    c!A$ir0   base64_stringc                 T    [        [        R                  " U R                  5      5      $ r+   )rN  r{  
a2b_base64r~  rT  s    r.   rV  rV  f  s    .A(BUBUVWVeVeBf.gr0   c                 L    U S   SSS2   n[        SR                  U5      5      $ )zS
parse action to concatenate strings in a VBA expression with operators '+' or '&'
r   Nr(   r7   )rN  rB   )tokensstringss     r.   concat_strings_listr  k  s)     Qi!nGrwww/00r0   +c                 .    U S   SSS2   n[        U5      $ )zD
parse action to sum integers in a VBA expression with operator '+'
r   Nr(   )sumr  integerss     r.   sum_ints_listr    s     ay1~Hx=r0   c                 2    U S   SSS2   n[        S U5      $ )zI
parse action to subtract integers in a VBA expression with operator '-'
r   Nr(   c                 
    X-
  $ r+   r,   r-   ys     r.   rV  $subtract_ints_list.<locals>.<lambda>      QSr0   r1   r  s     r.   subtract_ints_listr    s"     ay1~H.(++r0   c                 2    U S   SSS2   n[        S U5      $ )zI
parse action to multiply integers in a VBA expression with operator '*'
r   Nr(   c                 
    X-  $ r+   r,   r  s     r.   rV  $multiply_ints_list.<locals>.<lambda>  r  r0   r1   r  s     r.   multiply_ints_listr    "     ay1~H.(++r0   c                 2    U S   SSS2   n[        S U5      $ )zG
parse action to divide integers in a VBA expression with operator '/'
r   Nr(   c                 
    X-  $ r+   r,   r  s     r.   rV  "divide_ints_list.<locals>.<lambda>  r  r0   r1   r  s     r.   divide_ints_listr    r  r0   *r   c                 ,    U R                  [        5      $ )a  
Check if the provided data is the content of a MSO/ActiveMime file, such as
the ones created by Outlook in some cases, or Word/Excel when saving a
file with the MHTML format or the Word 2003 XML format.
This function only checks the ActiveMime magic at the beginning of data.
:param data: bytes string, MSO/ActiveMime file content
:return: bool, True if the file is MSO, False otherwise
)
startswithMSO_ACTIVEMIME_HEADERdatas    r.   is_mso_filer    s     ??011r0   r-   c           	          [        U 5      (       d   eSS/n [        R                  " SU SS9S   S-   n[        R	                  SU-  5        UR                  SU5        U H6  n [        R	                  SU-  5        [        R                  " XS 5      nUs  $    [        R	                  S5        [        R                  U 5       HF  nUR                  5       n [        R	                  SU-  5        [        R                  " XS 5      nUs  $    [        S5      e! [        R                   a<  n[        R                  S	U-  5        [        R	                  S
SS9  [        S5      eSnAff = f! [        R                   a>  n[        R                  SU< SU< S35        [        R	                  S
SS9   SnAGMY  SnAff = f! [        R                   a8  n[        R                  SU-  5        [        R	                  S
SS9   SnAGMD  SnAff = f)ae  
Extract the data stored into a MSO/ActiveMime file, such as
the ones created by Outlook in some cases, or Word/Excel when saving a
file with the MHTML format or the Word 2003 XML format.

:param data: bytes string, MSO/ActiveMime file content
:return: bytes string, extracted data (uncompressed)

raise a MsoExtractionError if the data cannot be extracted
2   i*  <H   )offsetr   .   z$Parsing MSO file: data offset = 0x%Xz/Unable to parse MSO/ActiveMime file header (%s)Trace:Texc_infoz*Unable to parse MSO/ActiveMime file headerNz7Attempting zlib decompression from MSO file offset 0x%Xz%zlib decompression failed for offset  (r>  z8Looking for potential zlib-compressed blocks in MSO filezzlib decompression failed (%s)z4Unable to decompress data from a MSO/ActiveMime file)r  structunpack_fromrY   debuginserterrorinfor|   zlib
decompressre_zlib_headerfinditerrD   )r  offsetsr  rG   rD   extracted_datamatchs          r.   mso_file_extractr    s    t
 UmG
O##D$t<Q?"D		86ABq&! 	/IIORWWX!__T&\:N!!	  IIHI((.	/IIORWWX!__T&\:N!! / S
TT5 << OBSHI		(T	* !MNNO zz 	/HHs$ %IIhI..	/ zz 	/HH5;<IIhI..	/sH   AD $1E,1GE)-7E$$E),F> 2F99F>H,HHc                 >    [        U 5      R                  [        5      $ )z
returns True if string s only contains printable ASCII characters
(i.e. contained in string.printable)
This is similar to Python 3's str.isprintable, for Python 2.x.
:param s: str
:return: bool
)setissubset_PRINTABLE_SET)ss    r.   is_printabler    s     q6??>**r0   c                     X-
  n[        [        R                  " [        R                  " US5      5      5      n[	        US/5      nSU-	  nU) nSU-	  S-   nXEX64$ )aF  
compute bit masks to decode a CopyToken according to MS-OVBA 2.4.1.3.19.1 CopyToken Help

decompressed_current: number of decompressed bytes so far, i.e. len(decompressed_container)
decompressed_chunk_start: offset of the current chunk in the decompressed container
return length_mask, offset_mask, bit_count, maximum_length
r(   r   i  r3   )r   mathceilrY   max)decompressed_currentdecompressed_chunk_start
difference	bit_countlength_maskoffset_maskmaximum_lengths          r.   copytoken_helpr    sc     &@JDIIdhhz1567IYN#II%K,K	)Q.NY>>r0   c                 T   [        U [        5      (       d  [        U 5      n [        R                  SR	                  [        U 5      5      5        [        5       nSnX   nUS:w  a  [        SR	                  U5      5      eUS-  nU[        U 5      :  Ga  Un[        R                  " SXUS-    5      S   nUS-  S-   nUS	-	  S
-  nUS:w  a  [        S5      eUS-	  S-  n[        R                  SR	                  XdU5      5        US:X  a  US:  a  [        SU-  5      eUS:X  a  US:w  a  [        SU-  5      eXF-   [        U 5      :  a  [        R                  S5        [        [        U 5      XF-   /5      n	US-   nUS:X  a  UR                  XUS-    5        US-  nO[        U5      n
X):  a  X   nUS-  n[        SS5       H  nX):  a    OX-	  S-  nUS:X  a  UR                  X   /5        US-  nM2  [        R                  " SXUS-    5      S   n[        [        U5      U
5      u  nnnnX-  S-   nUU-  nSU-
  nUU-	  S-   n[        U5      U-
  n[        UUU-   5       H  nUR                  UU   /5        M     US-  nM     X):  a  M  U[        U 5      :  a  GM  [        U5      $ )z
Decompress a stream according to MS-OVBA section 2.4.1

:param compressed_container bytearray: bytearray or bytes compressed according to the MS-OVBA 2.4.1.3.6 Compression algorithm
:return: the decompressed container as a bytes string
:rtype: bytes
z-decompress_stream: compressed size = {} bytesr   r   zinvalid signature byte {0:02X}r  r(   i  r3      r   z9Invalid CompressedChunkSignature in VBA compressed stream   z2chunk size = {}, offset = {}, compressed flag = {}i  z:CompressedChunkSize=%d > 4098 but CompressedChunkFlag == 1z;CompressedChunkSize=%d != 4098 but CompressedChunkFlag == 0z3Chunk size is larger than remaining compressed datai   r   r]  )r@   	bytearrayrY   r  r:   lenr   r  unpackwarningminextendxranger  bytes)compressed_containerdecompressed_containercompressed_currentsig_bytecompressed_chunk_startcompressed_chunk_header
chunk_sizechunk_signature
chunk_flagcompressed_endr  	flag_byte	bit_indexflag_bit
copy_tokenr  r  r  rL  lengthtemp1temp2r  copy_sourceindexs                            r.   decompress_streamr  %  s2   : *I66()=>II=DDSI]E^_`&[#7H49@@JKK! s#78
8!3 MM$ 4LbefLf ghijk 	  .6!;
2b8D@e#XYY-3t;
		FMMjr|}~ ?zD0Y\ffgg?zT1Z]gghh ".5I1JJKKMNc"679O9\]^3a7? #))*>RdgkRk*lm$& (++A'B$$5
 1D	"a'"!'1I); !* 6!;H1}.557K7_6`a*a/* #MM$0DXjmnXn0opqrs # BP 679QBS>[)Q",":a!? *[ 8 "Y"'5.A!5&)*@&AF&J%+Kv9M%NE299;QRW;X:YZ &O*a/*7 ". %5Y s#78
8` '((r0   c                       \ rS rSrSrS rSrg)
VBA_Modulei  zp
Class to parse a VBA module from an OLE file, and to store all the corresponding
metadata and VBA source code.
c           	      L   Xl         SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l	        SU l
        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l         [&        R(                  " SUR+                  S5      5      S   nUR-                  SSU5        [&        R(                  " SUR+                  S	5      5      S   nUR+                  U5      nUR/                  U5      U l        [1        U R                  5      U l        [&        R(                  " SUR+                  S5      5      S   nUS
:X  ax  [&        R(                  " SUR+                  S	5      5      S   nUR+                  U5      R3                  SS5      U l        [&        R(                  " SUR+                  S5      5      S   nUS:X  Ga  [&        R(                  " SUR+                  S	5      5      S   nUR+                  U5      nUR/                  U5      U l        [1        U R                  5      U l        [&        R(                  " SUR+                  S5      5      S   n	UR-                  SSU	5        [&        R(                  " SUR+                  S	5      5      S   nUR+                  U5      R3                  SS5      U l        [&        R(                  " SUR+                  S5      5      S   nUS:X  a  [&        R(                  " SUR+                  S	5      5      S   nUR+                  U5      n
UR/                  U
5      U l        [&        R(                  " SUR+                  S5      5      S   n	UR-                  SSU	5        [&        R(                  " SUR+                  S	5      5      S   nUR+                  U5      U l        [&        R(                  " SUR+                  S5      5      S   nUS:X  a  [&        R(                  " SUR+                  S	5      5      S   nUR-                  SS	U5        [&        R(                  " SUR+                  S	5      5      S   U l	        [&        R(                  " SUR+                  S5      5      S   nUS:X  a  [&        R(                  " SUR+                  S	5      5      S   nUR-                  SS	U5        [&        R(                  " SUR+                  S	5      5      S   n[&        R(                  " SUR+                  S5      5      S   nUS:X  a  [&        R(                  " SUR+                  S	5      5      S   nUR-                  SSU5        [&        R(                  " SUR+                  S5      5      S   n[&        R(                  " SUR+                  S5      5      S   nUS:X  d  US:X  aX  Xpl
        [&        R(                  " SUR+                  S	5      5      S   n	[&        R(                  " SUR+                  S5      5      S   nUS:X  al  SU l        [&        R(                  " SUR+                  S	5      5      S   n	UR-                  SSU	5        [&        R(                  " SUR+                  S5      5      S   nUS:X  al  SU l        [&        R(                  " SUR+                  S	5      5      S   n	UR-                  SSU	5        [&        R(                  " SUR+                  S5      5      S   nUS :X  a>  [&        R(                  " SUR+                  S	5      5      S   n	UR-                  S!SU	5        SnUS:w  a$  [4        R7                  S"R9                  U5      5        [4        R;                  S#R9                  U R                  5      5        [4        R;                  S$R9                  U R
                  5      5        [4        R;                  S%R9                  U R                  5      5        SnU R                  U R                  U R                  U R                  4nU Hu  nUc  M   UR<                  S&-   U-   U l        [4        R;                  S'U R$                  -  5        UR>                  RA                  U R$                  5      R+                  5       n  O   Uce  [4        RE                  S+X1RF                  S,RI                  S- U 5       5      4-  5        URJ                  (       a  g[M        S.S&U R                  -   5      e[4        R;                  S/R9                  [O        U5      5      5        [4        R;                  S0R9                  U R                  5      5        XR                  S n[O        U5      S:  a  [Q        [S        U5      5      nXl        UR/                  U5      U l        [1        U R                  5      U l        U R                   RT                  RW                  U R                  RY                  5       S15      nS2R9                  U R                  U5      U l        [1        U R                   5      U l        [4        R;                  S3R9                  U R"                  5      5        g[4        R7                  S4R9                  U R
                  5      5        g! [B         a*  n[4        R;                  S(U< S)U< S*35         SnAGM  SnAff = f! [Z        [L        4 a    e [\         a3  n[4        RE                  S5R9                  X1RF                  5      SS69  e SnAff = f)7a]  
Parse a VBA Module record from the dir stream of a VBA project.
Reference: MS-OVBA 2.3.4.2.3.2 MODULE Record

:param VBA_Project project: VBA_Project, corresponding VBA project
:param olefile.OleStream dir_stream: olefile.OleStream, file object containing the module record
:param int module_index: int, index of the module in the VBA project list
NFr  r(   r   MODULENAME_Id   <Lr   G   zUTF-16LErK      MODULESTREAMNAME_Reservedr     MODULEDOCSTRING_ReservedH   1   MODULEOFFSET_Sizer  MODULEHELPCONTEXT_Size,   MODULECOOKIE_Size!   "   %   TMODULEREADONLY_Reserved(   MODULEPRIVATE_Reserved+   MODULE_Reservedz,unknown or invalid module section id {0:04X}zModule Name = {0}zStream Name = {0}zTextOffset = {0}zVBA/zopening VBA code stream %szfailed to open stream VBA/r  z), try other namez4Could not open stream %d of %d ('VBA/' + one of %r)!r   c              3   2   #    U  H  nS U-   S -   v   M     g7f)'Nr,   )r;   stream_names     r.   r=   &VBA_Module.__init__.<locals>.<genexpr>R  s"      %C8A &);%6%<8As   z[BASE]zlength of code_data = {0}zoffset of code_data = {0}vbaz{0}.{1}zextracted file {0}z(module stream {0} has code data length 0z Error parsing module {0} of {1}:r  )/projectr   name_str_name_unicode
streamnamestreamname_str_streamname_unicode	docstring_docstring_unicode
textoffsetr   readonlyprivatecode_rawcodecode_strrc   filename_str	code_pathr  r  readcheck_valuedecode_bytesrQ   rS   rY   r  r:   r  vba_rootole
openstreamIOErrorr  modules_countrB   relaxedr   r  r  r  
module_extgetlowerr   	Exception)re   r	  
dir_streammodule_index_idsizemodulename_bytes
section_idstreamname_bytesreserveddocstring_bytesmodulehelpcontext_sizehelpcontextcookie	code_data	try_namesr  ioefilextrG   s                       r.   ra   VBA_Module.__init__  s	    	!"#' "&		 b	 --jooa&89!<C===zq'9:1=D)t4,,-=>DI'		2DM  tZ__Q-?@CJV# }}T:??1+=>qA%/__T%:%A%A*i%X"#]]41CDQG
V# }}T:??1+=>qA#-??4#8 ")"6"67G"H&1$//&B#!==zq/AB1E##$?R}}T:??1+=>qA+5??4+@+G+G
T]+^(#]]41CDQG
V# }}T:??1+=>qA",//$"7!(!5!5o!F!==zq/AB1E##$>Q}}T:??1+=>qA*4//$*?'#]]41CDQG
V# }}T:??1+=>qA##$7F"(--jooa6H"I!"L#]]41CDQG
V# *0tZ__Q=O)PQR)S&##$<fF\] %mmD*//!2DEaH#]]41CDQG
V# }}T:??1+=>qA##$7FtZ__Q-?@C#]]41CDQG
V#zV'; '	!==zq/AB1E#]]41CDQG
V# !%!==zq/AB1E##$=vxP#]]41CDQG
V#  $!==zq/AB1E##$<fhO#]]41CDQG
V# "==zq/AB1E##$5vxH!
T!JQQR\]^II)00?@II)001D1DEFII(//@AI$*B*BDIItOaOabI( *8)0)9)9G)Ck)Q		">"OP$+KK$:$:4>>$J$O$O$Q	  )  O(*?*?HH %C8A%C CDD E ??,Xv		7IJJII188YHIII188IJ!//"23I9~!-i	.BC	 )#00;	 +DII 60044TYY__5FN * 1 1$))V D$/$>!		.55d6G6GHIFMMdNaNabc? # 8		%0##7 8 88@ $%78 	 	HH7f\+@+@A"  $
 	sR   ^#k .A,jAk -Fk 0.k 
k)kk kk l#0.ll#)r  r  r  r  r  r  r  r  rc   r  r   r
  r  r	  r  r  r  r  r   Nr   r,   r0   r.   r  r    s    
Ir0   r  c                   >    \ rS rSrSrS
S jrS rS rS rSS jr	Sr
g	)VBA_Projectix  zm
Class to parse a VBA project from an OLE file, and to store all the corresponding
metadata and VBA modules.
c                 j(   Xl         X l        X0l        X@l        XPl        / U l        0 U l        [        R                  SU-  5        UR                  U5      R                  5       n[        [        [        U5      5      5      nXpl        [        R                   " SUR                  S5      5      S   nU R#                  SSU5        [        R                   " SUR                  S5      5      S   n	U R#                  S	SU	5        [        R                   " SUR                  S5      5      S   U l        S
SSSS.n
U
R'                  U R$                  S5      U l        [        R                  SU R$                  U R(                  4-  5        U R$                  U
;  a.  [        R+                  SR-                  U R$                  5      5        [        R                   " SUR                  S5      5      S   nUS:X  a  UnU R#                  SSU5        [        R                   " SUR                  S5      5      S   nU R#                  SSU5        [        R                   " SUR                  S5      5      S   n[        R                  SR-                  US95        [        R                   " SUR                  S5      5      S   nUnU R#                  SSU5        [        R                   " SUR                  S5      5      S   nU R#                  SSU5        [        R                   " SUR                  S5      5      S   U l        U R#                  SSU R.                  5        [        R                   " SUR                  S5      5      S   nU R#                  SSU5        [        R                   " SUR                  S5      5      S   nU R#                  SSU5        [        R                   " SUR                  S5      5      S   U l        U R#                  SSU R0                  5        [        R                   " SUR                  S5      5      S   nU R#                  SS U5        [        R                   " SUR                  S5      5      S   nU R#                  S!SU5        [        R                   " SUR                  S5      5      S   U l        [4        R6                  " U R2                  5      U l        [        R                  S"U R2                  < S#U R8                  < 35        [4        R:                  " U R2                  5      U l        [        R                  S$U R2                  U R<                  4-  5        [        R                   " SUR                  S5      5      S   nU R#                  S%SU5        [        R                   " SUR                  S5      5      S   n[        R                  S&U-  5        US:  d  US':  a$  [        R+                  S(R-                  U5      5        UR                  U5      nU R?                  U5      U l         [        R                   " SUR                  S5      5      S   nU R#                  S)S*U5        [        R                   " SUR                  S5      5      S   nUS+:  a$  [        R+                  S,R-                  U5      5        UR                  U5      nU R?                  U5      U l!        [        R                   " SUR                  S5      5      S   nU R#                  S-S.U5        [        R                   " SUR                  S5      5      S   nUS-  S:w  a  [        R+                  S/5        UR                  U5      nURE                  S0S1S29U l#        [        R                   " SUR                  S5      5      S   nU R#                  S3S4U5        [        R                   " SUR                  S5      5      S   nUS5:  a$  [        R+                  S6R-                  U5      5        UR                  U5      n [        R                   " SUR                  S5      5      S   n!U R#                  S7S8U!5        [        R                   " SUR                  S5      5      S   n"U"U:w  a  [        R+                  S95        UR                  U"5      n#U#U :w  a  [        R+                  S:5        [        R                   " SUR                  S5      5      S   n$U R#                  S;S<U$5        [        R                   " SUR                  S5      5      S   n%U R#                  S=SU%5        [        R                   " SUR                  S5      5      S   n&U&n'[        R                   " SUR                  S5      5      S   n(U R#                  S>S?U(5        [        R                   " SUR                  S5      5      S   n)U R#                  S@SU)5        [        R                   " SUR                  S5      5      S   n*U R#                  SASU*5        [        R                   " SUR                  S5      5      S   n+U R#                  SBSCU+5        [        R                   " SUR                  S5      5      S   n,U R#                  SDSU,5        [        R                   " SUR                  S5      5      S   n-[        R                   " SUR                  S5      5      S   n.U-n'U.n'[        R                   " SUR                  S5      5      S   n/U R#                  SESFU/5        [        R                   " SUR                  S5      5      S   n0U0SG:  a$  [        R+                  SHR-                  U05      5        UR                  U05      n1[        R                   " SUR                  S5      5      S   n2U R#                  SISJU25        [        R                   " SUR                  S5      5      S   n3U3S-  S:w  a  [        R+                  SK5        UR                  U35      n4U1n'U4n'SLn5 [        R                   " SUR                  S5      5      S   n5[        R                  SMR-                  U55      5        U5SN:X  a  gLU5SO:X  Ga  U5n6[        R                   " SUR                  S5      5      S   n7UR                  U75      n8[        R                  SP[I        U R?                  U85      5      -  5        [        R                   " SUR                  S5      5      S   n9U9SQ:X  aC  [        R                   " SUR                  S5      5      S   n:UR                  U:5      n;U6n'U8n'U;n'GM:  U9n5[        R                  SMR-                  U55      5        U5SR:X  as  U5n<[        R                   " SUR                  S5      5      S   n=UR                  U=5      n>[        R                  SS[I        U R?                  U>5      5      -  5        U<n'U>n'GM  U5ST:X  Ga^  U5n?[        R                   " SUR                  S5      5      S   n@[        R                   " SUR                  S5      5      S   nAUR                  UA5      nB[        R                  SU[I        U R?                  UB5      5      -  5        [        R                   " SUR                  S5      5      S   nCU R#                  SVSUC5        [        R                   " SUR                  S5      5      S   nDU R#                  SWSUD5        U?n'U@n'UBn'[        R                   " SUR                  S5      5      S   nEUESO:X  Ga  U5nF[        R                   " SUR                  S5      5      S   nGUR                  UG5      nH[        R                  SX[I        U R?                  UH5      5      -  5        [        R                   " SUR                  S5      5      S   nIUISQ:X  aj  [        R                   " SUR                  S5      5      S   nJUR                  UJ5      nK[        R                   " SUR                  S5      5      S   nLWFn'WHn'UKn'OWInLOWEnLU R#                  SYSZWL5        [        R                   " SUR                  S5      5      S   nM[        R                   " SUR                  S5      5      S   nNUR                  UN5      nO[        R                   " SUR                  S5      5      S   nP[        R                   " SUR                  S5      5      S   nQUR                  S[5      nR[        R                   " SUR                  S5      5      S   nSUMn'UOn'UPn'UQn'URn'USn'GM>  U5S\:X  Ga  U5nT[        R                   " SUR                  S5      5      S   nU[        R                   " SUR                  S5      5      S   nVUR                  UV5      nW[        R                  S][I        U R?                  UW5      5      -  5        [        R                   " SUR                  S5      5      S   nXU R#                  S^SUX5        [        R                   " SUR                  S5      5      S   nYU R#                  S_SUY5        UTn'UUn'UWn'GM[  U5S`:X  Ga`  U5nZ[        R                   " SUR                  S5      5      S   n[[        R                   " SUR                  S5      5      S   n\UR                  U\5      n][        R                  Sa[I        U R?                  U]5      5      -  5        [        R                   " SUR                  S5      5      S   n^UR                  U^5      n_[        R                  Sb[I        U R?                  U_5      5      -  5        [        R                   " SUR                  S5      5      S   n`[        R                   " SUR                  S5      5      S   naUZn'U[n'U]n'U_n'U`n'Uan'GM  [        R+                  ScR-                  U55      5        [K        USdSeU55      e)fak  
Extract VBA macros from an OleFileIO object.

:param vba_root: path to the VBA root storage, containing the VBA storage and the PROJECT stream
:param project_path: path to the PROJECT stream
:param relaxed: If True, only create info/debug log entry if data is not as expected
                (e.g. opening substream fails); if False, raise an error in this case
zParsing the dir stream from %rr  r(   r   PROJECTSYSKIND_Idr   r  r   PROJECTSYSKIND_Sizez16-bit Windowsz32-bit Windows	Macintoshz64-bit Windows)r   r   r(   r3   UnknownzPROJECTSYSKIND_SysKind: %d - %sz&invalid PROJECTSYSKIND_SysKind {0:04X}J   PROJETCOMPATVERSION_IdPROJECTCOMPATVERSION_Sizez compat version: {compat_version})compat_versionPROJECTLCID_IdPROJECTLCID_SizePROJECTLCID_Lcidi	  PROJECTLCIDINVOKE_Id   PROJECTLCIDINVOKE_SizePROJECTLCIDINVOKE_LcidInvokePROJECTCODEPAGE_Idr3   PROJECTCODEPAGE_SizezProject Code Page:  - z.Python codec corresponding to code page %d: %sPROJECTNAME_IdzProject name size: %d bytes   z=PROJECTNAME_SizeOfProjectName value not in range [1-128]: {0}PROJECTDOCSTRING_Idr4   i  z8PROJECTDOCSTRING_SizeOfDocString value not in range: {0}PROJECTDOCSTRING_Reserved@   z3PROJECTDOCSTRING_SizeOfDocStringUnicode is not evenutf16rK   rL   PROJECTHELPFILEPATH_Idr   i  z;PROJECTHELPFILEPATH_SizeOfHelpFile1 value not in range: {0}PROJECTHELPFILEPATH_Reserved=   zVPROJECTHELPFILEPATH_SizeOfHelpFile1 does not equal PROJECTHELPFILEPATH_SizeOfHelpFile2zJPROJECTHELPFILEPATH_HelpFile1 does not equal PROJECTHELPFILEPATH_HelpFile2PROJECTHELPCONTEXT_Idr   PROJECTHELPCONTEXT_SizePROJECTLIBFLAGS_Idr   PROJECTLIBFLAGS_SizePROJECTLIBFLAGS_ProjectLibFlagsPROJECTVERSION_Idr   PROJECTVERSION_ReservedPROJECTCONSTANTS_Idr  i  z8PROJECTCONSTANTS_SizeOfConstants value not in range: {0}PROJECTCONSTANTS_Reserved<   z3PROJECTCONSTANTS_SizeOfConstantsUnicode is not evenNzreference type = {0:04X}r     zREFERENCE name: %s>   3   zREFERENCE original lib id: %s/   z%REFERENCE control twiddled lib id: %sREFERENCECONTROL_Reserved1REFERENCECONTROL_Reserved2z*REFERENCE control name record extended: %sREFERENCECONTROL_Reserved30   r]     zREFERENCE registered lib id: %sREFERENCEREGISTERED_Reserved1REFERENCEREGISTERED_Reserved2   z%REFERENCE project lib id absolute: %sz%REFERENCE project lib id relative: %sz#invalid or unknown check Id {0:04X}zreference type)r  r_  ra  rb  rg  rj  )&r  r  project_pathdir_pathr!  modulesr"  rY   r  r  r  r   r  r  r&  r  r  r  syskindr#  syskind_namer  r:   lcid
lcidinvokecodepager%   get_codepage_namecodepage_namecodepage2codeccodecr  projectnamer  rS   docstring_unicoderQ   r   )bre   r  r  rk  rl  r!  dir_compressedr&  projectsyskind_idprojectsyskind_sizeSYSKIND_NAME
project_idprojectcompatversion_idprojectcompatversion_size"projectcompatversion_compatversionprojectlcid_idprojectlcid_sizeprojectlcidinvoke_idprojectlcidinvoke_sizeprojectcodepage_idprojectcodepage_sizeprojectname_idsizeof_projectnameprojectname_bytesprojectdocstring_id!projectdocstring_sizeof_docstringr.  projectdocstring_reserved)projectdocstring_sizeof_docstring_unicodedocstring_unicode_bytesprojecthelpfilepath_id$projecthelpfilepath_sizeof_helpfile1projecthelpfilepath_helpfile1projecthelpfilepath_reserved$projecthelpfilepath_sizeof_helpfile2projecthelpfilepath_helpfile2projecthelpcontext_idprojecthelpcontext_sizeprojecthelpcontext_helpcontextunusedprojectlibflags_idprojectlibflags_sizeprojectlibflags_projectlibflagsprojectversion_idprojectversion_reservedprojectversion_versionmajorprojectversion_versionminorprojectconstants_id!projectconstants_sizeof_constantsprojectconstants_constantsprojectconstants_reserved)projectconstants_sizeof_constants_unicode"projectconstants_constants_unicodecheckreference_idreference_sizeof_namereference_namereference_reservedreference_sizeof_name_unicodereference_name_unicodereferenceoriginal_id&referenceoriginal_sizeof_libidoriginalreferenceoriginal_libidoriginalreferencecontrol_idreferencecontrol_sizetwiddled%referencecontrol_sizeof_libidtwiddledreferencecontrol_libidtwiddledreferencecontrol_reserved1referencecontrol_reserved2check2&referencecontrol_namerecordextended_id/referencecontrol_namerecordextended_sizeof_name(referencecontrol_namerecordextended_name,referencecontrol_namerecordextended_reserved7referencecontrol_namerecordextended_sizeof_name_unicode0referencecontrol_namerecordextended_name_unicodereferencecontrol_reserved3referencecontrol_sizeextended%referencecontrol_sizeof_libidextendedreferencecontrol_libidextendedreferencecontrol_reserved4referencecontrol_reserved5 referencecontrol_originaltypelibreferencecontrol_cookiereferenceregistered_idreferenceregistered_size referenceregistered_sizeof_libidreferenceregistered_libidreferenceregistered_reserved1referenceregistered_reserved2referenceproject_idreferenceproject_size%referenceproject_sizeof_libidabsolutereferenceproject_libidabsolute%referenceproject_sizeof_libidrelativereferenceproject_libidrelativereferenceproject_majorversionreferenceproject_minorversionsb                                                                                                     r.   ra   VBA_Project.__init__~  s     ) 		2X=>1668.y/HIJ
$ #MM$
0BCAF,f6GH$mmD*//!2DEaH.8KL}}T:??1+=>qA"""	
 ),,T\\9E		3t||TEVEV6WWX<<|+II>EEdllST ]]4);<Q?
 '1#5v?VW(.dJOOA<N(OPQ(R%8&B[\17tZ__UVEW1XYZ1[.II8??Oq?rs  tZ__Q-?@CJ# 	)6>B!==zq/AB1E+V5EFMM$
(:;A>	+UDII>  &}}T:??13EFqI/9MN!'tZ__Q5G!H!K16;QR --jooa.@A!D7P $]]41CDQG-v7IJ%}}T:??13EFqI/9MNdJOOA,>?B&88G		$--ASASTU--dmm<
		BdmmUYU_U_E``a
  tZ__Q-?@C)6>B#]]41CDQG		/2DDE!%7#%=IIU\\]opq&OO,>?,,->?
 %mmD*//!2DEaH.8KL,2MM$
PQ@R,STU,V),t3IIJQQRstv
 %//*KL**?;$*MM$
8J$KA$N!4f>WX4:MM$
XYHZ4[\]4^14q8A=IIKL #-//2["\!8!?!?PY!?!Z "(tZ__Q5G!H!K16;QR/5}}T:??STCU/VWX/Y,/#5IIMTTUyz|(28\(]%'-}}T:??1;M'Nq'Q$7A]^/5}}T:??STCU/VWX/Y,/3WWIIno(28\(]%(,IIIIbc !'dJOOA4F G J0&:OP"(--jooa6H"I!"L2F<ST)/tZ__Q=O)PQR)S&/ $]]41CDQG-v7IJ%}}T:??13EFqI/9MN*0--jooa>P*QRS*T':FDcd #MM$
0BCAF,f6GH"(--jooa6H"I!"L2F<ST&,mmD*//!:L&Ma&P#&,mmD*//!:L&Ma&P#,, %mmD*//!2DEaH.8KL,2MM$
PQ@R,STU,V),t3IIJQQRstv%/__5V%W"$*MM$
8J$KA$N!4f>WX4:MM$
XYHZ4[\]4^14q8A=IIKL-7__=f-g*+3 MM$
(:;A>EII077>?  %(.dJOOA<N(OPQ(R%!+1F!G		.T=N=N~=^1__`%+]]49K%LQ%O" &/ 5;MM$
XYHZ4[\]4^1-7__=Z-[*)F+F3F.EII8??FG (-$9?tZ__]^M_9`ab9c62<//Bh2i/		9KHYHYZyHz<{{|-8 ',#06dJOOTUDV0WXY0Z-8>dJOO\]L^8_`a8b51;Af1g.		AKPTPaPa  cA  QB  EC  C  D-3]]4QRAS-TUV-W*  !=vGab-3]]4QRAS-TUV-W*  !=vGab,67tZ__Q-?@CV#=B:FLmmTXZdZiZijkZlFmnoFpC?IG@I<IIJ[))*RSNU U VCI==QUWaWfWfghWiCjklCm@CvMRXR_R_`dfpfufuvwfxRyz{R|OKU??SLUH5;]]4YZI[5\]^5_2!G!I!Q5a217.  !=vGab06dJOOTUDV0WXY0Z-8>dJOO\]L^8_`a8b51;Af1g.-3]]4QRAS-TUV-W*-3]]4QRAS-TUV-W*3=??23F0*0--jooa>P*QRS*T'673390 */&+1==zq?Q+RST+U(39==zWXGY3Z[\3]0,6OO<\,])		;k$J[J[\uJv>wwx06dJOOTUDV0WXY0Z-  !@&Jgh06dJOOTUDV0WXY0Z-  !@&Jgh/12 ',#(.dJOOA<N(OPQ(R%8>dJOO\]L^8_`a8b51;Af1g.		AKPTPaPa  cA  QB  EC  C  D8>dJOO\]L^8_`a8b51;Af1g.		AKPTPaPa  cA  QB  EC  C  D06dJOOTUDV0WXY0Z-06dJOOTUDV0WXY0Z-,.7766II;BB5IJ%h0@Bfhmnnr0   c                     X#:w  aN  U R                   (       a&  [        R                  SR                  XU5      5        g [	        U R
                  XU5      eg )Nz2invalid value for {0} expected {1:04X} got {2:04X})r!  rY   r  r:   r   rl  )re   r   r   r   s       r.   r  VBA_Project.check_value  sF    || P!6$%8: *$--OO r0   c                 :   U R                   R                  U R                  5      n0 U l        U H  nU R	                  U5      n[
        R                  SU-  5        UR                  5       nSU;   d  MD  UR                  SS5      u  p4UR                  5       nUS:X  a*  UR                  SS5      S   n[        U R                  U'   M  US:X  a  [        U R                  U'   M  US:X  a  [        U R                  U'   M  US	:X  d  M  [        U R                  U'   M     g
)z8
Parse the PROJECT stream from the VBA project
:return:
zPROJECT: %r=r   Documentr   r   ModuleClass	BaseClassN)r  r  rk  r"  r  rY   r  rr  splitr$  CLASS_EXTENSIONMODULE_EXTENSIONFORM_EXTENSION)re   project_streamliner   r   s        r.   parse_project_stream VBA_Project.parse_project_stream  s     ,,T->->?, "D$$T*DIImd*+::<Dd{"jja0
 :%!KKQ/2E-<DOOE*X%-=DOOE*W_-<DOOE*[(-;DOOE*+ #r0   c              #     #    U R                   n[        R                  " SUR                  S5      5      S   nU R	                  SSU5        [        R                  " SUR                  S5      5      S   U l        [        R                  " SUR                  S5      5      S   nU R	                  SSU5        [        R                  " SUR                  S5      5      S   nU R	                  S	SU5        [        R                  " SUR                  S5      5      S   nUn[        R                  S
R                  U R
                  5      5        [        SU R
                  5       HW  n[        X R                   US9nU R                  R                  U5        UR                  UR                  UR                  4v   MY     Un	g 7f)Nr  r   r   PROJECTMODULES_Sizer(   r  %PROJECTMODULES_ProjectCookieRecord_Id   'PROJECTMODULES_ProjectCookieRecord_Sizezparsing {0} modules)r'  )r&  r  r  r  r  r   rY   r  r:   r  r  rm  appendr  r  r  )
re   r&  projectmodules_sizer(  r)  projectcookierecord_cookier  r'  modulerL  s
             r.   parse_modulesVBA_Project.parse_modules  sh    __
 %mmD*//!2DEaH.8KL#]]41CDQGmmD*//!"45a8@&#N}}T:??1#56q9BFDQ%+]]49K%LQ%O"+		'..t/A/ABC"1d&8&89LooLQFLL'##V%8%8&//JJ : s   F<F>c                 6    UR                  U R                  US9$ )z
Decode a bytes string to a unicode string, using the project code page
:param bytes_string: bytes, bytes string to be decoded
:param errors: str, mode to handle unicode conversion errors
:return: str/unicode, decoded string
rL   )rS   rv  )re   rT   rM   s      r.   r  VBA_Project.decode_bytes*  s     ""4::f"==r0   )rv  rr  rt  rl  r&  r  rx  rp  rq  r"  rm  r   r  rk  rw  r!  rn  ro  r  NT)rK   )rj   rk   rl   rm   rn   ra   r  r  r  r  ro   r,   r0   r.   r8  r8  x  s%    
Qoh
	P4<l.>r0   r8  c              #      #    [         R                  SU-  5        [        XX#U5      nUR                  5         UR	                  5        H  u  pgnXgU4v   M     g7f)a  
Extract VBA macros from an OleFileIO object.
Internal function, do not call directly.

vba_root: path to the VBA root storage, containing the VBA storage and the PROJECT stream
vba_project: path to the PROJECT stream
:param relaxed: If True, only create info/debug log entry if data is not as expected
                (e.g. opening substream fails); if False, raise an error in this case
This is a generator, yielding (stream path, VBA filename, VBA source code) for each VBA code stream
zrelaxed is %sN)rY   r  r8  r  r  )	r  r  rk  rl  r!  r	  r  rc   r2  s	            r.   _extract_vbar  5  sV      IIo'(#IG  "*1*?*?*A&	YI.. +Bs   AAc                      U R                  SS5      n U R                  SS5      n U R                  SS5      n U $ !   [        R                  S[        U 5      -  5        e = f)z
Parse a VBA module code to detect continuation line characters (underscore) and
collapse split lines. Continuation line characters are replaced by spaces.

:param vba_code: str, VBA module code
:return: str, VBA module code with long lines collapsed
z _
 z _z _
ztype(vba_code)=%s)rK   rY   rj  r   )vba_codes    r.   vba_collapse_long_linesr  I  sd    ##Hc2##FC0##FC0 O)DN:;s	   6: $Ac                     U R                  5       nSnU H&  nUR                  S5      (       a  SU;  a  US-  nM&    O   SR                  XS 5      nU$ )a  
Filter VBA source code to remove the first lines starting with "Attribute VB_",
which are automatically added by MS Office and not displayed in the VBA Editor.
This should only be used when displaying source code for human analysis.

Note: lines are not filtered if they contain a colon, because it could be
used to hide malicious instructions.

:param vba_code: str, VBA source code
:return: str, filtered VBA source code
r   zAttribute VB_:r   
N)
splitlinesr  rB   )r  	vba_linesrD   r  r  s        r.   
filter_vbar  \  s\     ##%IE???++C4KQJE	  ))If%
&CJr0   c                    / nSnU(       a  SU-  n[         R                  5        Hm  u  pEU Hb  n[        R                  " S[        R                  " U5      -   S-   U 5      nU(       d  M=  UR                  5       nUR                  XU-   45        Md     Mo     [        R                  5        HY  u  pEU HN  n[        R                  " SU-   S-   U 5      nU(       d  M)  UR                  5       nUR                  XU-   45        MP     M[     U$ )aQ  
Detect if the VBA code contains keywords corresponding to macros running
automatically when triggered by specific actions (e.g. when a document is
opened or closed).

:param vba_code: str, VBA source code
:param obfuscation: None or str, name of obfuscation to be added to description
:return: list of str tuples (keyword, description)
r7    (obfuscation: %s)(?i)\b\b)AUTOEXEC_KEYWORDSitemsresearchescapegroupr  AUTOEXEC_KEYWORDS_REGEX	r  obfuscationresultsobf_textdescriptionkeywordskeywordr  found_keywords	            r.   detect_autoexecr  t  s     GH'+5!2!8!8!:G IIi"))G*<<uDhOEu %X/EFG   "; "9!>!>!@G IIi'1E98DEu %X/EFG   "A Nr0   c                    / nSnU(       a  SU-  n[         R                  5        Hm  u  pEU Hb  n[        R                  " S[        R                  " U5      -   S-   U 5      nU(       d  M=  UR                  5       nUR                  XU-   45        Md     Mo     [        R                  5        HY  u  pEU HN  n[        R                  " SU-   S-   U 5      nU(       d  M)  UR                  5       nUR                  XU-   45        MP     M[     [        R                  5        HD  u  pEU H9  nUR                  5       U ;   d  M  US:X  a  Ub  M$  UR                  XdU-   45        M;     MF     U$ )a  
Detect if the VBA code contains suspicious keywords corresponding to
potential malware behaviour.

:param vba_code: str, VBA source code
:param obfuscation: None or str, name of obfuscation to be added to description
:return: list of str tuples (keyword, description)
r7   r  r   r  r=  )
SUSPICIOUS_KEYWORDSr  r  r  r  r  r  SUSPICIOUS_KEYWORDS_REGEXSUSPICIOUS_KEYWORDS_NOREGEXr$  r	  s	            r.   detect_suspiciousr    s?    GH'+5!4!:!:!<G IIi"))G*<<uDhOEu %X/EFG   "= ";!@!@!BG IIi'1E98DEu %X/EFG   "C "=!B!B!DG}}(*})@NNG8-C#DE	   "E Nr0   c                 f   / n[        5       nSnU(       a  SU-  n[         H  u  pVUR                  U 5       Hr  nUR                  5       nSn	[         H  n
UR                  U
5      (       d  M  Sn	M     X;  d  MC  U	(       a  ML  UR                  XT-   U45        UR                  U5        Mt     M     U$ )z
Detect if the VBA code contains specific patterns such as IP addresses,
URLs, e-mail addresses, executable file names, etc.

:param vba_code: str, VBA source code
:return: list of str tuples (pattern type, value)
r7   r  FT)r  RE_PATTERNSr  r  EXCLUDE_URLS_PATTERNSr  r  add)r  r
  r  foundr  pattern_type
pattern_rer  r   exclude_pattern_foundurl_exclude_patterns              r.   detect_patternsr     s     GEEH'+5$/ ((2EKKME$)!'<###$788,0) (= !*?*? 7?@		%  3 %0 Nr0   c                    / n[        5       n[        R                  U 5       H\  nUR                  5       nXB;  d  M  [	        [
        R                  " U5      5      nUR                  XE45        UR                  U5        M^     U$ )z
Detect if the VBA code contains strings encoded in hexadecimal.

:param vba_code: str, VBA source code
:return: list of str tuples (encoded string, decoded string)
)	r  re_hex_stringr  r  rV   r{  	unhexlifyr  r  )r  r  r  r  r   decodeds         r.   detect_hex_stringsr%    sm     GEE''1 2 25 9:GNNE+,IIe 2 Nr0   c                     / n[        5       n[        R                  U 5       H  nUR                  5       R	                  S5      n[
        R                  U5      (       d  M>  XB;  d  ME  UR                  5       [        ;  d  M_   [        [        R                  " U5      5      nUR                  XE45        UR                  U5        M     U$ ! [        [        4 a#  n[         R#                  SU-  5         SnAM  SnAff = f)z
Detect if the VBA code contains strings encoded in base64.

:param vba_code: str, VBA source code
:return: list of str tuples (encoded string, decoded string)
rA  zFailed to base64-decode (%s)N)r  re_base64_stringr  r  rr  re_nothex_checkr  r$  BASE64_WHITELISTrV   base64	b64decoder  r  	TypeErrorr   rY   r  r  r  r  r  r   r$  rG   s          r.   detect_base64_stringsr.    s     GEE!**84##C(%%e,,%++-7G"G@#F$4$4U$;</0		%  5 N z* @		83>??@s   AC

C=C88C=c                 d    SnU  H  nUR                  5       (       d  M  X-  nM      [        U5      $ )Nr7   isdigitr   inputresultr<   s      r.   
StripCharsr5  	  s/    F99;;KF  v;r0   c                 n    SnU  H#  nUR                  5       (       a  X-  nM  US-  nM%     [        U5      $ )Nr7   0r0  r2  s      r.   StripCharsWithZeror8  	  s8    F99;;KFcMF	 
 v;r0   c                 x   U SS n[        U[        U5      S-  S-
  [        U5      S-   5      n[        U[        U5      S-  [        U5      S-  S-    5      nX2-
  nUS [        U5      S-  S-
   U[        U5      S-  S-   S  -   n[        U[        U5      S-  US-  -
  [        U5      S-  US-  -    5      nUS [        U5      S-  US-  -
   U[        U5      S-  US-  -   S  -   n[        S[        U5      U5       Vs/ s H	  oaXfU-    PM     nnSnU H  n	U[	        [        U	5      U-  5      -  nM     U$ s  snf )Nr   r(   r   r7   )r8  r  r5  rangerh  )
	inputTextwork	strKeyEnc
strKeySize	nCharSize
strKeyEnc2rk  
work_splitr$  r  s
             r.   DridexUrlDecoderC  	  sg   Qr?D"4TQ!(;c$i!m#MNI#D#d)a-3t9q=A:M$NOJ&I$#d)a-1$%c$i!mq-@-A(BBDD#d)a-IaK!@3t9q=U^_`U`BabcJ0#d)a-IaK01D#d)a-IVWK9X9Y4ZZD/4QD	9/MN/M!q9%/MJNG3z%(344  N Os   >D7c                    / n[        5       n[        R                  U 5       Hq  nUR                  5       SS n[        R                  U5      (       d  M2  XB;  d  M9   [        [        U5      5      nUR                  XE45        UR                  U5        Ms     U$ ! [         a#  n[        R                  SU-  5         SnAM  SnAff = f)z
Detect if the VBA code contains strings obfuscated with a specific algorithm found in Dridex samples.

:param vba_code: str, VBA source code
:return: list of str tuples (encoded string, decoded string)
r   rt  zFailed to Dridex-decode (%s)N)r  re_dridex_stringr  r  r(  r  rV   rC  r  r  r%  rY   r  r-  s          r.   detect_dridex_stringsrF  2	  s     GEE!**84a#%%e,,@#OE$:;/0		%  5 N  @		83>??@s   7B
C#CCc                 L   / n[        5       nU R                  5       n U R                  5        Hs  n[        R	                  U5       HW  u  pEnX5U nUS   n[        U[        5      (       d  M&  Xr;  d  M-  X:w  d  M4  UR                  Xx45        UR                  U5        MY     Mu     U$ )z
Detect if the VBA code contains strings obfuscated with VBA expressions
using keywords such as Chr, Asc, Val, StrReverse, etc.

:param vba_code: str, VBA source code
:return: list of str tuples (encoded string, decoded string)
r   )	r  
expandtabsr  vba_expr_str
scanStringr@   rN  r  r  )	r  r  r  vba_liner  rD   rE   encodedr$  s	            r.   detect_vba_stringsrM  K	  s     GEE ""$H'')"."9"9("CF3S)GQiG'#677 'G,>NNG#56IIg& #D *$ Nr0   c                    U c   U $ [        U [        [        [        45      (       a   U $ [        U [        5      (       a  [
        (       a  U R                  X5      R                  X5      nX0:w  a\  [        R                  SR                  U [        U 5      5      5        [        R                  SR                  U[        U5      5      5        U$ U $ [        U [        5      (       aB  [
        (       a7  U R                  X5      n[        R                  SR                  U5      5        U$ [        U [        5      (       aB  [
        (       d7  U R                  X5      n[        R                  SR                  U5      5        U$ [        U [        5      (       a  U  H  n[        X   5      X'   M     U $ [        U [         ["        45      (       a  U  H  n[        U5      nM     U $ [        R                  SR                  [%        U 5      5      5        U $ )z
ensure there is no unicode in json and all strings are safe to decode

works recursively, decodes and re-encodes every string to/from unicode
to ensure there will be no trouble in loading the dumped json output
z#json2ascii: replaced: {0} (len {1})z#json2ascii:     with: {0} (len {1})zjson2ascii: encode unicode: {0}z1unexpected type in json2ascii: {0} -- leave as is)r@   boolr   floatr   rN   rS   rO   rY   r  r:   r  unicoder  dict
json2asciilistr   r   )json_objrU   rM   dencodedjson_obj_bytesjson_obj_strkeyitems           r.   rS  rS  p	  s    P OO 
HtS%0	1	1L OK 
Hc	"	"7x8??QH#		? &3x=9;		? &3x=9;O O	Hg	&	&77!:		3::>JK 	He	$	$WWx8		3::<HI 	Hd	#	#C&x}5HM  O 
HtEl	+	+Dd#D 
 O 			E6$x.)	+Or0   c                    U (       a  U(       a  [        S5      eU b8  [        U [        5      (       d#  [        SR                  [	        U 5      5      5      eU(       a  Un [
        R                  " [        U 5      SSSS9R                  5       nU(       d  gU(       a  [        SUS   -   5        O[        S	US   -   5        US
S  H  n[        SUR                  5       -   5        M!     g)a  line-wise print of json.dumps(json2ascii(..)) with options and indent+1

can use in two ways:
(1) print_json(some_dict)
(2) print_json(key1=value1, key2=value2, ...)

This is compatible with :py:mod:`oletools.common.log_helper`: log messages
can be mixed if arg `use_json` was `True` in
:py:func:`log_helper.enable_logging` provided this function is called
before the first "regular" logging with `_json_is_first=True` (and
non-empty input) but after log_helper.enable_logging.
zOInvalid json argument: want either single dict or key=value parts but got both)Nz^Invalid json argument: want either single dict or key=value parts but got {0} instead of dict)Fr   )check_circularindentensure_asciiz      r   z,     r   )r   r@   rR  r:   r   jsondumpsrS  r  printrstrip)	json_dict_json_is_first
json_partslinesr  s        r.   
print_jsonrg  	  s     Z 9 : 	:

*Y*E*E H &i13 	3 	JJz),Ue55?Z\ 
hq!"hq!"ab	h&' r0   c                   .    \ rS rSrSrS rSS jrS rSrg)	VBA_Scanneri	  z
Class to scan the source code of a VBA module to find obfuscated strings,
suspicious keywords, IOCs, auto-executable macros, etc.
c                     [        U5      U l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l	        SU l
        SU l        SU l        SU l        SU l        SU l        SU l        g)zO
VBA_Scanner constructor

:param vba_code: str, VBA source code to be analyzed
r7   N)r  r  code_hexcode_hex_revcode_rev_hexcode_base64code_dridexcode_vba
strReverser  autoexec_keywordssuspicious_keywordsiocshex_stringsbase64_stringsdridex_stringsvba_strings)re   r  s     r.   ra   VBA_Scanner.__init__	  s     ,H5	!%#' 	""r0   c                 j
   [        U R                  5      U l        SU l        SU R                  R	                  5       ;   a  SU l        U R                   H  u  p4U =R
                  SU-   -  sl        U R                  (       d  M0  U =R                  SUSSS2   -   -  sl        U =R                  S[        [        R                  " USSS2   5      5      -   -  sl        M     [        U R                  5      U l        U R                   H  u  p4U =R                  SU-   -  sl        M     [        U R                  5      U l        U R                   H  u  p4U =R                   SU-   -  sl        M     U(       a  [#        U R                  5      U l        O/ U l        U R$                   H  u  p4U =R&                  SU-   -  sl        M     / n/ U l        / U l        / U l        U R                  S4U R
                  S4U R                  S4U R                  S	4U R                  S
4U R                   S4U R&                  S44 H_  u  pgU =R(                  [/        Xg5      -  sl        U =R*                  [1        Xg5      -  sl        U =R,                  [3        Xg5      -  sl        Ma     U R                  (       a  U R*                  R5                  S5        U R                  (       a  U R*                  R5                  S5        U R                  (       a  U R*                  R5                  S5        U R$                  (       a  U R*                  R5                  S5        [7        5       nU R(                   H0  u  pX;  d  M  UR5                  SX45        UR9                  U	5        M2     [7        5       nU R*                   H0  u  pX;  d  M  UR5                  SX45        UR9                  U	5        M2     [7        5       nU R,                   H0  u  pX;  d  M  UR5                  SX45        UR9                  U5        M2     U R                   H1  u  p4U(       d  [;        U5      (       d  M  UR5                  SXC45        M3     U R                   H1  u  p4U(       d  [;        U5      (       d  M  UR5                  SXC45        M3     U R                   H1  u  p4U(       d  [;        U5      (       d  M  UR5                  SXC45        M3     U R$                   H1  u  p4U(       d  [;        U5      (       d  M  UR5                  SXC45        M3     XPl        U$ )a  
Analyze the provided VBA code to detect suspicious keywords,
auto-executable macros, IOC patterns, obfuscation patterns
such as hex-encoded strings.

:param include_decoded_strings: bool, if True, all encoded strings will be included with their decoded content.
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)
:return: list of tuples (type, keyword, description)
(type = 'AutoExec', 'Suspicious', 'IOC', 'Hex String', 'Base64 String' or 'Dridex String')
F
strreverseTr  Nrt  HexzHex+StrReversezStrReverse+HexBase64DridexzVBA expression)zHex Stringsz`Hex-encoded strings were detected, may be used to obfuscate strings (option --decode to see all))zBase64 StringszcBase64-encoded strings were detected, may be used to obfuscate strings (option --decode to see all))zDridex StringszcDridex-encoded strings were detected, may be used to obfuscate strings (option --decode to see all))zVBA obfuscated StringszcVBA string expressions were detected, may be used to obfuscate strings (option --decode to see all)r   
SuspiciousIOCz
Hex StringzBase64 StringzDridex string
VBA string)r%  r  ru  rq  r$  rk  rl  rm  rV   r{  r#  r.  rv  rn  rF  rw  ro  rM  rx  rp  rr  rs  rt  r  r  r   r  r  r  r  r  )re   include_decoded_stringsdeobfuscaterL  r$  r  r  r
  keyword_setr  r  r  r   s                r.   scanVBA_Scanner.scan	  s^    .dii8499??,,do $ 0 0GMMTG^+M!!TGDbDM%99!!!TIh6H6HQUSUQU6W,X%XX! !1 4DII> $ 3 3Gw. !4 4DII> $ 3 3Gw. !4 1$))<D!D $ 0 0GMMTG^+M !1!##% 	 D!&""$45""$45!!8,!!8, 01"
D ""od&HH"$$(9$(LL$II;;I"
 $$++ -Q R$$++ -T U$$++ -T U$$++ -T U e$($:$: G)
GAB( %; e$($<$< G)gCD( %= e#'99L'u;<& $- !% 0 0G&,w*?*?g?@ !1 !% 3 3G&,w*?*?BC !4 !% 3 3G&,w*?*?BC !4 !% 0 0G&,w*?*?g?@ !1 r0   c           	      X   U R                   c  U R                  5         [        U R                  5      [        U R                  5      [        U R
                  5      [        U R                  5      [        U R                  5      [        U R                  5      [        U R                  5      4$ )a  
Analyze the provided VBA code to detect suspicious keywords,
auto-executable macros, IOC patterns, obfuscation patterns
such as hex-encoded strings.

:return: tuple with the number of items found for each category:
    (autoexec, suspicious, IOCs, hex, base64, dridex, vba)
)
r  r  r  rr  rs  rt  ru  rv  rw  rx  re   s    r.   scan_summaryVBA_Scanner.scan_summaryR
  s~     <<IIKD**+S1I1I-JDIID$4$4 5s4;N;N7OD''(#d.>.>*?A 	Ar0   )rr  rv  r  rn  ro  rk  rl  rm  rp  rw  ru  rt  r  rq  rs  rx  NFF)	rj   rk   rl   rm   rn   ra   r  r  ro   r,   r0   r.   ri  ri  	  s    
 4hTAr0   ri  c                 6    [        U 5      R                  X5      $ )aN  
Analyze the provided VBA code to detect suspicious keywords,
auto-executable macros, IOC patterns, obfuscation patterns
such as hex-encoded strings.
(shortcut for VBA_Scanner(vba_code).scan())

:param vba_code: str, VBA source code to be analyzed
:param include_decoded_strings: bool, if True all encoded strings will be included with their decoded content.
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)
:return: list of tuples (type, keyword, description)
    with type = 'AutoExec', 'Suspicious', 'IOC', 'Hex String', 'Base64 String' or 'Dridex String'
)ri  r  )r  r  r  s      r.   scan_vbar  c
  s     x %%&=KKr0   c                       \ rS rSrSrSSS\S4S jrS rS rS	 r	S
 r
S rS rS rS rS%S jrS rS rS rS rS rS rS rS%S jrS rS rS rS rS&S jrS rS rS rS  r S! r!S" r"S# r#S$r$g)'
VBA_Parseriu
  zR
Class to parse MS Office files, to detect VBA macros and extract VBA source code
NTFc                    Uc
  UnSU l         O[        U5      nSU l         SU l        / U l        Xl        X0l        X@l        SU l        SU l        SU l	        SU l
        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        SU l        XPl        / U l        SU l        X`l        SU l        SU l        SU l        SU l        SU l        [@        RB                  " U R                  US9U l"        [F        RI                  SU RD                  RJ                  RL                  < SU RD                  R
                  < 35        [N        RP                  " U5      (       a!  U RS                  U5        U RU                  5         U R                  c,  [V        RX                  " U5      (       a  U R[                  U5        U R                  GcZ  Uc%  []        US5       nUR_                  5       nSSS5        S	U;   a  U Ra                  U5        S
U;   a  U Rc                  U5        URe                  5       n	U R                  cS  SU	;   aM  SU	;   aG  SU	;   aA  [g        U	Ri                  S5      U	Ri                  S5      -
  5      S:  a  U Rk                  U5        [l        Rn                  " USS9(       a/  SU R                  -  n
[F        Rq                  U
5        [s        U
5      eURu                  S5      (       a  U Rw                  U5        U R                  c  SU;  a  U Ry                  U5        U R                  c/  SU R                  -  n
[F        Rq                  U
5        [s        U
5      eg! , (       d  f       GN~= f)a  
Constructor for VBA_Parser

:param str filename: filename or path of file to parse, or file-like object

:param bytes data: None or bytes str, if None the file will be read from disk (or from the file-like object).
    If data is provided as a bytes string, it will be parsed as the content of the file in memory,
    and not read from disk. Note: files must be read in binary mode, i.e. open(f, 'rb').

:param str container: str, path and filename of container if the file is within
    a zip archive, None otherwise.

:param bool relaxed: if True, treat mal-formed documents and missing streams more like MS office:
    do nothing; if False (default), raise errors in these cases

:param str encoding: encoding for VBA source code and strings.
    Default: UTF-8 bytes strings on Python 2, unicode strings on Python 3 (None)

raises a FileOpenError if all attempts to interpret the data header failed.
NTFr   r  zftguess: file type=z - container=rbs4   http://schemas.microsoft.com/office/word/2003/wordmls3   http://schemas.microsoft.com/office/2006/xmlPackages   mimes   versions	   multipartrF  )treat_str_as_datazL%s is RTF, which cannot contain VBA Macros. Please use rtfobj to analyse it.s   ID    z;%s is not a supported file type, cannot extract VBA Macros.)=file_on_diskr   ole_fileole_subfilesrc   	containerr!  r   vba_projects	vba_formscontains_vba_macroscontains_xlm_macrosvba_code_all_modulesrm  analysis_results	nb_macrosnb_autoexecnb_suspiciousnb_iocsnb_hexstringsnb_base64stringsnb_dridexstringsnb_vbastringsrU   
xlm_macrosno_xlmdisable_pcodepcodedmp_outputvba_stomping_detectedis_encryptedxlm_macrosheet_foundtemplate_injection_foundr&   FileTypeGuesserftgrY   r  ftyper   olefile	isOleFileopen_oleopen_pptzipfile
is_zipfileopen_openxmlrG  r  open_word2003xmlopen_flatopcr$  absr  open_mhtr"   is_rtfr  rs   r  open_slk	open_text)re   rc   r  r  r!  rU   r  _filefile_handledata_lowercaserb   s              r.   ra   VBA_Parser.__init__{
  s   2 <E $D DME %D "	 #' #' $(! $ ! ! *#%)"!$)!(-% **4==tD		DHHNN<O<OQUQYQYQcQcde U##MM%  MMO99!3!3E!:!:e$99 |(D)[&++-D * G$N%%d+EM!!$'!ZZ\N 		!>)n,.N((4~7K7KG7TTUXZZd# }}TT: egkgtgtt#C(( u%%d# yy WD%8t$99ORVR_R__CHHSM$$	 O *)s   2M::
N	c                 P   [         R                  SU R                  -  5         [        R                  " USS9U l        [        U l        g! [        [        [        4 aF  n[         R                  SU R                  < SU< S35        [         R                  SSS	9   SnAgSnAff = f)
z\
Open an OLE file
:param _file: filename or file contents in a file object
:return: nothing
zOpening OLE file %sN)path_encodingzFailed OLE parsing for file r  r>  r  Tr  )rY   r  rc   r  	OleFileIOr  TYPE_OLEr   r  r,  r   r  )re   r  rG   s      r.   r  VBA_Parser.open_ole
  sv     	&67	/#--e4HDM DIJ/ 	/HHdmmSQRIIhI.	/s   %A
 
B%<B  B%c           	      j   [         R                  SU R                  -  5         [        R                  " U5      nUR                  5        H  n[         R                  SR                  U5      5        UR                  U5       nUR                  [        [        R                  5      5      nU[        R                  :X  aS  [         R                  SU-  5        UR                  U5       nUR                  5       nSSS5         U R                  UWS9  SSS5        M     UR#                  5         [$        U l        g! , (       d  f       NG= f! [         am  nU R                  (       a@  [         R                  U< SU< S35        [         R                  SS	S
9   SnASSS5        GM\  [!        U R                  UU5      eSnAff = f! , (       d  f       GM  = f! [         a^  nU R                  (       aG  [         R                  SR                  XpR                  5      5        [         R                  SS	S
9   SnAge SnAf[(        [        R*                  [        R,                  [.        4 aF  n[         R                  SU R                  < SU< S35        [         R                  SS	S
9   SnAgSnAff = f)z`
Open an OpenXML file
:param _file: filename or file contents in a file object
:return: nothing
zOpening ZIP/OpenXML file %szOpenXML subfile {}zOpening OLE file %s within zipNrc   r  z is not a valid OLE file (r>  r  Tr  z4Error {0} caught in Zip/OpenXML parsing for file {1}z$Failed Zip/OpenXML parsing for file r  )rY   r  rc   r  ZipFilenamelistr  r:   rG  r  r  r  MAGICappend_subfiler^   r!  r   closeTYPE_OpenXMLr   RuntimeError
BadZipfileLargeZipFiler  )re   r  zsubfiler  magicole_datarG   s           r.   r  VBA_Parser.open_openxml  s    	.>?E	/&A ::<		.55g>?VVG_ (,,S-?@E-< 		"BW"LMVVG_'2'7'7'9H -	> //x/PO %_ (d GGI$DI -_  3 >#|| #gWZ)[ \ #		(T	 B (Y %_\ '99<'> !>>Q %_f # 	||O &mm46		(T	2g00'2F2FP 	/HH!]]C1 2IIhI.		/s   AG A&G(D:9GE'G :
EG
GAF=GG &F==GG
G		G 
J2"AH;:H;;1J2,<J--J2c                    [         R                  SU R                  -  5         [        R                  " U5      nUR                  [        5       H~  nUR                  [        S5      n[        R                  " UR                  5      n[        U5      (       a   [        U5      nU R                  XFS9  Mf  [         R                  S	U-  5        M     [(        U l        g! [         aj  nU R                   (       a>  [         R                  SR#                  XG5      5        [         R%                  SSS9   SnAM  ['        U R                  XG5      eSnAff = f! [         aX  nU R                   (       aA  [         R                  S
U R                  < SU< S35        [         R%                  SSS9   SnAge SnAf[,         aF  n[         R                  S
U R                  < SU< S35        [         R%                  SSS9   SnAgSnAff = f)z\
Open a Word 2003 XML file
:param data: file contents in a string or bytes
:return: nothing
zOpening Word 2003 XML file %sz
noname.msor  Error parsing subfile {0}: {1}r  Tr  Nz%s is not a valid MSO fileFailed XML parsing for file r  r>  )rY   r  rc   ET
fromstringiterTAG_BINDATAr#  	ATTR_NAMEr{  r  textr  r  r  r^   r!  r:   r  r   TYPE_Word2003_XMLr   r%  )re   r  etbindatafnamemso_datar  rG   s           r.   r  VBA_Parser.open_word2003xmlm  sw    	04==@A(	/ t$B77;/  I|<#..w||<x((	P#3H#=++U+J HH9EAB+ 0. *DI / P<<HH%E&,fU&8:IIhI>"4T]]E"OOP # 	||$--QTUV		(T	2 	/ HHdmmSQRIIhI.	/s\   A4E C3)E 
E'A	E0E 6EEE 
HAF10F11H><G??Hc           	          [         R                  SU R                  -  5         [        R                  " U5      nUR                  [        5       H  nUR                  [        S5      nUR                  [        S5      nU[        :X  d  M;  UR                  [        5       H3  n [        R                  " UR                  5      nU R!                  XGS9  M5     M     [,        U l        g! ["         aj  nU R$                  (       a>  [         R                  SR'                  XH5      5        [         R)                  SSS9   SnAM  [+        U R                  XH5      eSnAff = f! ["         aX  nU R$                  (       aA  [         R                  S	U R                  < S
U< S35        [         R)                  SSS9   SnAge SnAf[0         aF  n[         R                  S	U R                  < S
U< S35        [         R)                  SSS9   SnAgSnAff = f)z{
Open a Word or PowerPoint 2007+ XML file, aka "Flat OPC"
:param data: file contents in a string or bytes
:return: nothing
z,Opening Flat OPC Word/PowerPoint XML file %sunknownr  r  r  Tr  Nr  r  r>  )rY   r  rc   r  r  r  TAG_PKGPARTr#  ATTR_PKG_NAMEATTR_PKG_CONTENTTYPECTYPE_VBAPROJECTiterfindTAG_PKGBINDATAr{  r  r  r  r^   r!  r:   r  r   TYPE_FlatOPC_XMLr   r%  )	re   r  r  pkgpartr  content_typer  r  rG   s	            r.   r  VBA_Parser.open_flatopc  s~    	?$--OP"	/ t$B 77;/M9=&{{+?K#33#*#3#3N#C	T'/':':7<<'HH ///N $D	 0  )DI  3 T#|| #)I*0&*<!> #		(T	 B&8&S ST # 	||$--QTUV		(T	2 	/ HHdmmSQRIIhI.	/sb   A"E 
E #/C&E &
E0A	E9E ?EEE 
H'AF:9F::H<HHc                 >   [         R                  SU R                  -  5         UR                  S5      nUR	                  S5      nUR	                  S5      nSUs=:  a  U::  a  O  OX#S nO
US:  a  X$S n[
        R                  R                  n[        R                  " S5      nU[
        R                  l         [        (       a  [
        R                  " U5      nO[
        R                  " U5      nU[
        R                  l        UR                  5        H  nUR                  5       n	UR                  S5      n
[         R!                  SU
< S	U	< 35        UR#                  S
S9n[%        U[&        5      (       aB  [)        U5      (       a2  [         R!                  S5         [+        U5      nU R-                  XS9  M  [         R!                  S[5        U5      -  5         [         R!                  SUSS -  5        M     [8        U l        g! U[
        R                  l        f = f! [.         ad  nU R0                  (       a8  [         R                  U
< SU< S35        [         R!                  SS
S9   SnAGMa  [3        U R                  X5      eSnAff = f! [6         a!  n[         R!                  S5         SnAGM  SnAff = f! [.         a    e [:         aB    [         R                  SU R                  < S[<        < 35        [         R!                  SS
S9   gf = f)zT
Open a MHTML file
:param data: file contents in a string or bytes
:return: nothing
zOpening MHTML file %ss   
	 s   MIMEs   Contentrt  Nz)^(From |[\041-\071\073-\176]{1,}:?|[\t ])zMHTML part: filename=z, content-type=T)rS   z4Found ActiveMime header, decompressing MSO containerr  z$ does not contain a valid OLE file (r>  r  r  ztype(part_data) = %szpart_data[0:20] = %rr   rF  zpart_data has no __getitem__zFailed MIME parsing for file rK  )rY   r  rc   lstripfindemail
feedparserheaderREr  compilerN   message_from_stringmessage_from_byteswalkget_content_typeget_filenamer  get_payloadr@   r  r  r  r  r^   r!  r   r   r,  
TYPE_MHTMLr%  MSG_OLEVBA_ISSUES)re   r  stripped_datamime_offsetcontent_offsetoldHeaderREloosyHeaderREmhtmlr   r  r  	part_datar  rG   errs                  r.   r  VBA_Parser.open_mht  s    	(4==89G	/ !KK
3M (,,W5K*//
;NK1>1 -l ;  "$ -o >  **33KJJ'STM(5E%87!55mDE "44]CE,7  )

#446))$/		|\] ,,D,9	 i//K	4J4JIITUP#3I#> ++U+J II4tIFGB		"89Qr?"JK= %D #DII -8  )* / P<<HH).&5 6IIhI>> #5T]]E"OOP % B		"@AAB # 	 	/HH!]],=? @IIhI.	/s   BK <8H 4B/K $H'>#K "J=K H$$K '
J1AJ3K :JJK 
K"J>7K >KK ALLc                    [         R                  S5         [        R                  " U R                  SS9nUR                  5        H  nU R                  SUSS9  M     [         R                  S5        U R                  R                  5         SU l        [        U l	        g! [        R                  [        4 aL  nU R                  S:X  a  [         R                  S5         SnAg[         R                  S	U-  5         SnAgSnAff = f)
a  try to interpret self.ole_file as PowerPoint 97-2003 using PptParser

Although self.ole_file is a valid olefile.OleFileIO, we set
self.ole_file = None in here and instead set self.ole_subfiles to the
VBA ole streams found within the main ole file. That makes most of the
code below treat this like an OpenXML file and only look at the
ole_subfiles (except find_vba_* which needs to explicitly check for
self.type)
zCheck whether OLE file is PPTT)	fast_failN	PptParser)r  zFile is PPTzPPT subfile is not a PPT filez&File appears not to be a ppt file (%s))rY   r  r    r  r  iter_vba_datar  r  TYPE_PPTr   PptUnexpectedDatar   r  r  )re   pptvba_datarG   s       r.   r  VBA_Parser.open_ppt  s     	01	J&&t}}EC--/##D(k#J 0HH]#MM! DM DI,,j9 	J~~,		9::		BSHII	Js   BB   D:%D$DDc           
         [         R                  SU R                  -  5        Sn/ nUR                  S5        UR	                  S5       GH[  nUR                  S5      (       aI  UR                  S5       H2  nUR                  S5      (       d  M  Sn[         R                  S5        M4     Mc  UR                  S	5      (       ao  U(       ah  UR                  S5       HQ  nUR                  S
5      (       d  M  UR                  5       S	:w  d  M1  UR                  S[        USS 5      -  5        MS     M  UR                  S5      (       d  GM  U(       d  GM  UR                  S5       H;  nUR                  S5      (       d  M  UR                  S[        USS 5      -  5        M=     GM^     U(       a  SU l
        X0l        [        U l        g)zu
Open a SLK file, which may contain XLM/Excel 4 macros
:param data: file contents in a bytes string
:return: nothing
zOpening SLK file %sFz8Formulas and XLM/Excel 4 macros extracted from SLK file:   O   ;   ETzSLK parser: found macro sheets   NN   NzNamed cell: %sr   N   CzFormula or Macro: %s)rY   r  rc   r  r  r  r  r  rr  rV   r  r  TYPE_SLKr   )re   r  xlm_macro_foundr  r  r  s         r.   r  VBA_Parser.open_slk5  sY    	&67
TUOOE*Dt$$D)A||D))*.		"AB * ''OD)A||D))aggi5.@"))*:Yqu=M*MN * &&??D)A||D))"))*@9QqrUCS*ST * +" '+D$(O	r0   c                     [         R                  SU R                  -  5        [        U5      U l        SU l        [        U l        g)zz
Open a text file containing VBA or VBScript source code
:param data: file contents in a string or bytes
:return: nothing
zOpening text file %sTN)rY   r  rc   rV   r  r  	TYPE_TEXTr   )re   r  s     r.   r  VBA_Parser.open_textW  s7     	'$--78 %.dO!#' 	r0   c                     U R                   R                  [        XUU R                  U R                  U R
                  S95        g)zB
Create sub-parser for given subfile/data and append to subfiles.
)r!  rU   r  N)r  r  r  r!  rU   r  )re   rc   r  r  s       r.   r  VBA_Parser.append_subfilef  s<     	  HI48LL59]]:>:L:L"N 	Or0   c                    [         R                  S5        U R                  c  U R                  [        :w  a  gU R
                  b  U R
                  $ U R                  [        :X  ad  [         R                  S5        / U l        U R                   H,  nU R
                  R                  UR                  5       5        M.     U R
                  $ S n/ U l        U R                  nUR                  SSS9 H  n[         R                  SU-  5        US	   R                  5       S
:X  d  M4  [         R                  SSR                  U5      -  5        SR                  USS	 5      nUS:w  a  US-  n[         R                  SU-  5        U" X5S5      nU(       d  M  U" X5S5      nU(       d  M  U" X5S5      nU(       d  M  [         R                  SU-  5        U R
                  R                  XVU45        M     U R
                  $ )a  
Finds all the VBA projects stored in an OLE file.

Return None if the file is not OLE but OpenXML.
Return a list of tuples (vba_root, project_path, dir_path) for each VBA project.
vba_root is the path of the root OLE storage containing the VBA project,
including a trailing slash unless it is the root of the OLE file.
project_path is the path of the OLE stream named "PROJECT" within the VBA project.
dir_path is the path of the OLE stream named "VBA/dir" within the VBA project.

If this function returns an empty list for one of the supported formats
(i.e. Word, Excel, Powerpoint), then the file does not contain VBA macros.

:return: None if OpenXML file, list of tuples (vba_root, project_path, dir_path)
for each VBA project found if OLE file
zVBA_Parser.find_vba_projectsN,Returned info is not complete for PPT types!c                     X-   nU R                  U5      (       aB  U R                  U5      [        R                  :X  a  [        R                  SU< SU< 35        U$ [        R                  SU-  5        g)NzFound z	 stream: z<Missing %s stream, this is not a valid VBA project structureF)existsget_typer  STGTY_STREAMrY   r  )r  r  r   	full_paths       r.   check_vba_stream6VBA_Parser.find_vba_projects.<locals>.check_vba_stream  s\     .Izz)$$i)@GDXDX)X		;	JK  		X[ffgr0   FTstreamsstoragesChecking storage %rrt  VBAzFound VBA storage: %sr   r7   zChecking vba_root="%s"PROJECTzVBA/_VBA_PROJECTzVBA/dirzVBA root storage: "%s")rY   r  r  r   r  r  r  r  r  find_vba_projectslistdirupperrB   r  )	re   r  r)  r  storager  rk  vba_project_pathrl  s	            r.   r1  VBA_Parser.find_vba_projectso  s   " 			01 == TYY(%: ($$$
 99  KKFG "D,,!!(()B)B)DE -$$$ 	 mm{{54{@GII+g56r{  "e+		1SXXg5FGH88GCRL1 r>OH		2X=>  0yI#X#3CCU#V '+C9E		2X=>!!(((()KL1 A2    r0   c                 ~    U R                  5       nSnU R                  (       d  U R                  5       nU=(       d    U$ )a  
Detect the potential presence of VBA or Excel4/XLM macros in the file,
by calling detect_vba_macros and detect_xlm_macros.
(if the no_xlm option is set, XLM macros are not checked)

:return: bool, True if at least one VBA project has been found, False otherwise
F)detect_vba_macrosr  detect_xlm_macros)re   r  xlms      r.   detect_macrosVBA_Parser.detect_macros  s6     $$&{{((*C
sr0   c                    [         R                  S5        U R                  b  U R                  $ U R                  cn  U R                   HV  n[         R                  SR                  U5      5        U R                  Ul        UR                  5       (       d  MO  SU l          g   SU l        gU R                  5       n[        U5      S:X  a  SU l        OSU l        U R                  n[        [        UR                  5      5       GHm  n[         R                  SU-  5        UR                  U   nUc&  UR                  U5      n[         R                  S5        UR                  [        R                  :X  d  Mt  [         R                  S	UR                   UR"                  4-  5         UR%                  UR&                  UR"                  5      R)                  5       n[         R                  S
[        U5      -  5        [        U5      S:  a#  [         R                  USS < SUSS < 35        O[         R                  [+        U5      5        SU;   a  [         R                  S5        SU l        GMm  GMp     U R                  $ ! [,         at  nU R.                  (       a=  [         R1                  SUR                   -  5        [         R                  SSS9   SnAGM  [3        U R4                  UR                   U5      eSnAff = f)ay  
Detect the potential presence of VBA macros in the file, by checking
if it contains VBA projects. Both OLE and OpenXML files are supported.

Important: for now, results are accurate only for Word, Excel and PowerPoint

Note: this method does NOT attempt to check the actual presence or validity
of VBA macro source code, so there might be false positives.
It may also detect VBA macros in files embedded within the main file,
for example an Excel workbook with macros embedded into a Word
document without macros may be detected, without distinction.

:return: bool, True if at least one VBA project has been found, False otherwise
zdetect vba macrosNzole subfile {}TFr   Checking DirEntry #%d$This DirEntry is an orphan or unusedz,Reading data from stream %r - size: %d byteszRead %d bytes   d   z...[much more data]...is	   Attribut zFound VBA compressed codez Error when reading OLE Stream %rr  )	exc_trace)rY   r  r  r  r  r:   r  r8  r1  r  r  
direntries_load_direntry
entry_typer  r'  r   r)  _open
isectStartr  reprr  r!  r  r   rc   )re   ole_subfiler  r  siddr  rG   s           r.   r8  VBA_Parser.detect_vba_macros  sU    			%& ##/+++== #00		*11+>?%)[["0022/3D,  1 (-D$--/|!',D$'+D$ mm#cnn-.CII-34s#Ay&&s+		@A||w333		HAFFTUTZTZK[[\M99Q\\166:??ADIIoD	9:4y3		$t*dSVSWj"YZ		$t*-&$.		"=>370 /% /6 '''  M||!Caff!LM		(d	;;0LLMs    %CJ  
K>
AK9!K99K>c                    [         R                  S5        U R                  b  U R                  $ U R                  [        :X  a  U R                  $ / U l        U R                  R                  5       (       d  SU l        g[        (       a8  U R                  (       d  [         R                  S5        O U R                  5       $ U R                  c  gU R                  5       $ ! [         a    [         R                  S5         N?f = f)a  
Detect the potential presence of Excel 4/XLM macros in the file, by checking
if it contains a macro worksheet. Both OLE and OpenXML files are supported.
Only Excel files may contain XLM macros, and also SLK and CSV files.

If XLMMacroDeobfuscator is available, it will be used. Otherwise plugin_biff
is used as fallback (plugin_biff only supports OLE files, not XLSX or XLSB)

:return: bool, True if at least one macro worksheet has been found, False otherwise
zdetect xlm macrosFzcXLMMacroDeobfuscator only works with files on disk, not in memory. Analysis might be less complete.z'Error when running XLMMacroDeobfuscator)rY   r  r  r   r  r  r  is_excelXLMDEOBFUSCATORr  r  _extract_xlm_xlmdeobfr%  r  r  _extract_xlm_plugin_biffr  s    r.   r9  VBA_Parser.detect_xlm_macros!  s     			%&##/+++99 +++xx  ""',D$? $$  B  CI5577 == ,,.. ! IIIGHIs   0C D ?D c           	         [         R                  S5        S[        l        S/n[        R                  " U R
                  SSSSSS9n[        U5      S:X  a  SU l        gX-  nUR                  S5        UR                  S	5        [        R                  " U R
                  SSSSS
9nX-  n[         R                  U5        Xl	        SU l        g)z
Run XLMMacroDeobfuscator to detect and extract XLM macros
:return: bool, True if at least one macro worksheet has been found, False otherwise
z=Calling XLMMacroDeobfuscator to detect and extract XLM macrosTzRAW EXCEL4/XLM MACRO FORMULAS:r  )filenoninteractivenoindentreturn_deobfuscatedtimeoutextract_onlyr   FzL- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - z3EMULATION - DEOBFUSCATED EXCEL4/XLM MACRO FORMULAS:)rT  rU  rV  rW  rX  )
rY   r  xlmdeobfuscatorSILENTprocess_filerc   r  r  r  r  )re   r:  r4  s      r.   rP   VBA_Parser._extract_xlm_xlmdeobfI  s    
 			QR!%/0 --4==:>48?C358<- v;!',D$

9

HI --4==:>48?C35- 			##' r0   c                 d   [         R                  S5        S GHh  nU R                  R                  U5      (       d  M&  [         R                  SU-  5        U R                  R	                  U5      R                  5       n[         R                  S5         [        U/USS9nUR                  5       U l        SSR                  U R                  5      ;   a  [         R                  S	5        [        U/US
S9nU =R                  UR                  5       -  sl        [        U/USS9nU =R                  UR                  5       -  sl        [        U/USS9nU =R                  UR                  5       -  sl        SU l
          gGMk     SU l
        g!   [         R                  S[        -  5         GM  = f)z
Run plugin_biff to detect and extract XLM macros
:return: bool, True if at least one macro worksheet has been found, False otherwise
rQ  )WorkbookBookzFound Excel stream %rz Running BIFF plugin from oledumpz-o BOUNDSHEET)r   streamoptionszExcel 4.0 macro sheetr  zFound XLM macrosz-o LABEL -r LNz-c -r LNz-o DCONN -sTz;Error when running oledump.plugin_biff, please report to %sF)rY   r  r  r%  r  r  r   Analyzer  rB   r  rj  URL_OLEVBA_ISSUES)re   excel_streamr  biff_plugins       r.   rQ  #VBA_Parser._extract_xlm_plugin_biffp  sm   
 			,-0L}}##L11		1L@A}}//=BBD		<=u #(l^DRa"bK&1&9&9&;DO.$))DOO2LL		"45&+,Vf&g;+>+>+@@&+,V`&a;+>+>+@@ ',,Vc&d;+>+>+@@370# M 14 $) uMM"_bs"stts   C)FF/c                     U R                   (       a%  [        R                  " U R                   5      U l        U R                  $ r+   )r  r#   r  r  s    r.   detect_is_encryptedVBA_Parser.detect_is_encrypted  s,    == & 3 3DMM BD   r0   c                     S nU R                  5       (       a^  [        R                  nU(       a&  [        U[        5      (       a  UR                  U5        [        R                  " U R                  U5      nU$ r+   )ri  r#   DEFAULT_PASSWORDSr@   rT  r  decryptrc   )re   passwords_listdecrypted_file	passwordss       r.   decrypt_fileVBA_Parser.decrypt_file  sX    ##%%00I*^T"B"B  0#^^DMM9ENr0   c                 T    U R                   c  U$ UR                  U R                   SS9$ )z
Encode a unicode string to bytes or str, using the specified encoding
for the VBA_parser. By default, it will be bytes/UTF-8 on Python 2, and
a normal unicode string on Python 3.
:param str unicode_str: string to be encoded
:return: encoded string
rK   rL   )rU   rO   )re   unicode_strs     r.   encode_stringVBA_Parser.encode_string  s.     == %%dmmI%FFr0   c              #     #    [         R                  S5        U R                  c  U R                  [        :X  a'  U R
                  SU R
                  U R                  4v   gU R                  [        :X  a;  U R                  (       a)  SnU R                   H  nUSU-   S-   -  nM     SSSU4v   ggU R                   H  nUR                  5        H  nUv   M	     M      U R                  (       a)  SnU R                   H  nUSU-   S-   -  nM     SSSU4v   ggU R                  5         [        5       nU R                   Hm  u  pgn [        U R                  XgXR                  5       HA  u  pnUR!                  U R                  R#                  U	5      5        U R
                  XU4v   MC     Mo     U R                  n[)        [+        UR,                  5      5       GH  n[         R                  S	U-  5        X;   a  [         R                  S
5        M8  UR,                  U   nUc&  UR/                  U5      n[         R                  S5        UR0                  [2        R4                  :X  d  M  [         R                  SUR6                  -  5        UR9                  UR:                  UR<                  5      R?                  5       n[@        RB                  " SU[@        RD                  S9 Hx  nURG                  5       S-
  n[         R                  SU-  5        UUS n [I        [K        U5      5      n[M        USS9nU R
                  UR6                  UR6                  U4v   Mz     GM     U R                  (       a(  SnU R                   H  nUSU-   S-   -  nM     SSSU4v   U RO                  5       (       a7  SnU RP                  RS                  5        H  nUSU-   S-   -  nM     SSSU4v   gg! [$         a!  n[         R'                  S5         SnAGM  SnAff = f! [$         aV  n[         R                  SUR6                  < SU R
                  < SU< S35        [         R                  SSS9   SnAGM  SnAff = f7f)a  
Extract and decompress source code for each VBA macro found in the file

Iterator: yields (filename, stream_path, vba_filename, vba_code) for each VBA macro found
If the file is OLE, filename is the path of the file.
If the file is OpenXML, filename is the path of the OLE subfile containing VBA macros
within the zip archive, e.g. word/vbaProject.bin.
If the file is PPT, result is as for OpenXML but filename is useless
zextract_macros:Nr7   z' r  	xlm_macrozxlm_macro.txtzError in _extract_vbar>  zAlready extractedr?  zReading data from stream %rs   \x00Attribut[^e])flagsr3   z%Found VBA compressed code at index %Xcp1252)rU   zError processing stream z	 in file r  r>  
Traceback:Tr  z
VBA P-codezVBA_P-code.txt)*rY   r  r  r   r  rc   r  r  r  r  extract_macrosr1  r  r  r  r!  r  _findr%  rj  r  r  rC  rD  rE  r  r'  r   rF  rG  r)  r  r  r  
IGNORECASErD   r  r  rV   detect_vba_stompingr  r  )re   r  r  rI  r  vba_stream_idsr  rk  rl  r   vba_filenamer   r  rJ  rK  r  r  rD   compressed_codevba_code_bytesvba_code_strrG   s                         r.   r|  VBA_Parser.extract_macros  s     			#$== yyI%}}b$--9R9RSSh&??!H $ D4K$$66 !0&_hOO	 # $(#4#4K#.#=#=#?% $@ $5 ??!H $ D4K$$66 !0&_hOO	 # ""$ UN484E4E0
;()1<<A <8 '**4==+>+>{+KL#}}kRR	A 5F  --Cc#..12		1C78(II12NN3'9**3/AIIDE<<7#7#77II;affDE99Q\\166:??AD!#-A4r}}!] % 1		"IE"QR*.uv,C->y?Y-ZN ,5^h+WL#'==!&&!&&,"OO "^ 3F  OODtd 22H ,"K(KK '')) 00;;=Dtd 22H >#\3CXNN	 *a ! ;MM"9::;F  ) CIIVWV\V\^b^k^kmp&qrIIlTIBBCsf   EQ;A&O*+B:Q;)B-Q;APBQ;*
P4P	Q;PQ;
Q8"A
Q3,Q;3Q88Q;c                     U R                   c>  / U l         U R                  5        H#  u  pp4U R                   R                  XX445        M%     [        U R                   5      U l        U R                   $ )a6  
Extract and decompress source code for each VBA macro found in the file
by calling extract_macros(), store the results as a list of tuples
(filename, stream_path, vba_filename, vba_code) in self.modules.
See extract_macros for details.
:returns: list of tuples (filename, stream_path, vba_filename, vba_code)
)rm  r|  r  r  r  )re   r   r   r  r  s        r.   extract_all_macrosVBA_Parser.extract_all_macros  s`     <<DLFJFYFYF[B<##[|$VW G\T\\*||r0   c                     SnU R                  5        H:  u      p#[        U[        5      (       d  [        R	                  S5        M3  XS-   -  nM<     U$ )a  
Extract the VBA macro source code from all modules, and return it
as a single string (str) with all modules concatenated.
If an exception is triggered when decompressing a VBA module, it
will not be included. The error is logged but the exception is not
raised further.
:return: str
r7   z7VBA code returned by extract_all_macros is not a stringr  )r  r@   r   rY   r  )re   r  rL  r  s       r.   get_vba_code_all_modules#VBA_Parser.get_vba_code_all_modules(  sS      "#'#:#:#<Q1h,,		ST$47$	 $=
 $#r0   c                     U R                  5       (       Gam  U R                  b  U R                  $ U R                  cG  U R                  5       U l        U R	                  5        H  u    p4U =R                  US-   -  sl        M      [        U R                  5      nUR                  X5      U l        U R                  5       (       aR  [        R                  S5        SnSnUR                  R                  Xg45        UR                  R                  SXg45        U R                  (       aR  [        R                  S5        SnSnUR                  R                  Xg45        UR                  R                  SXg45        U R                  (       aR  [        R                  S	5        S
nSnUR                  R                  Xg45        UR                  R                  SXg45        UR                  5       u  pppnU =R                   U-  sl        U =R"                  U	-  sl        U =R$                  U
-  sl        U =R&                  U-  sl        U =R(                  U-  sl        U =R*                  U-  sl        U =R,                  U-  sl        U R                  $ )a[  
runs extract_macros and analyze the source code of all VBA+XLM macros
found in the file.
All results are stored in self.analysis_results.
If called more than once, simply returns the previous results.

:return: list of tuples (type, keyword, description)
(type = 'AutoExec', 'Suspicious', 'IOC', 'Hex String', 'Base64 String' or 'Dridex String')
r  z*adding VBA stomping to suspicious keywordszVBA StompingzwVBA Stomping was detected: the VBA source code and P-code are different, this may have been used to hide malicious coder  z2adding XLM macrosheet found to suspicious keywordsz	XLM macroz.XLM macro found. It may contain malicious codez0adding Template Injection to suspicious keywordszTemplate Injectionz^Template injection found. A malicious template could have been uploaded from a remote location)r;  r  r  r  extract_form_stringsri  r  r  rY   r  rs  r  r  r  r  r  r  r  r  r  r  r  r  )re   show_decoded_stringsr  rL  form_stringscannerr  r  autoexec
suspiciousrt  
hexstringsbase64stringsdridex
vbastringss                  r.   analyze_macrosVBA_Parser.analyze_macros:  s'    $$0,,,((0,0,I,I,K)+/+D+D+F'Q--t1CC- ,G "$";";<G$+LL1E$SD!''))		FG(E++22G3IJ&&g'KL''		NO%N++22G3IJ&&g'KL,,		LM.-++22G3IJ&&g'KLX_XlXlXnUH$M:(*,LLD L*,!!]2!!!V+!*,$$$r0   c                 V   U R                  SS9n[        US SS9n[        U R                  5      n[	        U5      nU Hg  u  p4nUS:X  d  M  UR                  SS5      nS	U-  nUR                  S
5      (       a  UR                  S5      (       a  SU-  nUR                  XT5      nMi     U$ )NF)r  c                     [        U S   5      $ )Nr(   )r  )type_decoded_encodeds    r.   rV  #VBA_Parser.reveal.<locals>.<lambda>w  s    SI]^_I`Ear0   T)rY  reverser  rA  r^  z"%s"re  r>  z(%s))r  sortedr  r  r  rK   r  endswith)re   analysis
deobf_codekw_typer$  rL  s         r.   revealVBA_Parser.revealr  s    &&E&B ((akop -T-F-FG

+
)1%Gg,& "//#t4 7* %%c**w/?/?/D/D$w.G'//A
 *2 r0   c           	      d   [         R                  S5        U R                  c  U R                  [        :w  a  gU R                  [        :X  a"  U R
                  n[         R                  S5        OU R                  /n/ U l        U GH  nUR                  SSS9 GH  n[         R                  SU-  5        US/-   nUS	/-   n[         R                  S
U< SU< S35        UR                  U5      (       d  M^  UR                  U5      [        R                  :X  d  M  UR                  U5      (       d  M  UR                  U5      [        R                  :X  d  M  SR                  U5      n[         R                  SU-  5        U R                  R                  U5        GM     GM      U R                  $ )a  
Finds all the VBA forms stored in an OLE file.

Return None if the file is not OLE but OpenXML.
Return a list of tuples (vba_root, project_path, dir_path) for each VBA project.
vba_root is the path of the root OLE storage containing the VBA project,
including a trailing slash unless it is the root of the OLE file.
project_path is the path of the OLE stream named "PROJECT" within the VBA project.
dir_path is the path of the OLE stream named "VBA/dir" within the VBA project.

If this function returns an empty list for one of the supported formats
(i.e. Word, Excel, Powerpoint), then the file does not contain VBA forms.

:return: None if OpenXML file, list of tuples (vba_root, project_path, dir_path)
for each VBA project found if OLE file
zVBA_Parser.find_vba_formsNr#  FTr+  r.  rX  fzChecking if streams z and z existr   zFound VBA Form: %r)rY   r  r  r   r  r  r  r  r2  r%  r&  r  r'  rB   r  )re   	ole_filesr  r4  o_streamf_stream	form_paths          r.   find_vba_formsVBA_Parser.find_vba_forms  sM   " 			-. == TYY(%:$ 99  ))IKKFG)I  C;;ut;D		/'9:"cU?"cU?		8XVW::h''CLL,BgFZFZ,ZJJx((S\\(-CwG[G[-[ # 1III2Y>?NN))'2 E  ~~r0   c              #     #    U R                   cD  U R                  [        :X  a  gU R                   H  nUR	                  5        H  nUv   M	     M      gU R                  5         U R                   nU R                   H  nUS/-   n[        R                  SSR                  U5      -  5        UR                  U5      R                  5       n[        R                  U5       H  n[        R                  SUR                  5       -  5        [        (       a  UR                  5       nOUR                  5       R!                  SSS9nUS	:w  d  Mk  U R"                  SR                  U5      U4v   M     M     g7f)
a  
Extract printable strings from each VBA Form found in the file

Iterator: yields (filename, stream_path, form_string) for each printable string found in forms
If the file is OLE, filename is the path of the file.
If the file is OpenXML, filename is the path of the OLE subfile containing VBA macros
within the zip archive, e.g. word/vbaProject.bin.
If the file is PPT, result is as for OpenXML but filename is useless
Note: form_string is a raw bytes string on Python 2, a unicode str on Python 3
NrX  zOpening form object stream %rr   z"Printable string found in form: %rr)   rK   rL   Tahoma)r  r   r  r  r  r  r  rY   r  rB   r  r  re_printable_stringr  r  rN   rS   rc   )	re   rI  r  r  form_storager  	form_datam	found_strs	            r.   r  VBA_Parser.extract_form_strings  s)     == yyI% $(#4#4K#.#C#C#E% $F $5
 !--C $'3%/		9CHHX<NNONN8499;	,55i@AIIBQWWYNOw$%GGI	$%GGI$4$4VI$4$N	 H,#}}chhx.@)LL A !/s   EE4)E4c              #     #    U R                   cD  U R                  [        :X  a  g U R                   H  nUR	                  5        H  nUv   M	     M      g U R                  5         U R                   nU R                   H@  n[        R                  " X45       H#  nU R                  SR                  U5      U4v   M%     MB     g 7fr   )r  r   r  r  extract_form_strings_extendedr  r  r!   extract_OleFormVariablesrc   rB   )re   rI  r  r  r  r   s         r.   r  (VBA_Parser.extract_form_strings_extended  s     == yyI% $(#4#4K#.#L#L#N% $O $5
 !--C $ ' @ @ SH==#((<*@(KK !T !/s   B?Cc                 &   U R                   [        [        4;   a  SU l        gU R                  (       a  SU l        gU R                  c  [
        R                  S5         SSKJn  [        5         [        (       a  [        5       nO
[        5       n " S S5      n [
        R                  S	5        [        R                   nU[        l        UR#                  U R$                  XCS
9  U[        l        [
        R                  S5        UR)                  5       U l        U R                  $ ! [         a5  n[
        R                  SR                  U5      5        SU l         SnAgSnAff = f! [         a  n[
        R'                  S5         SnANSnAff = f)ze
Extract and disassemble the VBA P-code, using pcodedmp

:return: VBA P-code disassembly
:rtype: str
r7   Nz:Calling pcodedmp to extract and disassemble the VBA P-coder   )pcodedmpz%Exception when importing pcodedmp: {}c                       \ rS rSrSrSrSrg)&VBA_Parser.extract_pcode.<locals>.argsi7  TFr,   N)rj   rk   rl   rm   
disasmOnlyverbosero   r,   r0   r.   argsr  7  s    !
r0   r  zbefore pcodedmp)output_filezafter pcodedmpzError while running pcodedmp)r   r  r  r  r  rY   r  r  r%  r  r:   r\   rN   r   r   sysstderrprocessFilerc   rj  getvalue)re   r  r   outputr  r  s         r.   extract_pcodeVBA_Parser.extract_pcode  sF    999--#%D #%D 'IIRS- 
 w  "   >		+,#
$$T]]D$M#
		*+ $*??#4D  ###]   @GGJK')$F  > <==	>s1   D% A*E' %
E$/+EE$'
F1FFc                    [         R                  S5        U R                  b  U R                  $ U R                  [        [
        4;   a  SU l        gU R                  (       d  [         R                  S5        SU l        gU R                  Gcd  [         R                  S5        U R                  5         [         R                  S5        [        5       nU R                  R                  5        GHJ  nUR                  S5      (       d  M  [         R                  SUR                  5       -   5        UR                  SS	5      nUS
   nSn[        U5      S:X  a  US	   R                  5       nUS;   aW  UR                  S5      (       a  USS nUR                  SS	5      S
   nUR                  S5      (       d  UR!                  U5        US:X  d  M  UR                  SS	5      S	   n[        U5      S:  a3  US
   S:X  a	  US   S:X  d   eUS	S nUR#                  SS5      nSU-   S-   nUR!                  U5        GMM     [         R                  S[%        ['        U5      5      -   5        SU l        U R)                  5       nU HJ  n	X;  d  M
  [         R                  SR+                  U	5      5        [         R                  S5        SU l          O   U R                  (       d  [         R                  S5        U R                  $ )z
Detect VBA stomping, by comparing the keywords present in the P-code and
in the VBA source code.

:return: True if VBA stomping detected, False otherwise
:rtype: bool
r  NFz<For now, VBA stomping cannot be detected for files in memoryz+Analysing the P-code to detect VBA stompingzpcodedmp OK	zP-code: r   r   r7   r(   )ArgsCallArgsLdStLdMemStLabelz(Call) r   id_LitStrrA  rt  r^  z Keywords extracted from P-code: z"Keyword {!r} not found in VBA codezVBA STOMPING DETECTED!TzNo VBA stomping detected.)rY   r  r  r   r  r  r  r  r  r  r  r  r  rr  r  r  r  rK   rH  r  r  r:   )
re   r  r  r  mnemonicr  r   r  r  r  s
             r.   r  VBA_Parser.detect_vba_stompingP  s    			'(%%1---999--).D&  KKVW).D&%%-IICD IIm$uH,,779??4((IIj4::<78!ZZa0F%ayHD6{a'%ay0  #WW??955#'8D#zz$215  $u55$LL.8+
 !JJtQ/2 q619#$Q492<#; !!BA !		#t 4A #a#A QW :X II84x@P;QQR).D&#'#@#@#B #6IIBII'RSII6715D. $ --		56)))r0   c                     U R                   c2  U R                  b$  U R                   H  nUR                  5         M     ggU R                   R                  5         g)zm
Close all the open files. This method must be called after usage, if
the application is opening many files.
N)r  r  r  )re   rI  s     r.   r  VBA_Parser.close  sM    
 ==   ,#'#4#4K%%' $5 - MM!r0   ) r  r  r  r  r  rU   r  rc   r  r  rm  r  r  r  r  r  r  r  r  r  r  r  r  r!  r  r   r  r  r  r  r  r  r+   r  )%rj   rk   rl   rm   rn   DEFAULT_API_ENCODINGra   r  r  r  r  r  r  r  r  r  r1  r;  r8  r9  rP  rQ  ri  rq  ru  r|  r  r  r  r  r  r  r  r  r  r  ro   r,   r0   r.   r  r  u
  s    
 '+dDSg$M%^/"P/d//b)/VN/`J8DO\!|D(L&/P$N!F!
GfOR $$5%p8AF&MPL&B$HU*n
"r0   r  c                   ~   ^  \ rS rSrSrU 4S jrSS jrSS jrSS jrS r	    SS jr
    SS	 jrSS
 jrSrU =r$ )VBA_Parser_CLIi  zd
VBA parser and analyzer, adding methods for the command line interface
of olevba. (see VBA_Parser)
c                 .   > [         [        U ]
  " U0 UD6  g)ze
Constructor for VBA_Parser_CLI.
Calls __init__ from VBA_Parser with all arguments --> see doc there
N)r`   r  ra   )re   r  rf   rg   s      r.   ra   VBA_Parser_CLI.__init__  s    
 	nd,d=f=r0   c                     [         R                  R                  5       (       a(  [        SSS9  [         R                  R	                  5         U R                  X5        g)a@  
Analyze the provided VBA code, without printing the results (yet)
All results are stored in self.analysis_results.

:param show_decoded_strings: bool, if True hex-encoded strings will be displayed with their decoded content.
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)
:return: None
Analysis...r7   rE   N)r  stdoutisattyra  flushr  )re   r  r  s      r.   run_analysisVBA_Parser_CLI.run_analysis  s@     ::/r*JJ0>r0   c                    U R                   nU(       a  [        R                  " SSS9nSSSS.nU Hc  u  pgn[        U5      (       d  [	        U5      n[        U5      (       d  [	        U5      nUR                  US5      n	UR                  XgU4U	SS4S	9  Me     UR                  5         U R                  (       a  [        S
5        gg[        S5        g)z
print the analysis results in a table

:param show_decoded_strings: bool, if True hex-encoded strings will be displayed with their decoded content.
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)
:return: None
)
   rF  -   )TypeKeywordDescription)column_width
header_rowyellowredcyanr   r  r  N)colorszVBA Stomping detection is experimental: please report any false positive/negative at https://github.com/decalage2/oletools/issuesz#No suspicious keyword or IOC found.)
r  r   TableStreamr  rH  r#  	write_rowr  r  ra  )
re   r  r  r  rU  
COLOR_TYPEr  r  r  
color_types
             r.   print_analysisVBA_Parser_CLI.print_analysis  s     ''''\3UWA %#J
 29-+#G,,"7mG#K00"&{"3K'^^GT:
W{;ZQUW[D\] 29 GGI))  Z  [ * 78r0   c                    [         R                  R                  5       (       a(  [        SSS9  [         R                  R	                  5         U R                  X5       VVVs/ s H  u  p4n[        X4US9PM     snnn$ s  snnnf )aH  
Analyze the provided VBA code, and return the results in json format

:param vba_code: str, VBA source code to be analyzed
:param show_decoded_strings: bool, if True hex-encoded strings will be displayed with their decoded content.
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)

:return: dict
r  r7   r  )r   r  r  )r  r  r  ra  r  r  rR  )re   r  r  r  r  r  s         r.   print_analysis_json"VBA_Parser_CLI.print_analysis_json  sr     ::/r*JJ595H5HI]5km5k1Gk 'L5km 	m ms   !A=c                     U R                   nU(       aL  SSSS.nU H@  u  pEnUR                  US5      nU(       d  M!  UR                  USU< SU< SU< S35      nMB     U$ )	z
Colorize keywords found during the VBA code analysis
:param vba_code: str, VBA code to be colorized
:return: str, VBA code including color tags for Colorclass
r  r  r  r  Nz{auto}z{/)r  r#  rK   )re   r  r  r  r  r  r  r  s           r.   colorize_keywords VBA_Parser_CLI.colorize_keywords  sj     ''$#J
 29-+'^^GT:
:'//jZacm9noH 29 r0   c	           	      v   Xl         U(       a	  U(       d  SnU R                  (       a  U R                  < SU R                  < 3n	OU R                  n	[        S5        [        SU	-  5         [        SU R                  -  5        U R                  5       (       Ga  U R                  XS9  U R                  5        GHC  u  ppU(       a  [        U5      nOUn[        S5        [        SU-  5        [        S	U
< S
[        U5      < 35        U(       d  MZ  [        S5        UR                  5       S:X  a  [        S5        M  SU;   ac  [        R                  S5        [        R                  R                  5       (       a  [         R"                  " S5      nOSnUR%                  SU5      n [        R                  R                  5       (       a%  [         R"                  " U R'                  U5      5      n[        U5        GMF     U R-                  5        H?  u  pnUc  M  [        S5        [        SU
< S
U< 35        [        S5        [        U5        MA      U R/                  5        HR  u  pnUc  M  [        S5        [        SUS   < SU
< S
U< 35        [        S5        [        [1        US   5      5        MT     U(       a1  [        S5        [        S5        U R9                  5       n[        U5        U(       d  U R;                  X5        U(       a$  [        S5        [        U R=                  5       5        O[        S5         [        S5        g! [(         a    [        R+                  S5         GNf = f! [2         a6  n[        R5                  SU-  5        [        R7                  SSS9   SnANSnAff = f! [>         a    e [2         al  n[        R5                  SU R                  < S U< S!35        [@        RB                  " 5         [        R7                  SSS9  [E        U R                  U5      eSnAff = f)"a  
Process a single file

:param filename: str, path and filename of file on disk, or within the container.
:param data: bytes, content of the file if it is in a container, None if it is a file on disk.
:param show_decoded_strings: bool, if True hex-encoded strings will be displayed with their decoded content.
:param display_code: bool, if False VBA source code is not displayed (default True)
:param global_analysis: bool, if True all modules are merged for a single analysis (default),
                        otherwise each module is analyzed separately (old behaviour)
:param hide_attributes: bool, if True the first lines starting with "Attribute VB" are hidden (default)
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)
:param show_pcode bool: if True, call pcodedmp to disassemble P-code and display it
:param no_xlm bool: if True, don't use the BIFF plugin to extract old style XLM macros
Tz in zO===============================================================================zFILE: %szType: %sr  r  zO-------------------------------------------------------------------------------zVBA MACRO %s z	in file: z - OLE stream: zN- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - r7   z(empty macro)r=  z]The VBA code contains special characters such as backspace, that may be used for obfuscation.s   {autored}\x08{/red}z\x08z;Unicode conversion to be fixed before colorizing the outputNzVBA FORM STRING IN zVBA FORM Variable "r   z" IN r   zError parsing form: %sr{  r  zP-CODE disassembly:zAMACRO SOURCE CODE WITH DEOBFUSCATED VBA STRINGS (EXPERIMENTAL):

zNo VBA or XLM macros found.Error processing file r  r>  )#r  r  rc   ra  r   r;  r  r  r  rH  rr  rY   r  r  r  r  
colorclassColorrK   r  UnicodeErrorr  r  r  r   r%  r  r  r  r  r  r^   	traceback	print_excrx   )re   r  display_codehide_attributesvba_code_onlyshow_deobfuscated_coder  
show_pcoder  display_filenamer   r   r  r  vba_code_filtered	backspacer  form_variablesrG   pcodes                       r.   r\  VBA_Parser_CLI.process_file  sl   ( L>>-1]]DNNK#}}hj++,[	6*dii'(!!##!!7K!eJNJaJaJcF[|&,6x,@),4)(O/L89KkIZ[\#|i(,224:!/2  &):: #  -L  !M#&::#4#4#6#60:0@0@AX0YI07I4E4M4MfV_4` 1i $'::#4#4#6#68B8H8HI_I_`qIr8s$5 ""34C KdD @D?X?X?Z;[{".h+Wbcdi(k* @[
;FJFhFhFjB>)5!(O!UcdjUkmx  {F  #G  H!),!#nW&=">? Gk (O/0 ..0E%L %''(<J)_`$++-(34 	b	o $0 i #		*g hi" ! ;HH5;<IIlTI:;< # 	 	6HHsKL!IIlTI2!$--55	6s   ,B#N8 BN8 )AM1'N8 8N8 M5 0AM5 ;A;N8 7N8 M2.N8 1M22N8 5
N5?,N0+N8 0N55N8 8P8A'P33P8c	                 r   Xl         U(       a	  U(       d  Sn0 n	U R                  (       a  U R                  U	S'   OSU	S'   U R                  U	S'   SU	S'   SU	S'   SU	S'   XiS	'   XyS
'    U R                  U	S'   / n
U R	                  5       (       a  U R                  5        HZ  u  pp0 nU(       a  [        U5      nOUnXS'   XS'   XS'   U(       a  UR                  5       US'   OSUS'   U
R                  U5        M\     U(       d  U R                  UU5      U	S'   U(       a  U R                  5       U	S'   U(       a  U R                  5       U	S'   XS'   SU	S'   U	$ ! [         aW  n[        R                  SU R                  < SU< S35        [        R                  SSS9  [!        U R                  U5      eSnAff = f)a  
Process a single file

every "show" or "print" here is to be translated as "add to json"

:param filename: str, path and filename of file on disk, or within the container.
:param data: bytes, content of the file if it is in a container, None if it is a file on disk.
:param show_decoded_strings: bool, if True hex-encoded strings will be displayed with their decoded content.
:param display_code: bool, if False VBA source code is not displayed (default True)
:param global_analysis: bool, if True all modules are merged for a single analysis (default),
                        otherwise each module is analyzed separately (old behaviour)
:param hide_attributes: bool, if True the first lines starting with "Attribute VB" are hidden (default)
:param show_deobfuscated_code: bool, if True add deobfuscated code to result
:param deobfuscate: bool, if True attempt to deobfuscate VBA expressions (slow)
:param show_pcode: bool, if True add extracted pcode to result
Tr  NrT  Fjson_conversion_successfulr  code_deobfuscateddo_deobfuscater	  r   r  r   
ole_streamr  r  macrosr  r  r>  r{  r  )r  r  rc   r   r;  r  r  rr  r  r  r  r  r%  rY   r  r  rx   )re   r  r  r  r  r  r  r	  r  r4  r  r   r   r  r  
curr_macror  rG   s                     r.   process_file_json VBA_Parser_CLI.process_file_json  s   , L>>"&..F;"&F;v/4+,!z&*"##. )|#	6!YYF6NF!!##JNJaJaJcF[|!#J&,6x,@),4)1=~.0;}-/:|,#->-D-D-F
6*-1
6*MM*- Kd  %)-)A)ABVBM*OF:&)26++-F./&*&8&8&:F7O%837F/0   	6HHsKLIIlTI2!$--55		6s   &C-E 
F6AF11F6c           	      n    U R                  5       (       a[  [        R                  R                  5       (       a(  [	        SSS9  [        R                  R                  5         U R                  UUS9  [        U R                     nS=n=n=n=n=n	=n
=pU R                  (       a  SnU R                  (       a  SnU R                  (       a  SnU R                  (       a  S	nU R                  (       a  S
n	U R                  (       a  Sn
U R                  (       a  SnU R                   (       a  SnXE< U< U< U< U	< U
< U< U< 3-  nU<S SU R"                  < 3n[	        U5        g! [$         aB  n[&        R)                  SU R"                  < SU< S3SS9  [+        U R"                  U5      eSnAff = f)zJ
Process a file in triage mode, showing only summary results on one line.
r  r7   r  r  rO  MASIHrb  DV12r  r  r  r>  Tr  N)r;  r  r  r  ra  r  r  TYPE2TAGr   r  r  r  r  r  r  r  r  rc   r%  rY   r  rx   )re   r  r  r  ry  r  r  r  rt  r  	base64obfr  vba_obfr  rG   s                  r.   process_file_triage"VBA_Parser_CLI.process_file_triage  so   
	6!!##::$$&&/r2JJ$$&##9M0; $ =TYY'E`ccFcXc
cTcJccV''#C!!:||CT!!:$$#i$$sf!!S768Zz)2FGE EE "'6D$K 	6IIL#  %!$--55		6s   E%E( (
F42=F//F4)r  r  )FTTFFFFF)FFF)rj   rk   rl   rm   rn   ra   r  r  r  r  r\  r  r%  ro   rp   rq   s   @r.   r  r    sV    
>? 9>m"& 168<AFAFyx 6;=AFKFKL^!6 !6r0   r  c           
         SnSn[         R                  " US9nUR                  SSSS9  UR                  SS	S
SS9  UR                  SSS[        SSS9  UR                  SS[        S/ SS9  UR                  SSS[        SSS9  UR	                  SS9nUR                  SSS S!S"S#S$S%9  UR                  S&S'S S!S(S#S)S%9  UR                  S*S+S S!S,S#S-S%9  UR                  S.S/S0S1S2S3S49  UR                  S5S6S	S7S8S9S49  UR                  S:S	S;S<S9  UR                  S=S0S>S2S?S49  UR                  S@S	SASBS9  UR                  SCSDSESFUSGSH9  UR                  SISJS	S8SKSH9  UR                  SLSMS	S2SNSH9  UR                  SOSPS	S8SQSH9  UR                  SRS	SSST9  UR                  SUSVS	S8SWSH9  UR                  U 5      n[        UR                  5      SX:X  ag  SY[        R                  SXSZ -  n[        S[[        < S\U< S]35        [        [        5        UR                  5         [        R                  " [        5        UR                   (       a"  UR"                  (       a  UR%                  S^5        U$ )_zBparse command line arguments (given ones or per default sys.argv) r  z2usage: olevba [options] <filename> [filename2 ...])usage	filenamesr  zFiles to analyze)nargshelpz-r
store_true	recursivez)find files recursively in subdirectories.)actiondestr+  z-zz--zipzip_passwordNzRif the file is a zip archive, open all files from it, using the provided password.)r/  r   defaultr+  z-pz
--passwordr  z^if encrypted office files are encountered, try decryption with this password. May be repeated.)r   r.  r1  r+  z-fz
--zipfname	zip_fnamezzif the file is a zip archive, file(s) to be opened within the zip. Wildcards * and ? are supported. (default: %(default)s)z Output mode (mutually exclusive))titlez-tz--triagestore_constoutput_modetriageunspecifiedzLtriage mode, display results as a summary table (default for multiple files))r.  r/  constr1  r+  z-dz
--detaileddetailedz=detailed mode, display full results (default for single file)z-jz--jsonr_  z2json mode, detailed in json format (never default)z-az
--analysisstore_falser  Tz8display only analysis results, not the macro source code)r.  r/  r1  r+  z-cz--coder  Fz/display only VBA source code, do not analyze itz--decoder  zedisplay all the obfuscated strings with their decoded content (Hex, Base64, StrReverse, Dridex, VBA).z--attrr  z?display the attribute lines at the beginning of VBA source codez--revealr  zbdisplay the macro source code after replacing all the obfuscated strings by their decoded content.z-lz
--loglevelloglevelstorezElogging level debug/info/warning/error/critical (default=%(default)s))r/  r.  r1  r+  z--deobfr  z-Attempt to deobfuscate VBA expressions (slow)z	--relaxedr!  zeDo not raise errors if opening of substream fails (this option is now deprecated, enabled by default)z--show-pcoder	  z)Show disassembled P-code (using pcodedmp)z
--no-pcodez(Disable extraction and analysis of pcode)r.  r+  z--no-xlmr  zKDo not extract XLM Excel macros. This may speed up analysis of large files.r   %d.%d.%dr3   olevba  on Python ' - http://decalage.info/python/oletoolsz6You cannot combine options --no-pcode and --show-pcode)argparseArgumentParseradd_argumentr   add_argument_group
parse_argsr  r)  r  version_infora  __version__rn   
print_helprH  RETURN_WRONG_ARGSr	  no_pcoder  )cmd_line_argsDEFAULT_LOG_LEVELr(  parsermodesrb  python_versions          r.   rE  rE    s_    "@E$$51F
35GH
 \H  J
gN $E  F lX "O  P l3 #A  B
 %%,N%OE	tZ),;  <
 
t\-),+  ,
 
tXm).  / l=+T+  , h|,eN  P 
<3-  .
 =N $/  0 
<5(  )
 lG 15  6 	l %L  N )L $Y  Z \, %H  J \G  I

,PU!n  p .G 7"#c&6&6q&;;N, 	-g"#g..MNNr0   c                     Sn[        XUUR                  UR                  S9nUR                  S:X  ag  UR	                  UR
                  UR                  UR                  UR                  UR                  UR                  UR                  UR                  S9  OUR                  S:X  a0  UR                  UR
                  UR                  UR                  S9  OUR                  S:X  ap  [        UR                  UR
                  UR                  UR                  UR                  UR                  UR                  UR                  UR                  S95        O$[!        SR#                  UR                  5      5      eUR%                  5         [&        R)                  S	5        [*        R,                  " U 5      (       d  [&        R)                  S
5        [.        $  U[*        RL                  :  a  [*        RN                  " X@5      eSn [&        R)                  SR#                  URP                  5      5        URP                  [*        RR                  -   n[*        RT                  " X5      nU(       d+  [&        RW                  S5        [*        RX                  " U 5      e[&        R[                  S 5        [	        XqU=(       d    U X4S!-   5       [&        R)                  S"R#                  U5      5        [\        R^                  " U5        $ ! [0         GaV  n[&        R)                  SSS9  W(       a  UR%                  5         [&        R)                  S5        [*        R,                  " U 5      (       a   SnAGN[3        U[4        [6        45      (       a  UR                  S;   a  [9        S<S SU < S35        OQUR                  S:X  a)  [        U S[;        U5      R<                  [?        U5      S9  O[&        RA                  SU -  5        [B        s SnA$ [3        U[D        5      (       a  UR                  S;   a  [9        S<S SU < S35        OQUR                  S:X  a)  [        U S[;        U5      R<                  [?        U5      S9  O[&        RA                  SU -  5        [B        s SnA$ [3        U[F        5      (       a  UR                  S;   a"  [9        S<S SU < SURH                  < 35        OkUR                  S:X  a3  [        U S[;        U5      R<                  [?        URH                  5      S9  O([&        RA                  SU < SURH                  < S35        [J        s SnA$ e SnAff = f! [0         a     $ f = f!  [&        R)                  S"R#                  U5      5        [\        R^                  " U5        f ! [0         a     f f = f= f)#z
Part of main function that processes a single file.
This is meant to be used only for the command-line interface of olevba

This handles exceptions and encryption.

Returns a single code summarizing the status of processing of this file
N)r  r  r!  r  r9  )r  r  r  r  r  r  r	  r  r6  )r  r  r  r_  zunexpected output mode: "{0}"!z Checking for encryption (normal)zno encryption detectedzCaught exception:Tr  z)Checking for encryption (after exception))r6  r7  ?r!  r  z0 - Error opening substream or uenxpected contentr  rT  r   r  messagez3Error opening substream or unexpected content in %sz - File format not supportedz,Failed to open %s -- probably not supported!z!ERRORrK  r  r  z)!z Checking encryption passwords {}z4Decrypt failed, run with debug output to get detailszWorking on decrypted filer   zRemoving crypt temp file {})0r  r!  rJ  r5  r\  r  r  r  r  r  r  r	  r  r%  rg  r  r   r:   r  rY   r  r#   r  	RETURN_OKr%  r@   r   r   ra  r   rj   r   rj  RETURN_OPEN_ERRORrs   rx   rd   RETURN_PARSE_ERRORMAX_NESTING_DEPTHMaxCryptoNestingReachedpasswordrl  rm  r  WrongEncryptionPasswordr  osunlink)	rc   r  r  rb  crypto_nesting
vba_parserrG   ro  rp  s	            r.   r\  r\  l  s   N
 $H9,3OO292B2BD
 *,##9U9U&-&:&:)0)@)@PWPePe070N0N%,%8%8WEWEW+2>> $ ;   H,**@\@\7>7J7JSZSaSa + c  F*,,'B^B^&-&:&:)0)@)@PWPePe070N0N%,%8%8WEWEW4;NN - DE =DDWEXEXYZZ 			45""8,,II./ -` 111,,^FFN		4;;G<L<LMN$$v'?'??	<IILM00::,-N)2Gx#A%57	II3::>JKIIn%}  )		%	5		=>x((# 24GHII&&*CC'*H6 7((F2H7%)#Y%7%7SK MM #24<#= >((C//&&*CCCRS((F2H7%)#Y%7%7SK MM"PS["[\((C11&&*CCXxNO((F2H7%)#Y%7%7'*3<<'8: MM%-s||#= >))S)~  			II3::>JKIIn% 		s   GL C U8 	:U(U%AU 0BU U%BU U%"B7U U%U  U%(
U54U58W::V54W5
W?WWWc           
         [        U 5      n[        R                  " UR                  S:H  UR                  SS9  UR                  S:X  a$  [        S[        [        R                  SS SSSS	9  O.S
[        R                  SS -  n[        S[        < SU< S35        UR                  (       a-  UR                  (       d  [        R                  S5        SUl        [        S [        R                   " UR"                  UR$                  UR&                  UR(                  S9 5       5      nUR                  S:X  a  [+        U5      S:X  a  SUl        OSUl        UR                  S:X  aL  UR                  (       a  [        R                  S5        UR,                  (       a  [        R                  S5        UR                  S:X  a  [        SS-  5        [        SS-  5        SnSnS=n=px[.        n	 U GH  u  pgn[1        U[2        5      (       Ga  [1        U[4        5      (       a`  UR                  S:X  a  [        S<S SU< S35        O(UR                  S:w  a  [        R7                  SU-  5        U	S:X  a  [8        O[:        n	OkUR                  S:X  a  [        S<S SU< S U< 35        O1UR                  S:w  a!  [        R7                  S!U< S"U< S#U< 35        U	S:X  a  [<        O[:        n	UR                  S:X  a(  [        US$[?        U5      R@                  [C        U5      S%9  GM8  UR                  S:X  a  Xd:w  a  Ub  [        S&U-  5        Un[E        XxXa5      n
US-  nU
[.        :X  a  GM~  U	[.        :X  a  U
n	GM  [:        n	GM     UR                  S:X  a  [        S'5        [        R                  S+U	-  5        [        RR                  " 5         [        RT                  " U	5        g! [F        RH                   aK  n[        RK                  S(RM                  U5      SS)9  U	[.        :X  a  [N        n	 SnANU	[:        :H     SnANSnAf[2         a'  n[        RK                  S*U-  SS)9  [P        n	 SnANSnAff = f),z
Main function, called when olevba is run from the command line

Optional argument: command line arguments to be forwarded to ArgumentParser
in process_args. Per default (cmd_line_args=None), sys.argv is used. Option
mainly added for unit-testing
r_  T)other_logger_has_first_linerW   r   r3   z$http://decalage.info/python/oletoolsMetaInformation)script_nameversionrO  urlr   rd  r=  r>  r?  r@  z$set --deobf because --reveal was setc              3   n   #    U  H+  u  pnU(       a  UR                  S 5      (       a  M%  XU4v   M-     g7f)r   N)r  )r;   r  rc   r  s       r.   r=   main.<locals>.<genexpr>  s:      J9<49 $-1B1B31G 7I69<s   $55)r-  r0  r2  r7  r   r9  r6  z.ignoring option --reveal in triage output modez2ignoring option --show-pcode in triage output modez%-12s %-65s)FlagsFilename)z-----------zA-----------------------------------------------------------------NrQ  r!  r  z - File not foundzGiven path %r does not exist!z  - Failed to read from zip file zException opening/reading z from zip file z: r  rR  z
Files in %s:z
(Flags: OpX=OpenXML, XML=Word2003XML, FlX=FlatOPC XML, MHT=MHTML, TXT=Text, M=Macros, A=Auto-executable, S=Suspicious keywords, I=IOCs, H=Hex strings, B=Base64 strings, D=Dridex strings, V=VBA strings, ?=Unknown)
z$Problems with encryption in main: {}r  zUnhandled exception in main: %szwill exit now with code %s)+rE  r'   r\   r5  r;  rg  rG  r  rF  ra  r  r  rY   r  r   r   
iter_filesr)  r-  r0  r2  r  r	  rT  r@   r%  r   r  RETURN_FILE_NOT_FOUNDRETURN_SEVERAL_ERRSRETURN_XGLOB_ERRr   rj   r   r\  r#   CryptoErrorBaserj  r:   RETURN_ENCRYPTEDRETURN_UNEXPECTEDend_loggingrH  )rK  rb  rO  all_input_infoprevious_containercountr  rc   r  return_codecurr_return_coderG   s               r.   mainrv    s    'G g11697;K;K:>@ f$x"%"2"21Q"7=)$	@ $c&6&6q&;;N, 	- %%g.A.A		89"  J8=8H8H&00G<M<M,3,@,@)0):):9<J JN m+~!#",G"*Gh&))IIFGIIJK h&m334m223E"&&I&K<()7%I$	**d$9::**h6S(KL ,,6		"AH"LM;F!;K"79L   **h6cS[]fgh ,,6		)19d#D E6AQ6F"29L  &&&0H7%)$Z%8%8#d)M""h.2 ,.:;)2&  ,HIOQJE  9,i'.1Q *8T (* T U( II*[89HH[% !! /<CCCH# 	 	%)#*K.. ( 	7#=M'(s+   .F5O' 'Q5;3Q3	QQ5Q00Q5__main__)r)   r  r+   )r)   rK   )NF)F)r   )rn   
__future__r   rG  r  r  r[  r  ior   r   r  r  r  rA  r{  r*  r  r  email.feedparserstringr_  
lxml.etreeetreer  ImportErrorxml.etree.cElementTreecElementTreeelementtree.cElementTreer   r   r  enable	pyparsingr   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   XLMMacroDeobfuscatorr   rZ  rO  pathnormpathabspathdirname__file___thismodule_dirrB   _parent_dirr  r  oletools.thirdparty.tablestreamr   oletools.thirdparty.xglobr   r   'oletools.thirdparty.oledump.plugin_biffr   oletoolsr    r!   r"   r#   oletools.common.io_encodingr$   oletools.commonr%   r&   oletools.common.log_helperr'   rF  rN   ro  r/   r  r;  r  rh  ri  r   rQ  	functoolsr2   codecslookup_errorrF   rI   register_errorrQ   rV   get_or_create_silent_loggerrY   r\   r%  r^   rs   rx   r  r|   r   r   rT  RETURN_WARNINGSrI  rj  rl  rU  rV  rk  ro  rn  MAC_CODEPAGESrd  r  r  r  r  r  r   r  r  r  r"  r  r  r  r  NS_Wr  r  NS_XMLPACKAGETAG_PACKAGEr  r  r  r  r  r  r  r  r  r  SCHEMETLDDNS_NAMENUMBER_0_255IPv4SERVERPORTSERVER_PORTURL_PATHURL_REr  re_urlr  r  r"  	BASE64_REr'  r  r)  rE  r(  r  enablePackratvba_identifier_charsrN  decimal_literalsetParseActionoctal_literalhex_literalintegerquoted_stringrI  vba_expr_intvba_chrrl  vba_ascvba_valrq  environlatin_identifierquoted_hex_stringhex_function_callquoted_base64_stringbase64_function_callr  vba_expr_str_itemLEFTr  r  r  r  vba_expr_int_itemr  r  r  	printabler  r  r  r  rC   r  r8  r  r  r  r  r  r   r%  r.  r5  r8  rC  rF  rM  rS  rg  ri  r  r  r  rE  r\  rv  rj   r,   r0   r.   <module>r     s  ` &z B  
 	      	        P  77d?$/% % % % % %DO ''""277??277??83L#MNggrww||OTBCchhHHOOA{#  7 B 9     E %  1 A!G H! G FFG  & #)#6#67I#J 	1 	02IJ?* ,,X6,!) !E' EG) G0': 0' '- . 	           C 47HH    " 
	 f&fvvff	 &   @Y6M	 Hi' f$&$}4 9 - 	1J2 	! 	H 	A 	!3 D 	*	v "^ ,	*	^ ^ 2-^ >^ 8^& .)^* -^. E1^< 5	?^D G^J 7M^T >#W^\ "	Wi^l Fo^p 4s^t 8w^x {^| $"^@ C'E^F I^L 4O^P 0S^T =W^X 6[^\ T!_^` e^f +k^l +	
o^v $	y^| +	
A^H <;M^N D#Q^T 8W^Z T4_^f 	9	

 	R
	
 	4 	 	 	 		L 	E{^ F 		 	.:5>9# , a  
1#c)C/ Ey(<7	$	x	'#	-tm8	'	K	'(	2	F	=8  BJJvRZZ%&rzz":V"Cd"JKL RZZ 	hi j  

45 f	::cIo34  8 9 
 ::34 **[) jj!>?      !3 
	# 
	< (3-)4H*IIDQUJV$Xd5.B%CDE F   2 3/#:N0P!PQTXY_`gYhTii8Da$89:; <   8 9ht45VM=R8SS8Da$89:; <   7 8
M
)K
7 S40   0 1 yyd I23oe6LLs+oc.BBCDFNsmT U "" %-SM2
2    } % ?5)C/
0<
?(3-
O   * + ?5)C/
0<
?(3-
O   2 3 ol3c9:\IHUXMY
 
  H I ?9-3
4|
Chsm
S   E F &IOD  SMGD,BY,N$OORZ[^R__      !4 5-.#>%l346>smD      !^ _  }uY'77(3-G   # #$7 8 01HSMA(9:<DSMJ   # #$g h
1 z)G3mCFWWZnn  0	a23	a23 ,,, w&0 
 0	a12	a/0	a12	a}-	 	2 D!4Ut V%%&
+?"|)~O Ohy>& y>z/(&0#L%P4$@(2"J0f"(JXA& XAvL$|" |"@*M6Z M6d
bJpLfAF zF {I  P
P++ P	P11 	P O P P	P	P	P:  OsH   f .g g	ff?"f,(g,f;;f??ggg