|iǙdZddlmZdZddlZddlZddlZddlZddlm Z m Z ddl Z ddl Z ddl Z ddlZddlZddlZddlZddlZddlZddlZddlZ ddlmZn=#e$r5 ddlmcmZn'#e$r ddlmZn#e$r edwxYwYnwxYwYnwxYwddlZejdkrej d dd l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 dd l5m6Z7dZ8n #e$rd Z8YnwxYwej9:ej9;ej9<e=Z>ej9:ej9?e>d Z@e@ej9vrej9Ade@ddlBZBddlCmDZDddlEmFZFmGZGddlHmIZIddlJmKZKddlJmLZLddlJmMZMddlJmNZNddlOmPZPddlQmRZRddlJmSZSddlTmUZUejVddkrdZWeXZYdZZnFd ZWdZYe[Z\e]Z^e_Z`ddlambZbdZZejVdkr(ddlcZcecjddZedZfecjgdefd Zhd:d!ZieUjjd"Zkd#ZlGd$d%emZnGd&d'enZoGd(d)enZpGd*d+eqenZrGd,d-eoZsGd.d/enZtdZud0ZvdZwd1Zxd2Zyd3Zzd4Z{d5Z|d6Z}d7Z~d8d9d:d;dd?d@dAdBd:dC ZdDZdEezZdFZdGZdHZdIZdJZdKZdLZdMZedNedOedPedQedRedSedTedUiZdVZdWZdXZdYZdZZed[zZed\zZd]Zed^zZed_zZed\zZed`zZdaZedbzZdcdddedfdgdhdidjdkdl ZdmdndoZidpdqdrdsdtdudvdwdxdydzd{d|d}d~dddddddddddddddddddiddddddddddddddddddddddddddddddddddddddddddddddd ZddddddddȜZddiZdZdZdezdzZdZdezdzezZdezdzezdzZdZeezZdZedzezezZe jeZddgZde jefde jefde jdezdzfde jdަffZe jdߦZdZe jdezdzZegdZe jdZe jdZe jdZe4je-dzZGdde_Ze$e'de,eze+e0ze*e'e+dd0zZede$e*e&de'e#dze+e2dze*e'e+dd0zZede$e*e#de+e2dze*e'e+dd0zZedeezezZe(ddZede%Ze%Ze*e$e,ee#dze'e#de#dzze'dzdzeze*dΦzZdZeee*e"ddzeze*dΦzZede*e"ddzeze*dΦzZe de*e"ddzeze*dΦzZeàde*e"ddzeze*dΦzZeĠde+e.e-dzZe*de$e+e/ddzze*dzZeƠde*eŦe*dzeƐdze*dΦzZeǠd e*de)eze*dzZeȠd e*eŦe*dzeȐd ze*dΦzZeɠd d ZeezezezezezZee3eːdde1jefdde1jefgzZdZ͐dZΐdZϐdZeezezZee3eѐdde1jefdde1jefdde1jefdde1jefgzZdZe jdZӐdZeejZ֐dZאdZؐdZGddeڦZGddeڦZܐd;dZݐd Zސd!Zߐd<d"Zd<d#Zd<d$Zd%Zd&Zd'Zd(Zd)Zd*Zd+Zd=d-Zd>d.ZGd/d0eڦZd?d1ZGd2d3eڦZGd4d5eZd<d6Zd@d7Zd<d8Zed9kr edSdS(Aao 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_functionz0.60.2N)BytesIOStringIOzplxml or ElementTree are not installed, see http://codespeak.net/lxml or http://effbot.org/zone/element-index.htmntT) auto_colors)CaselessKeywordCaselessLiteralCombineForwardLiteralOptional QuotedStringRegexSuppressWord WordStart alphanumsalphashexnumsnumsopAssocsrange infixNotation ParserElement) deobfuscatorFz..) tablestream)xglobPathNotFoundException)cBIFF) ppt_parser)oleform)rtfobj)crypto)ensure_stdout_handles_unicode) codepages)ftguess) log_helperutf8c|SN)xs =C:\PYTHON\_runtimes\venv\Lib\site-packages\oletools/olevba.pybyte_ordr/nsreduce)backslashreplacect|tr?dd|j|j|jD}||jfSt |S)Nc3@K|]}d|VdS)z \x{0:02x}Nformat).0cs r. z*backslashreplace_errors..s0ZZqL//22ZZZZZZr0) isinstanceUnicodeDecodeErrorjoinobjectstartend_backslashreplace_errors)excus r.backslashreplace_errorsrGsa#122 "GGZZCJsyQTQXGX>>r0cBtr|S||dS)a 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 rIrJ)rLdecode) bytes_stringencodings r. bytes2strrTs+?""8I">>>r0olevbacttjt jt jdS)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)logsetLevelr'NOTSETr enable_loggingr#r,r0r.rZrZs=LL"### r0c$eZdZdZdfd ZxZS)OlevbaBaseExceptionzD Base class for exceptions produced here for simpler except clauses Nc |r8tt|j|d|zfi|n!tt|j|fi|||_||_||_dS)Nz ({0}))superr\__init__r:msgfilenameorig_exc)selfr`rarbkwargs __class__s r.r_zOlevbaBaseException.__init__s  E 5E%t , , 5c6>ooh6O6O7P @ @8> @ @ @ @ 6E%t , , 5c D DV D D D    r0)NN__name__ __module__ __qualname____doc__r_ __classcell__res@r.r\r\sCNN ! ! ! ! ! ! ! ! ! !r0r\c$eZdZdZdfd ZxZS) FileOpenErrorzy raised by VBA_Parser constructor if all open_... attempts failed probably means the file type is not supported Ncbtt|d|z||dS)NzFailed to open file %s)r^rnr_rcrarbres r.r_zFileOpenError.__init__s@ mT""++ $x /8 E E E E Er0r+rfrls@r.rnrnsQ EEEEEEEEEEr0rnc"eZdZdZfdZxZS)ProcessingErrorz. raised by VBA_Parser.process_file* functions cbtt|d|z||dS)NzError processing file %s)r^rrr_rps r.r_zProcessingError.__init__s@ ot$$-- & 18X G G G G Gr0rfrls@r.rrrrsG88GGGGGGGGGr0rrceZdZdZdZdS)MsoExtractionErrorzB raised by mso_file_extract if parsing MSO/ActiveMIME data failed crt||t||dSr+)rur_r\)rcr`s r.r_zMsoExtractionError.__init__s4##D#...$$T3/////r0Nrgrhrirjr_r,r0r.rurus)LL00000r0ruc$eZdZdZdfd ZxZS)SubstreamOpenErrorzE special kind of FileOpenError: file is a substream of original file Nctt|t|dzt|z|||_||_dSN/)r^ryr_strra subfilename)rcrar~rbres r.r_zSubstreamOpenError.__init__sX  $''00 MMC #k"2"2 2H > > >  &r0r+rfrls@r.ryrysCOO''''''''''r0ryc"eZdZdZfdZxZS)UnexpectedDataErrorzE raised when parsing is strict (=not relaxed) and data is unexpected ct|trd|}nyt|tr5dd|D}d|}n/t dt |tt| d||||||_ ||_ ||_ ||_ dS)N{0:04X},c3@K|]}d|VdS)rNr9)r;es r.r=z/UnexpectedDataError.__init__..s0@@!)**1--@@@@@@r0z({0})zUnknown type encountered: {0}zIUnexpected value in {0} for variable {1}: expected {2} but found {3:04X}!)r>intr:tupler@ ValueErrortyper^rr_ stream_pathvariableexpectedvalue)rcrrrresres r.r_zUnexpectedDataError.__init__s h $ $ U!!(++BB % ( ( U@@x@@@@@B..$$BB<CCDNNSSTT T !4((11 . VK2u 5 5 7 7 7'     r0rfrls@r.rrs>OOr0rr3r4 z mac-romanshiftjisasciigb2321big5hebrewz mac-arabicz mac-greekz mac-turkishthaimaccentraleurope) i'i'i'i'i'i'i'i'ia'i%'i-'i'z,https://github.com/decalage2/oletools/issueszPlease report this issue on %sOLEOpenXML FlatOPC_XML Word2003_XMLMHTMLTextPPTSLKzOLE:zOpX:zFlX:zXML:zMHT:zTXT:zPPT:zSLK:s ActiveMimebasclsfrmz6{http://schemas.microsoft.com/office/word/2003/wordml}binDatanamez5{http://schemas.microsoft.com/office/2006/xmlPackage}packagepart contentTypez$application/vnd.ms-office.vbaProject binaryData)AutoExecAutoOpen DocumentOpen)AutoExit AutoCloseDocument_CloseDocumentBeforeClose)DocumentChange)AutoNew Document_New NewDocument) Document_Open)Document_BeforeClose) Auto_Open Workbook_OpenWorkbook_ActivateAuto_Ope) Auto_CloseWorkbook_CloseWorkbook_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)EnvironWin32_Environment EnvironmentExpandEnvironmentStringszHKCU\EnvironmentzHKEY_CURRENT_USER\EnvironmentzMay open a file)Openz+May write to a file (if combined with Open))WritePutOutputzPrint #z7May read or write a binary file (if combined with Open))BinaryzMay copy a file)FileCopyCopyFileCopyHere CopyFolderzMay move a file)MoveHereMoveFile MoveFolderzMay delete a file)KillzMay create a text file)CreateTextFilez ADODB.Stream WriteText SaveToFilez.May run an executable file or a system command)ShellvbNormal vbNormalFocusvbHidevbMinimizedFocusvbMaximizedFocusvbNormalNoFocusvbMinimizedNoFocusz WScript.ShellRun ShellExecute ShellExecuteAshell32 InvokeVerb InvokeVerbExDoItz 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 AppleScriptzMay run PowerShell commands) PowerShellnoexitExecutionPolicy noprofilecommandEncodedCommandzinvoke-command scriptblockzInvoke-ExpressionAuthorizationManagerz?May run an executable file or a system command using PowerShell)z Start-Process-May call a DLL using Excel 4 Macros (XLM/XLF))CALLzMay hide the application)zApplication.Visible ShowWindowSW_HIDEzMay create a directory)MkDirzMay save the current workbook)zActiveWorkbook.SaveAszrKsQqTr0&oz[0-7]c0t|ddS)NrrbaserHrIs r.rKrKss1Q4a'8'8'8r0z&hz [0-9a-fA-F]c0t|ddS)NrrOrHrIs r.rKrKsS1B%7%7%7r0"")escQuotec,t|dSrGr}rIs r.rKrKss1Q4yyr0rBW$(cB |d}|dkr"|dkrtt|Stt|ddS#t$r2t d|ztd|zcYSwxYw)Nrzutf-8r5z.ERROR: incorrect parameter value for chr(): %rzChr(%r))rCchrunichrrMrrW exception)rJis r. vba_chr_tostrras 2 aD a44AsFF's1vv.. . 'vayy'7'7AS'T'TUU U 222 FJKKK"9q=111112s/A"/A""9BBAscc,t|dSrG)ordrIs r.rKrK+sQqTr0ValcPt|dSrG)rstriprIs r.rKrK3sQqTZZ\\!2!2r0rcXtt|ddddS)Nr)rCr}rIs r.rKrK:s#$7AaD $$B$$H$Hr0rc2td|dzS)Nz%%%s%%r)rCrIs r.rKrKAs!4X!_!E!Er0) initChars bodyChars)r(Nc,t|dSrGrVrIs r.rKrKTs3qt99r0 hex_stringcNttj|jSr+)rCbinasciia2b_hexrnrIs r.rKrKXs+>x?OPQP\?]?]+^+^r0c,t|dSrGrVrIs r.rKrKbsc!A$iir0 base64_stringcNttj|jSr+)rCrp a2b_base64rsrIs r.rKrKfs.A(BUVWVeBfBf.g.gr0ch|dddd}td|S)z[ parse action to concatenate strings in a VBA expression with operators '+' or '&' rNr(r7)rCr@)tokensstringss r.concat_strings_listryks1 Qi!nG rwww// 0 00r0+cB|dddd}t|S)zL parse action to sum integers in a VBA expression with operator '+' rNr()sumrwintegerss r. sum_ints_listrs# ay1~H x==r0cF|dddd}td|S)zQ parse action to subtract integers in a VBA expression with operator '-' rNr(c ||z Sr+r,r-ys r.rKz$subtract_ints_list.. QqSr0r1r}s r.subtract_ints_listrs) ay1~H ..( + ++r0cF|dddd}td|S)zQ parse action to multiply integers in a VBA expression with operator '*' rNr(c ||zSr+r,rs r.rKz$multiply_ints_list..rr0r1r}s r.multiply_ints_listr) ay1~H ..( + ++r0cF|dddd}td|S)zO parse action to divide integers in a VBA expression with operator '/' rNr(c ||z Sr+r,rs r.rKz"divide_ints_list..rr0r1r}s r.divide_ints_listrrr0*r|c6|tS)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 ) startswithMSO_ACTIVEMIME_HEADERdatas r. is_mso_filers ??0 1 11r0r-c t|sJddg} tjd|dddz}td|z|d|n_#tj$rM}td |ztd d td d}~wwxYw|D]} td|ztj ||d}|cS#tj$rG}td|d|dtd d Yd}~d}~wwxYwtdt |D]}| } td|ztj ||d}|cS#tj$rC}td|ztd d Yd}~d}~wwxYwtd)a 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 2i* * **r0c||z }ttjtj|d}t |dg}d|z }|}d|z dz}||||fS)aZ 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(rir3)rmathceilrWmax)decompressed_currentdecompressed_chunk_start difference bit_count length_mask offset_maskmaximum_lengths r.copytoken_helprsr&(@@JDIdhz1556677IYN##II%K,K )Q.N  Y >>r0c|t|tst|}tdt |t}d}||}|dkr"t d||dz }|t |krw|}tjd|||dzd}|dzdz}|d z d z}|dkrt d |d z dz}td ||||dkr|dkrt d|z|dkr|dkrt d|z||zt |krt dtt |||zg} |dz}|dkr'| |||dz|dz }n t |} || kr ||} |dz }tddD]} || krn| | z dz} | dkr"| ||g|dz }:tjd|||dzd}tt || \}}}}||zdz}||z}d|z }||z dz}t ||z }t|||zD]}| ||g|dz }|| k |t |kwt|S)a 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 = {} bytesrrzinvalid signature byte {0:02X}rr(ir3 rz9Invalid CompressedChunkSignature in VBA compressed streamz2chunk size = {}, offset = {}, compressed flag = {}iz:CompressedChunkSize=%d > 4098 but CompressedChunkFlag == 1z;CompressedChunkSize=%d != 4098 but CompressedChunkFlag == 0z3Chunk size is larger than remaining compressed datairrR)r> bytearrayrWrr:lenrrunpackwarningminextendxrangerbytes)compressed_containerdecompressed_containercompressed_currentsig_bytecompressed_chunk_startcompressed_chunk_header chunk_sizechunk_signature chunk_flagcompressed_endr flag_byte bit_indexflag_bit copy_tokenrrrrAlengthtemp1temp2r copy_sourceindexs r.decompress_streamr%s: *I 6 6?()=>>II=DDSI]E^E^__```&[[#$67H49@@JJKKK! s#788 8 8!3 M$ 45KLbefLf5f g h hij k .6!; 2b8D@ e # #XYY Y-3t;  FMMjZpr|}}~~~ ??zD00Y\ffgg g ??zT11Z]gghh h "J .5I1J1J J J KKM N N Nc"6779OR\9\]^^3a7 ?? # ) )*>?QRdgkRk?k*l m m m $ &  (++A'B'B $$~55 11CD "a'"!'100I)^;;!*Y 6!;H1}}.557KL^7_6`aaa*a/**#M$0DEWXjmnXnEn0oppqrs#BP 6779QBSBS> [)Q",{":a!? *[ 8 "Y"'5.A!5&)*@&A&AF&J %+Kv9M%N%N[[E299;QRW;X:YZZZZ*a/**G%~55Y s#788 8 8` ' ( ((r0ceZdZdZdZdS) VBA_Modulez| Class to parse a VBA module from an OLE file, and to store all the corresponding metadata and VBA source code. c N||_d|_d|_d|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_d|_d|_ t'jd|dd}|dd|t'jd|d d}||}|||_t1|j|_t'jd|dd}|d krt'jd|d d}||d d |_t'jd|dd}|d krEt'jd|d d}||}|||_t1|j|_t'jd|dd} |dd| t'jd|d d}||d d |_t'jd|dd}|dkrt'jd|d d}||} || |_t'jd|dd} |dd| t'jd|d d}|||_t'jd|dd}|dkrt'jd|d d}|dd |t'jd|d d|_ t'jd|dd}|dkrt'jd|d d} |dd | t'jd|d d} t'jd|dd}|dkrt'jd|d d}|dd|t'jd|dd} t'jd|dd}|dks|dkrc||_ t'jd|d d} t'jd|dd}|dkrzd|_ t'jd|d d} |dd| t'jd|dd}|dkrzd|_ t'jd|d d} |dd| t'jd|dd}|d krGt'jd|d d} |d!d| d}|dkr-t4d"|t4d#|jt4d$|jt4d%|j d}|j|j|j|jf}|D]}| |jd&z|z|_t4d'|jz|j |j}n9#tB$r+}t4d(|d)|d*Yd}~d}~wwxYw|ct4"d+||j#d,$d-|Dfz|j%rdStMd.d&|jzt4d/tO|t4d0|j ||j d}tO|dkrtQtS|}||_ |||_t1|j|_|jj*+|j,d1}d2|j||_t1|j|_t4d3|jdSt4d4|jdS#tZtLf$rt\$r;}t4"d5||j#d6d}~wwxYw)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 NFrr(r MODULENAME_Id.RsH%C%C)4&);%6%<%C%C%C%C%C%Cr0z[BASE]zlength of code_data = {0}zoffset of code_data = {0}vbaz{0}.{1}zextracted file {0}z(module stream {0} has code data length 0z Error parsing module {0} of {1}:r)/projectrname_str _name_unicode streamnamestreamname_str_streamname_unicode docstring_docstring_unicode textoffsetrreadonlyprivatecode_rawcodecode_strra filename_str code_pathrrread check_value decode_bytesrOrQrWrr:rvba_rootole openstreamIOErrorr modules_countr@relaxedryrrr module_extgetlowerr Exception)rcr dir_stream module_index_idsizemodulename_bytes section_idstreamname_bytesreserveddocstring_bytesmodulehelpcontext_size helpcontextcookie code_data try_namesrioefilextrEs r.r_zVBA_Module.__init__s    !"#' "&        b -jooa&8&899!>DI' 22DM tZ__Q-?-?@@CJV##}T:??1+=+=>>qA%/__T%:%:%A%A*i%X%X"#]41C1CDDQG V##}T:??1+=+=>>qA#-??4#8#8 ")"6"67G"H"H&1$/&B&B#!=zq/A/ABB1E##$?RRR}T:??1+=+=>>qA+5??4+@+@+G+G T]+^+^(#]41C1CDDQG V##}T:??1+=+=>>qA",//$"7"7!(!5!5o!F!F!=zq/A/ABB1E##$>QQQ}T:??1+=+=>>qA*4//$*?*?'#]41C1CDDQG V##}T:??1+=+=>>qA##$7FFF"(-jooa6H6H"I"I!"L#]41C1CDDQG V##*0tZ__Q=O=O)P)PQR)S&##$>qA##$7FFFtZ__Q-?-?@@C#]41C1CDDQG V##zV';';' !=zq/A/ABB1E#]41C1CDDQG V##!% !=zq/A/ABB1E##$=vxPPP#]41C1CDDQG V## $ !=zq/A/ABB1E##$"OPPP$+K$:$:4>$J$J$O$O$Q$Q "888 %0[[####7888888888 + O('*?HH%C%C8A%C%C%CCCDDEEE?KF,Xv 7IJJJ II188YHH I I I II188II J J J!$/"2"23I9~~!!-i .B.BCC ) #00;; +DI 6 6 044TY__5F5FNN * 1 1$)V D D $/ $>$>! .55d6GHHIIIII FMMdNabbccccc#%78        HH7f\7+@AA"  $ $ $   sRbo A%e42o4 f)>!f$o$f))Ao:Fo2op$)6pp$Nrwr,r0r.rrs2 IIIIIr0rc4eZdZdZd dZdZdZdZd dZd S) VBA_Projectzy Class to parse a VBA project from an OLE file, and to store all the corresponding metadata and VBA modules. Tc.||_||_||_||_||_g|_i|_td|z| | }ttt|}||_tjd| dd}|dd|tjd| dd} |d d| tjd| dd|_d d d d d} | |jd|_td|j|jfz|j| vr2td|jtjd| dd} | dkr| } |dd| tjd| dd} |dd| tjd| dd}td|tjd| dd} | }|dd|tjd| dd}|dd|tjd| dd|_|dd|jtjd| dd}|dd|tjd| dd}|dd|tjd| dd|_|dd|jtjd| dd}|dd |tjd| dd}|d!d|tjd| dd|_t5j|j|_td"|jd#|jt5j|j|_td$|j|jfztjd| dd}|d%d|tjd| dd}td&|z|dks|d'kr-td(|| |}|||_ tjd| dd}|d)d*|tjd| dd}|d+kr-td,|| |}|||_!tjd| dd}|d-d.|tjd| dd}|dzdkrtd/| |}|"d0d12|_#tjd| dd}|d3d4|tjd| dd}|d5kr-td6|| |} tjd| dd}!|d7d8|!tjd| dd}"|"|krtd9| |"}#|#| krtd:tjd| dd}$|d;d<|$tjd| dd}%|d=d|%tjd| dd}&|&}'tjd| dd}(|d>d?|(tjd| dd})|d@d|)tjd| dd}*|dAd|*tjd| dd}+|dBdC|+tjd| dd},|dDd|,tjd| dd}-tjd| dd}.|-}'|.}'tjd| dd}/|dEdF|/tjd| dd}0|0dGkr-tdH|0| |0}1tjd| dd}2|dIdJ|2tjd| dd}3|3dzdkrtdK| |3}4|1}'|4}'dL}5 tjd| dd}5tdN|5|5dOkrdLS|5dPkr0|5}6tjd| dd}7| |7}8tdQtI||8ztjd| dd}9|9dRkrKtjd| dd}:| |:};|6}'|8}'|;}'l|9}5tdN|5|5dSkr|5}tdTtI||>z|<}'|>}')|5dUkr|5}?tjd| dd}@tjd| dd}A| |A}BtdVtI||Bztjd| dd}C|dWd|Ctjd| dd}D|dXd|D|?}'|@}'|B}'tjd| dd}E|EdPkr1|5}Ftjd| dd}G| |G}HtdYtI||Hztjd| dd}I|IdRkrxtjd| dd}J| |J}Ktjd| dd}L|F}'|H}'|K}'n|I}Ln|E}L|dZd[|Ltjd| dd}Mtjd| dd}N| |N}Otjd| dd}Ptjd| dd}Q| d\}Rtjd| dd}S|M}'|O}'|P}'|Q}'|R}'|S}' |5d]krB|5}Ttjd| dd}Utjd| dd}V| |V}Wtd^tI||Wztjd| dd}X|d_d|Xtjd| dd}Y|d`d|Y|T}'|U}'|W}'V|5dakr|5}Ztjd| dd}[tjd| dd}\| |\}]tdbtI||]ztjd| dd}^| |^}_tdctI||_ztjd| dd}`tjd| dd}a|Z}'|[}'|]}'|_}'|`}'|a}'tdd|5tK|dedf|5)ga 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 zParsing the dir stream from %rrr(rPROJECTSYSKIND_IdrrrPROJECTSYSKIND_Sizez16-bit Windowsz32-bit Windows Macintoshz64-bit Windows)rrr(r3UnknownzPROJECTSYSKIND_SysKind: %d - %sz&invalid PROJECTSYSKIND_SysKind {0:04X}JPROJETCOMPATVERSION_IdPROJECTCOMPATVERSION_Sizez compat version: {compat_version})compat_versionPROJECTLCID_IdPROJECTLCID_SizePROJECTLCID_Lcidi PROJECTLCIDINVOKE_IdPROJECTLCIDINVOKE_SizePROJECTLCIDINVOKE_LcidInvokePROJECTCODEPAGE_Idr3PROJECTCODEPAGE_SizezProject Code Page:  - z.Python codec corresponding to code page %d: %sPROJECTNAME_IdzProject name size: %d bytesz=PROJECTNAME_SizeOfProjectName value not in range [1-128]: {0}PROJECTDOCSTRING_Idr4iz8PROJECTDOCSTRING_SizeOfDocString value not in range: {0}PROJECTDOCSTRING_Reserved@z3PROJECTDOCSTRING_SizeOfDocStringUnicode is not evenutf16rIrJPROJECTHELPFILEPATH_Idriz;PROJECTHELPFILEPATH_SizeOfHelpFile1 value not in range: {0}PROJECTHELPFILEPATH_Reserved=zVPROJECTHELPFILEPATH_SizeOfHelpFile1 does not equal PROJECTHELPFILEPATH_SizeOfHelpFile2zJPROJECTHELPFILEPATH_HelpFile1 does not equal PROJECTHELPFILEPATH_HelpFile2PROJECTHELPCONTEXT_IdrPROJECTHELPCONTEXT_SizePROJECTLIBFLAGS_IdrPROJECTLIBFLAGS_SizePROJECTLIBFLAGS_ProjectLibFlagsPROJECTVERSION_IdrPROJECTVERSION_ReservedPROJECTCONSTANTS_Idriz8PROJECTCONSTANTS_SizeOfConstants value not in range: {0}PROJECTCONSTANTS_Reserved<z3PROJECTCONSTANTS_SizeOfConstantsUnicode is not evenNTzreference type = {0:04X}rzREFERENCE name: %s>3zREFERENCE original lib id: %s/z%REFERENCE control twiddled lib id: %sREFERENCECONTROL_Reserved1REFERENCECONTROL_Reserved2z*REFERENCE control name record extended: %sREFERENCECONTROL_Reserved30rR zREFERENCE registered lib id: %sREFERENCEREGISTERED_Reserved1REFERENCEREGISTERED_Reserved2z%REFERENCE project lib id absolute: %sz%REFERENCE project lib id relative: %sz#invalid or unknown check Id {0:04X}zreference type)rrOrQrRrWrZ)&rr  project_pathdir_pathrmodulesrrWrrr rrrrrrr syskindr syskind_namerr:lcid lcidinvokecodepager%get_codepage_name codepage_namecodepage2codeccodecr  projectnamerrQdocstring_unicoderOr)brcrr r[r\rdir_compressedrprojectsyskind_idprojectsyskind_size SYSKIND_NAME project_idprojectcompatversion_idprojectcompatversion_size"projectcompatversion_compatversionprojectlcid_idprojectlcid_sizeprojectlcidinvoke_idprojectlcidinvoke_sizeprojectcodepage_idprojectcodepage_sizeprojectname_idsizeof_projectnameprojectname_bytesprojectdocstring_id!projectdocstring_sizeof_docstringrprojectdocstring_reserved)projectdocstring_sizeof_docstring_unicodedocstring_unicode_bytesprojecthelpfilepath_id$projecthelpfilepath_sizeof_helpfile1projecthelpfilepath_helpfile1projecthelpfilepath_reserved$projecthelpfilepath_sizeof_helpfile2projecthelpfilepath_helpfile2projecthelpcontext_idprojecthelpcontext_sizeprojecthelpcontext_helpcontextunusedprojectlibflags_idprojectlibflags_sizeprojectlibflags_projectlibflagsprojectversion_idprojectversion_reservedprojectversion_versionmajorprojectversion_versionminorprojectconstants_id!projectconstants_sizeof_constantsprojectconstants_constantsprojectconstants_reserved)projectconstants_sizeof_constants_unicode"projectconstants_constants_unicodecheck reference_idreference_sizeof_namereference_namereference_reservedreference_sizeof_name_unicodereference_name_unicodereferenceoriginal_id&referenceoriginal_sizeof_libidoriginalreferenceoriginal_libidoriginalreferencecontrol_idreferencecontrol_sizetwiddled%referencecontrol_sizeof_libidtwiddledreferencecontrol_libidtwiddledreferencecontrol_reserved1referencecontrol_reserved2check2&referencecontrol_namerecordextended_id/referencecontrol_namerecordextended_sizeof_name(referencecontrol_namerecordextended_name,referencecontrol_namerecordextended_reserved7referencecontrol_namerecordextended_sizeof_name_unicode0referencecontrol_namerecordextended_name_unicodereferencecontrol_reserved3referencecontrol_sizeextended%referencecontrol_sizeof_libidextendedreferencecontrol_libidextendedreferencecontrol_reserved4referencecontrol_reserved5 referencecontrol_originaltypelibreferencecontrol_cookiereferenceregistered_idreferenceregistered_size referenceregistered_sizeof_libidreferenceregistered_libidreferenceregistered_reserved1referenceregistered_reserved2referenceproject_idreferenceproject_size%referenceproject_sizeof_libidabsolutereferenceproject_libidabsolute%referenceproject_sizeof_libidrelativereferenceproject_libidrelativereferenceproject_majorversionreferenceproject_minorversionsb r.r_zVBA_Project.__init__~s3  )     2X=>>>116688.y/H/HIIJJ $ #M$ 0B0BCCAF ,f6GHHH$mD*//!2D2DEEaH .8KLLL}T:??1+=+=>>qA """   ),,T\9EE 3t|TEV6WWXXX <| + + II>EEdlSS T T T]4););<BBB!=zq/A/ABB1E +V5EFFFM$ (:(:;;A>  +UDI>>> &}T:??13E3EFFqI /9MNNN!'tZ__Q5G5G!H!H!K 16;QRRR -jooa.@.@AA!D 7PPP$]41C1CDDQG -v7IJJJ%}T:??13E3EFFqI /9MNNN dJOOA,>,>??B &8GG $---ASASTUUU-dm<<  BdmUYU_E``aaa  tZ__Q-?-?@@C )6>BBB#]41C1CDDQG /2DDEEE  ! !%7#%=%= IIU\\]opp q q q&OO,>??,,->?? %mD*//!2D2DEEaH .8KLLL,2M$ PQ@R@R,S,STU,V) ,t 3 3 IIJQQRstt v v v %//*KLL**?;;$*M$ 8J8J$K$KA$N! 4f>WXXX4:M$ XYHZHZ4[4[\]4^1 4q 8A = = IIK L L L#-//2["\"\!8!?!?PY!?!Z!Z"(tZ__Q5G5G!H!H!K 16;QRRR/5}T:??STCUCU/V/VWX/Y, /# 5 5 IIMTTUyzz | | |(28\(](]%'-}T:??1;M;M'N'Nq'Q$ 7A]^^^/5}T:??STCUCU/V/VWX/Y, /3W W W IIn o o o(28\(](]% (,I I I IIb c c c!' dJOOA4F4F G G J 0&:OPPP"(-jooa6H6H"I"I!"L 2FP>P*Q*QRS*T' :FDcddd#M$ 0B0BCCAF ,f6GHHH"(-jooa6H6H"I"I!"L 2FWXXX4:M$ XYHZHZ4[4[\]4^1 4q 8A = = IIK L L L-7__=f-g-g*+3N oM$ (:(:;;A>E II077>> ? ? ? % (. dJOOA dJOO\]L^L^8_8_`a8b51;Af1g1g. AKPTPaPacAQBQBECECCDDD-3]4QRASAS-T-TUV-W*  !=vGabbb-3]4QRASAS-T-TUV-W*  !=vGabbb,67tZ__Q-?-?@@CV##=B:FLmTXZdZiZijkZlZlFmFmnoFpC?IG@I@I<IIJ[))*RSSNUNUUVVVCI=QUWaWfWfghWiWiCjCjklCm@CvMMRXR_`dfpfufuvwfxfxRyRyz{R|OKU??SLULUH5;]4YZI[I[5\5\]^5_2!G!I!Q5a2217.  !=vGabbb06 dJOOTUDVDV0W0WXY0Z-8> dJOO\]L^L^8_8_`a8b51;Af1g1g.-3]4QRASAS-T-TUV-W*-3]4QRASAS-T-TUV-W*3=??23F3F0*0-jooa>P>P*Q*QRS*T'673390*/&+1=zq?Q?Q+R+RST+U(39=zWXGYGY3Z3Z[\3]0,6OO<\,],]) ;k$J[J[\uJvJv>w>wwxxx06 dJOOTUDVDV0W0WXY0Z-  !@&Jghhh06 dJOOTUDVDV0W0WXY0Z-  !@&Jghhh/12',#(. dJOOA dJOO\]L^L^8_8_`a8b51;Af1g1g. AKPTPaPacAQBQBECECCDDD8> dJOO\]L^L^8_8_`a8b51;Af1g1g. AKPTPaPacAQBQBECECCDDD06 dJOOTUDVDV0W0WXY0Z-06 dJOOTUDVDV0W0WXY0Z-,.7766 II;BB5II J J J%h0@Bfhmnn nr0c||krO|jr1td|||dSt |j|||dS)Nz2invalid value for {0} expected {1:04X} got {2:04X})rrWrr:rr\)rcrrrs r.r zVBA_Project.check_valuesn u  | P P!6$%88:::::*$-xOOO  r0c0|j|j}i|_|D]}||}t d|z|}d|vr|dd\}}| }|dkr,|ddd}t|j|<|dkrt|j|<|dkrt|j|<|d krt|j|<d S) zP Parse the PROJECT stream from the VBA project :return: z PROJECT: %r=rDocumentr|rModuleClass BaseClassN) rrr[rr rWrrgsplitrCLASS_EXTENSIONMODULE_EXTENSIONFORM_EXTENSION)rcproject_streamlinerrs r.parse_project_streamz VBA_Project.parse_project_streams ,,T->??," < >>>>>r0r(c#Ktd|zt|||||}||D] \}}}|||fVdS)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)rWrr(rr) rr r[r\rrr rar#s r. _extract_vbar5sIIo'(((#xxIIG   """*1*?*?*A*A//& 8Y(I.....//r0c |dd}|dd}|dd}n0#tdt|zxYw|S)a 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 _ ztype(vba_code)=%s)rIrWr_r)vba_codes r.vba_collapse_long_linesrIsw##Hc22##FC00##FC00 )DNN:;;; Os AA-A2c|}d}|D]!}|dr d|vr|dz }!d||d}|S)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 rz Attribute VB_:r N) splitlinesrr@)r vba_linesrBrrs r. filter_vbar\sr##%%I E ??? + + C4KK QJEE  ))Ieff% & &C Jr0cg}d}|rd|z}tD]g\}}|D]_}tjdtj|zdz|}|r.|}||||zf`htD]U\}}|D]M}tjd|zdz|}|r.|}||||zfNV|S)am 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_KEYWORDSitemsresearchescapegrouprAUTOEXEC_KEYWORDS_REGEX r obfuscationresultsobf_text descriptionkeywordskeywordr found_keywords r.detect_autoexecrtsEGH6'+5!2!8!8!:!:HH X H HGIi")G*<*<!>!@!@HH X H HGIi'1E98DDE H %  {X/EFGGG  H Nr0cg}d}|rd|z}tD]g\}}|D]_}tjdtj|zdz|}|r.|}||||zf`htD]U\}}|D]M}tjd|zdz|}|r.|}||||zfNVtD]B\}}|D]:}| |vr"|dkr|||||zf;C|S)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) r7rrrr2) SUSPICIOUS_KEYWORDSrrrrrrSUSPICIOUS_KEYWORDS_REGEXSUSPICIOUS_KEYWORDS_NOREGEXrrs r.detect_suspiciousrsGH6'+5!4!:!:!???????? @ NsA CD.DDc`d}|D]}|r||z }t|S)Nr7isdigitrinputresultr<s r. StripCharsr  s< F  99;;  aKF v;;r0cld}|D]!}|r||z }|dz }"t|S)Nr70rrs r.StripCharsWithZeror# sH F  99;;  aKFF cMFF v;;r0c6|ddttdz dz tdz }ttdz tdz dz}||z dtdz dz tdz dzdzttdz dz z tdz dz z}dtdz dz z tdz dz zdzfdtdtD}d}|D]$}|t t||z z }%|S)Nrr(c*g|]}||zSr,r,)r;r` nCharSizeworks r. z#DridexUrlDecode..& s&NNN!$q9}%NNNr0rr7)r#rr ranger]) inputText strKeyEnc strKeySize strKeyEnc2 work_splitrrr'r(s @@r.DridexUrlDecoder0 s QrT?D"4TQ!(;c$ii!m(L#MNNI#D#d))a-3t99q=A:M)M$NOOJY&I $#d))a-1$$ %c$ii!mq-@-A-A(B BDD#d))a-IaK!@3t99q=U^_`U`Ba!abccJ 0#d))a-IaK00 1D#d))a-IVWK9X9Y9Y4Z ZDNNNNNuQD 9/M/MNNNJG553z%((3444 Nr0cg}t}t|D]}|dd}t|s9||vr~ t t|}|||f| |#t$r'}t d|zYd}~d}~wwxYw|S)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) rrizFailed to Dridex-decode (%s)N) rre_dridex_stringrrrrrTr0rrrrWrrs r.detect_dridex_stringsr32 sG EEE!**844 @ @ ad#%%e,,      @#OE$:$:;;w/000 %     @ @ @ 83>???????? @  Ns)AB22 C#<CC#cxg}t}|}|D]}t|D]c\}}}|||}|d}t |t r6||vr2||kr,|||f||d|S)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>rCrr) rrrvba_linerwrBrCencodedrs r.detect_vba_stringsr:K sG EEE""$$H''))''"."9"9("C"C ' ' FE3uSy)GQiG'#677 '%''Gw,>,>NNGW#5666IIg&&& '" Nr0rIc|nJt|tttfrn&t|trt r|||||}||krvt d |t|t d |t||S|St|trLt rE|||}t d ||St|trLt sE|||}t d ||St|tr|D]}t||||<nkt|t t"fr|D]}t|}n:t d t%||S)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 Nz#json2ascii: replaced: {0} (len {1})z#json2ascii: with: {0} (len {1})zjson2ascii: encode unicode: {0}z1unexpected type in json2ascii: {0} -- leave as is)r>boolrfloatr}rLrQrMrWrr:runicoderdict json2asciilistrr)json_objrSrKdencodedjson_obj_bytes json_obj_strkeyitems r.r@r@p s, HtS%0 1 1&+ Hc " "$+  x88??&QQH8## ? &3x==99;;; ? &3x==99;;;OO Hg & &+7+!6:: 3::>JJKKK He $ $+W+x88  3::<HHIII Hd # #+ 6 6C&x}55HSMM 6 HtEl + ++ $ $Dd##DD $ E6$x..)) + + + Or0c |r|rtd|Dt|ts/tdt ||r|}t jt|ddd}|sdS|rtd|dzntd |dz|d dD]&}td| z'dS) 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_circularindent ensure_asciiz rz, r) rr>r?r:rjsondumpsr@rprintrstrip) json_dict_json_is_first json_partslinesrs r. print_jsonrT s13Z39:: :  *Y*E*E H &i1133 3 Jz),,Ue 5 5 55?Z\\ # hq!"""" hq!"""abb (( h&''''((r0c&eZdZdZdZddZdZdS) VBA_Scannerz Class to scan the source code of a VBA module to find obfuscated strings, suspicious keywords, IOCs, auto-executable macros, etc. ct||_d|_d|_d|_d|_d|_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_dS)zg VBA_Scanner constructor :param vba_code: str, VBA source code to be analyzed r7N)rrcode_hex code_hex_rev code_rev_hex code_base64 code_dridexcode_vba strReverserautoexec_keywordssuspicious_keywordsiocs hex_stringsbase64_stringsdridex_strings vba_strings)rcrs r.r_zVBA_Scanner.__init__ s,H55    !%#'  ""r0Fc t|j|_d|_d|jvrd|_|jD]v\}}|xjd|zz c_|jrW|xjd|dddzz c_|xjdttj |dddzz c_wt|j|_ |j D]\}}|xj d|zz c_ t|j|_|jD]\}}|xjd|zz c_|rt#|j|_ng|_|jD]\}}|xjd|zz c_g}g|_g|_g|_|jdf|jdf|jdf|jd f|j d f|jd f|jd ffD]_\}}|xjt/||z c_|xjt1||z c_|xjt3||z c_`|jr|jd |j r|jd|jr|jd|jr|jdt7}|jD]6\} } | |vr-|d| | f|| 7t7}|jD]6\} } | |vr-|d| | f|| 7t7}|jD]6\} } | |vr-|d| | f|| 7|jD].\}}|st;|r|d||f/|j D].\}}|st;|r|d||f/|jD].\}}|st;|r|d||f/|jD].\}}|st;|r|d||f/||_|S)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 strreverseTrNriHexzHex+StrReversezStrReverse+HexBase64DridexzVBA expression)z Hex Stringsz`Hex-encoded strings were detected, may be used to obfuscate strings (option --decode to see all))zBase64 StringszcBase64-encoded strings were detected, may be used to obfuscate strings (option --decode to see all))zDridex StringszcDridex-encoded strings were detected, may be used to obfuscate strings (option --decode to see all))zVBA obfuscated StringszcVBA string expressions were detected, may be used to obfuscate strings (option --decode to see all)r SuspiciousIOCz Hex Stringz Base64 Stringz Dridex string VBA string)rrrbr^rrXrYrZrTrprrrcr[r3rdr\r:rer]r_r`rarrr rrrrr) rcinclude_decoded_strings deobfuscater9rrrr keyword_setrrrrs r.scanzVBA_Scanner.scan s.di88 49??,, , ,do $ 0 Y Y GW MMTG^ +MM Y!!TGDDbDM%99!!!!TIh6HQUQUSUQU6W6W,X,X%XX!!4DI>> $ 3 / / GW   w .   3DI>> $ 3 / / GW   w .     "1$)<*?*?A Ar0NFF)rgrhrirjr_rqrtr,r0r.rVrV sZ    4hhhhTAAAAAr0rVcHt|||S)av 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' )rVrq)rrnros r.scan_vbarwc s# x % %&={ K KKr0ceZdZdZdddedfdZdZdZdZd Z d Z d Z d Z d Z d#dZdZdZdZdZdZdZdZd#dZdZdZdZdZd$dZdZdZdZdZd Z d!Z!d"Z"dS)% VBA_ParserzZ Class to parse MS Office files, to detect VBA macros and extract VBA source code NTFc| |}d|_nt|}d|_d|_g|_||_||_||_d|_d|_d|_ d|_ d|_ d|_ d|_ d|_d|_d|_d|_d|_d|_d|_d|_d|_||_g|_d|_||_d|_d|_d|_d|_d|_tAj!|j||_"tF$d|j"j%j&d|j"jtOj(|r)|)||*|j)tWj,|r|-||j{|))n,,..N((44~7K7KG7T7TTUUXZZZ d###}TT::: )egkgtt #C(((u%% $ d###y WD%8%8t$$$ 9 ORVR__C HHSMMM$$ $  sG66G:=G:chtd|jz tj|d|_t |_dS#tttf$rM}td|jd|dt dd Yd}~dSd}~wwxYw) z| Open an OLE file :param _file: filename or file contents in a file object :return: nothing zOpening OLE file %sN) path_encodingzFailed OLE parsing for file rr3rTr) rWrrar OleFileIOrTYPE_OLErrrrr)rcrrEs r.rzVBA_Parser.open_ole s &6777 /#-e4HHHDM DIIIJ/ / / / HHHdmmmSSSQ R R R IIhI . . . . . . . . . /s'A B1$AB,,B1c td|jz tj|}|D]}td|||5}| ttj }|tj krtd|z||5}| }dddn #1swxYwY | ||n|#t$ro}|jrMt|d|dtdd Yd}~dddWt!|j||d}~wwxYwdddn #1swxYwY|t$|_dS#t$rc}|jrPtd ||jtdd nYd}~dSd}~wt(tjtjt.f$rM}td |jd |dtdd Yd}~dSd}~wwxYw)z Open an OpenXML file :param _file: filename or file contents in a file object :return: nothing zOpening ZIP/OpenXML file %szOpenXML subfile {}zOpening OLE file %s within zipNrarz is not a valid OLE file (r3rTrz4Error {0} caught in Zip/OpenXML parsing for file {1}z$Failed Zip/OpenXML parsing for file r)rWrrarZipFilenamelistrr:r<r rrMAGICappend_subfiler\rryclose TYPE_OpenXMLr RuntimeError BadZipfile LargeZipFiler)rcrzsubfilermagicole_datarEs r.rzVBA_Parser.open_openxml sp .>???E /&&A::<<1 >1 > .55g>>???VVG__/> (,,S-?-?@@E --< "BW"LMMMVVG__: '2'7'7'9'9H::::::::::::::: > //x/PPPP2>>>#|> #gggWZWZWZ)[ \ \ \ # (T B B B (Y/>/>/>/>/>/>/>\'99<'>'>!> >Q/>/>/>/>/>/>/>/>/>/>/>/>/>/>/>` GGIII$DIII"   | O &dm44666 (T 2222322222g0'2FP / / / HHH!]]]CCC1 2 2 2 IIhI . . . . . . . . .  /sA-G<A/G D! G !D% %G (D% )G -EG  F>AF9G  G<#F99F>>G  G< G G<G %G<< KAI$$*KAKKcHtd|jz tj|}|t D] }|td}tj |j }t|r t|}|||n#t$rr}|jrKtd||tddnt'|j||Yd}~d}~wwxYwtd |z t(|_dS#t$rV}|jrCtd |jd |d tddnYd}~dSd}~wt,$rM}td |jd |d tddYd}~dSd}~wwxYw) z| Open a Word 2003 XML file :param data: file contents in a string or bytes :return: nothing zOpening Word 2003 XML file %sz noname.msorError parsing subfile {0}: {1}rTrNz%s is not a valid MSO fileFailed XML parsing for file rr3)rWrraET fromstringiter TAG_BINDATAr ATTR_NAMErprutextrrrr\rr:rryTYPE_Word2003_XMLrr)rcretbindatafnamemso_datarrEs r.rzVBA_Parser.open_word2003xmlm sX 04=@AAA( /t$$B77;// C C I|<<#.w|<<x((C P#3H#=#=++U+JJJJ.PPP<PHH%E&,fUC&8&8:::IIhI>>>>"4T]E3"O"OO?>>>> PHH9EABBBB)DIII"   | $---QTQTQTUVVV (T 2222322222 / / / HHHdmmmSSSQ R R R IIhI . . . . . . . . .  /sQA4E,&C?E, D< A(D72E,7D<<.E,, H!6A G H!AHH!c Vtd|jz tj|}|t D]}|td}|td}|tkr| tD]} tj|j}|||4#t"$rr}|jrKtd||tddnt+|j||Yd}~d}~wwxYwt,|_dS#t"$rV}|jrCtd |jd |d tddnYd}~dSd}~wt0$rM}td |jd |d tddYd}~dSd}~wwxYw) 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 %sunknownrrrTrNrrr3)rWrrarrr TAG_PKGPARTr ATTR_PKG_NAMEATTR_PKG_CONTENTTYPECTYPE_VBAPROJECTiterfindTAG_PKGBINDATArprurrr\rr:rryTYPE_FlatOPC_XMLrr) rcrrpkgpartr content_typerrrEs r.rzVBA_Parser.open_flatopc s` ?$-OPPP" /t$$B77;// T T M9==&{{+?KK #333#*#3#3N#C#C T T T'/':7<'H'HH //X/NNNN2TTT#|T #)I*0&*<*<!>!>!> # (T B B B B&8s&S&S S!C B B B B T)DIII"   | $---QTQTQTUVVV (T 2222322222 / / / HHHdmmmSSSQ R R R IIhI . . . . . . . . .  /sQBE330C$#E3$ E .A(EE3E  E33 H(=A G H(AH##H(ctd|jz |d}|d}|d}d|cxkr|krnn ||d}n|dkr ||d}t jj}tj d}|t j_ trt j |}nt j |}|t j_n#|t j_wxYw| D]}|} |d} td| d | |d } t%| t&rt)| rtd  t+| } || | #t.$re} |jr=t| d| dtdd nt3|j| | Yd} ~ 2d} ~ wwxYwtdt5| z td| ddz#t6$r%}tdYd}~d}~wwxYwt8|_dS#t.$rt:$rJtd|jdt<tdd YdSwxYw)zt Open a MHTML file :param data: file contents in a string or bytes :return: nothing zOpening MHTML file %ss sMIMEsContentriNz)^(From |[\041-\071\073-\176]{1,}:?|[\t ])zMHTML part: filename=z, content-type=T)rQz4Found ActiveMime header, decompressing MSO containerrz$ does not contain a valid OLE file (r3rrztype(part_data) = %szpart_data[0:20] = %rrr6zpart_data has no __getitem__zFailed MIME parsing for file r;)rWrralstripfindemail feedparserheaderRErcompilerLmessage_from_stringmessage_from_byteswalkget_content_type get_filenamer get_payloadr>rrrrr\rryrr TYPE_MHTMLrMSG_OLEVBA_ISSUES)rcr stripped_data mime_offsetcontent_offset oldHeaderRE loosyHeaderREmhtmlrrr part_datarrEerrs r.rzVBA_Parser.open_mht s (4=8999G /!KK 33M(,,W55K*// ;;NK1111>11111 -kll ;  "$$ -noo >  *3KJ'STTM(5E  % 8D!5mDDEE"4]CCE,7 ))K )7777 B B#4466 ))$// ||\]]] ,,D,99 i//BK 4J4JBIITUUU P#3I#>#>++U+JJJJ.PPP<PHH).&5666IIhI>>>>#5T]E3"O"OO?>>>> PII4tIFGGGB "89QrT?"JKKKK$BBB "@AAAAAAAAB#DIII"     / / / HHH!]]],=,=? @ @ @ IIhI . . . . . . /sB K=0D5K=DB7K=&G98K=9 I(AI#K=#I((-K=%J=;K== K,K'!K='K,,K==AMMc6td tj|jd}|D]}|d|dtd|jd|_t|_ dS#tj tf$rT}|j dkrt dn#t d |zYd}~dSYd}~dSd}~wwxYw) 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) zCheck whether OLE file is PPTT) fast_failN PptParser)rz File is PPTzPPT subfile is not a PPT filez&File appears not to be a ppt file (%s))rWrr rr iter_vba_datarrTYPE_PPTrPptUnexpectedDatarrr)rcpptvba_datarEs r.rzVBA_Parser.open_ppt s3 0111 J&t}EEEC--// K K##D(k#JJJJ HH] # # # M   ! ! ! DM DIII,j9 J J J~,, 9:::: BSHIIIIIIIII;::::: JsBB..DADDc td|jzd}g}|d|dD]]}|drJ|dD]3}|drd}td4b|d ru|rs|dD]\}|d rE|d kr-|d t|d d z]|dr\|rZ|dD]D}|dr-|dt|d d zE_|rd|_ ||_ t|_ d S)z Open a SLK file, which may contain XLM/Excel 4 macros :param data: file contents in a bytes string :return: nothing zOpening SLK file %sFz8Formulas and XLM/Excel 4 macros extracted from SLK file:O;ETzSLK parser: found macro sheetsNNNzNamed cell: %srNCzFormula or Macro: %s)rWrrarrrrrrgrTrrTYPE_SLKr)rcrxlm_macro_foundrrrs r.rzVBA_Parser.open_slk5 s &6777 TUUUOOE** U UDt$$ UD))CCA||D))C*. "ABBBC'' UO UD))OOA||D))Oaggii5.@.@"))*:Yqu=M=M*MNNNO&& U? UD))UUA||D))U"))*@9QqrrUCSCS*STTT  )'+D $(DO r0ctd|jzt||_d|_t |_dS)z Open a text file containing VBA or VBScript source code :param data: file contents in a string or bytes :return: nothing zOpening text file %sTN)rWrrarTrr TYPE_TEXTr)rcrs r.rzVBA_Parser.open_textW sA '$-7888%.dOO!#'  r0c ~|jt||||j|j|jdS)zR Create sub-parser for given subfile/data and append to subfiles. )rrSrN)rrryrrSr)rcrarrs r.rzVBA_Parser.append_subfilef sX   HdI48L59]:>:L"N"N"N O O O O Or0ctd|j|jtkrdS|j|jS|jtkr^tdg|_|jD].}|j| /|jSd}g|_|j}| ddD]}td|z|d  d krtd d |zd |dd }|d kr|d z }td|z|||d}|s|||d}|s|||d}|std|z|j |||f|jS)aO 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 zVBA_Parser.find_vba_projectsN,Returned info is not complete for PPT types!c||z}||rE||tjkr"td|d||Std|zdS)NzFound z stream: z.check_vba_stream s| ;.Izz)$$ i)@)@GDX)X)X ;;; JKKK   X[ffgggur0FTstreamsstoragesChecking storage %rriVBAzFound VBA storage: %sr|r7zChecking vba_root="%s"PROJECTzVBA/_VBA_PROJECTzVBA/dirzVBA root storage: "%s")rWrrrrrrrrfind_vba_projectslistdirupperr@r) rcrr rstorager r[vba_project_pathr\s r.rzVBA_Parser.find_vba_projectso s*" 0111 = TY(%:%:4   ($ $ 9  KKF G G G "D , F F!(()B)B)D)DEEEE$ $    m{{54{@@ M MG II+g5 6 6 6r{  ""e++ 1SXXg5F5FGHHH88GCRCL11r>>OH 2X=>>> 0/XyII #-X#3#3CCU#V#V '1++C9EE) 2X=>>>!(((L()KLLL  r0cl|}d}|js|}|p|S)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_macrosrdetect_xlm_macros)rcrxlms r. detect_macroszVBA_Parser.detect_macros s?$$&&{ +((**C sr0c td|j|jS|jj|jD]Y}td||j|_|r d|_dSZd|_dS|}t|dkrd|_nd|_|j}tt|j D]}td|z|j |}|/| |}td|j tjkrtd |j|jfz ||j|j}td t|zt|d kr0t|dd d |ddn'tt+|d|vr!tdd|_#t,$rl}|jr?td|jztddnt3|j|j|Yd}~d}~wwxYw|jS)a 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 zdetect vba macrosNzole subfile {}TFrChecking DirEntry #%d$This DirEntry is an orphan or unusedz,Reading data from stream %r - size: %d bytesz Read %d bytesdz...[much more data]...is AttributzFound VBA compressed codez Error when reading OLE Stream %rr) exc_trace)rWrrrrr:rrrrr direntries_load_direntry entry_typerrrr_open isectStartr reprrrrryra)rc ole_subfilerrsiddrrEs r.rzVBA_Parser.detect_vba_macros s %&&&  # /+ + = #0   *11+>>???%)[ "0022 /3D,44 (-D $5--// |   ! !',D $ $'+D $m#cn--.. M MC II-3 4 4 4s#Ay&&s++ @AAA|w333 HAFTUTZK[[\\\M99Q\16::??AADIIoD 9:::4yy3 $tt***dSVSWSWjj"YZZZZ $t**---&$.. "=>>>370MMM|M!Caf!LMMM (d ;;;;0LLL<;;;;M4&''sC+J K9 A!K44K9ctd|j|jS|jtkr|jSg|_|js d|_dStra|j st dn? | S#t$rt dYnwxYw|jdS|S)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 zdetect xlm macrosNFzcXLMMacroDeobfuscator only works with files on disk, not in memory. Analysis might be less complete.z'Error when running XLMMacroDeobfuscator)rWrrrrrris_excelXLMDEOBFUSCATORr~r_extract_xlm_xlmdeobfrrr_extract_xlm_plugin_biffrss r.rzVBA_Parser.detect_xlm_macros! s %&&&  # /+ + 9 + +x  "" ',D $5  I$ I BCCCCI55777 IIIIIGHHHHHI = 5,,...sB''$C Cctddt_dg}tj|jddddd}t |dkr d|_dS||z }|d|d tj|jdddd }||z }t|||_ d|_dS) 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 macrosTzRAW EXCEL4/XLM MACRO FORMULAS:r)filenoninteractivenoindentreturn_deobfuscatedtimeout extract_onlyrFzL- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - z3EMULATION - DEOBFUSCATED EXCEL4/XLM MACRO FORMULAS:)r/r0r1r2r3) rWrxlmdeobfuscatorSILENT process_filerarrrr)rcrrs r.r,z VBA_Parser._extract_xlm_xlmdeobfI s QRRR!%/0 -4=:>48?C358< --- v;;!  ',D $5 v  9 HIII -4=:>48?C35 --- v  ##' tr0ctddD]}|j|rtd|z|j|}td t |g|d}||_dd |jvrtd t |g|d }|xj|z c_t |g|d }|xj|z c_t |g|d }|xj|z c_d |_ d S#t dtzYxYwd|_ dS)z Run plugin_biff to detect and extract XLM macros :return: bool, True if at least one macro worksheet has been found, False otherwise r-)WorkbookBookzFound Excel stream %rz Running BIFF plugin from oledumpz -o BOUNDSHEET)rstreamoptionszExcel 4.0 macro sheetrzFound XLM macrosz-o LABEL -r LNz-c -r LNz -o DCONN -sTz;Error when running oledump.plugin_biff, please report to %sF) rWrrrrr rAnalyzerr@rr_URL_OLEVBA_ISSUES)rc excel_streamr biff_plugins r.r-z#VBA_Parser._extract_xlm_plugin_biffp s ,---0 u uL}##L11 u 1L@AAA}// ==BBDD <===u#(l^DRa"b"b"bK&1&9&9&;&;DO.$))DO2L2LLL "4555&+,Vf&g&g&g ;+>+>+@+@@&+,V`&a&a&a ;+>+>+@+@@',,Vc&d&d&d ;+>+>+@+@@370#ttMuMM"_bs"sttttt1 u2$) us DF,,$GcZ|jrtj|j|_|jSr+)rr#rrss r.detect_is_encryptedzVBA_Parser.detect_is_encrypted s+ = C & 3DM B BD   r0cd}|rRtj}|r*t|tr||tj|j|}|Sr+)rBr#DEFAULT_PASSWORDSr>rArdecryptra)rcpasswords_listdecrypted_file passwordss r. decrypt_filezVBA_Parser.decrypt_file sj  # # % % F0I 1*^T"B"B 1  000#^DM9EENr0cL|j|S||jdS)a) 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 NrIrJ)rSrM)rc unicode_strs r. encode_stringzVBA_Parser.encode_string s- =  %%dmI%FF Fr0c #<Ktd|j|jtkr|jd|j|jfVdS|jtkr*|jr!d}|jD] }|d|zdzz }ddd|fVdSdS|j D]}| D]}|V|jr!d}|jD] }|d|zdzz }ddd|fVdSdS| t}|j D]\}}} t|j||||jD]@\} } }||j| |j| | |fVAf#t$$r$} tdYd} ~ d} ~ wwxYw|j} t)t+| jD]} td | z| |vrtd ?| j| }|/| | }td |jt2jkr\td |jz| |j|j}tAj!d |t@j"D]}|#dz }td|z||d} tItK|}tM|d}|j|j|j|fV#t$$rT}td|jd|jd|dtddYd}~d}~wwxYw|jrd}|jD] }|d|zdzz }ddd|fV|'r3d}|j()D] }|d|zdzz }ddd|fVdSdS)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 zextract_macros:Nr7z' r xlm_macroz xlm_macro.txtzError in _extract_vbarzAlready extractedrzReading data from stream %rs\x00Attribut[^e])flagsr3z%Found VBA compressed code at index %Xcp1252)rSzError processing stream z in file rr3 Traceback:Trz VBA P-codezVBA_P-code.txt)*rWrrrrrarrrrextract_macrosrrrrrr_findrr_rrr r!r"rrrr#r$rr rr IGNORECASErBrrrTdetect_vba_stompingrr)rcrrr&rvba_stream_idsr r[r\r vba_filenamerrr'r(rrrBcompressed_codevba_code_bytes vba_code_strrEs r.rRzVBA_Parser.extract_macros s& #$$$ = yI%%}b$-9RSSSSSSh&&?P!H $77 D4K$$66& _hOOOOOO PP$(#4&&K#.#=#=#?#?&&% &?P!H $77 D4K$$66& _hOOOOOO PP  " " $ $ $ UUN484E ; ;0, ;(,)14<AASS; \8'**4=+>+>{+K+KLLL#}k<RRRRR S !;;;MM"9::::::::;-Cc#.1122! C! C 1C7888.((II1222N3'9**3//AIIDEEE<7#777II;afDEEE99Q\16::??AAD!#-A4r}!]!]!]CC %  1 "IE"QRRR*.uvv,C->y?Y?Y-Z-ZN,5^h+W+W+WL#'=!&!&,"OOOOO(CCCIIIVWV\V\V\^b^k^k^kmpmpmp&qrrrIIlTIBBBBBBBBC  L O33Dt d 22HH"K(KKKK'')) O 0;;==33Dt d 22HH#\3CXNNNNNN  O Os3AE%% F/FFAM  N*A N%%N*c|jAg|_|D]%\}}}}|j||||f&t|j|_|jS)af 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) )r]rRrrr)rcr~rrWrs r.extract_all_macroszVBA_Parser.extract_all_macrosst < DLFJFYFYF[F[ X XBk< ##[+|X$VWWWWT\**|r0cd}|D]?\}}}}t|tstd7||dzz }@|S)aT 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 r7z7VBA code returned by extract_all_macros is not a stringr)r\r>r}rWr)rcrrArs r.get_vba_code_all_modulesz#VBA_Parser.get_vba_code_all_modules(sn "#'#:#:#<#< 8 8 Q1hh,, 8 STTTT$47$$##r0c|r>|j|jS|jG||_|D]\}}}|xj|dzz c_t |j}||||_|rWt dd}d}|j ||f|j d||f|j rWt dd}d }|j ||f|j d||f|jrWt d d }d }|j ||f|j d||f|\}} } } } } }|xj|z c_|xj| z c_|xj| z c_|xj| z c_|xj| z c_|xj| z c_|xj|z c_|jS) 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') Nrz*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 coderkz2adding XLM macrosheet found to suspicious keywordsz XLM macroz.XLM macro found. It may contain malicious codez0adding Template Injection to suspicious keywordszTemplate Injectionz^Template injection found. A malicious template could have been uploaded from a remote location)rrrr^extract_form_stringsrVrqrUrWrr`rrrrrtrrrrrrr)rcshow_decoded_stringsrorA form_stringscannerrrautoexec suspiciousra hexstrings base64stringsdridex vbastringss r.analyze_macroszVBA_Parser.analyze_macros:s     ( -$0,,(0,0,I,I,K,K)+/+D+D+F+FDD'Q;--t1CC---!$";<.wsSI]^_I`EaEar0T)rFreversermr6rSz"%s"rZr3z(%s))rjsortedrrrrIrendswith)rcanalysis deobf_codekw_typerr9s r.revealzVBA_Parser.revealrs&&E&BB((a(akoppp-T-FGG  ++ )1 B B %GWg,&&"//#t44 7*%%c**/w/?/?/D/D/$w.G'//AA r0c Jtd|j|jtkrdS|jtkr"|j}tdn|jg}g|_|D]%}|ddD] }td|z|dgz}|d gz}td |d |d | |r| |tj kr| |ro| |tj krLd |}td|z|j| '|jS)aK 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 zVBA_Parser.find_vba_formsNrFTr r rMfzChecking if streams z and z existr|zFound VBA Form: %r)rWrrrrrrrrrrrrr@r)rc ole_filesrro_streamf_stream form_paths r.find_vba_formszVBA_Parser.find_vba_formss" -... = TY(%:%:4$ 9 )I KKF G G G G)I 3 3C;;ut;DD 3 3 /'9:::"cU?"cU? 888XXXVWWW::h''3CLL,B,BgFZ,Z,ZJJx((-[-0\\(-C-CwG[-[-[ # 1 1III2Y>???N))'222 3~r0c#K|j9|jtkrdS|jD]}|D]}|VdS||j}|jD]}|dgz}tdd |z| | }t |D]}td|ztr|}n)|dd}|d kr|jd ||fVdS) a2 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 NrMzOpening form object stream %rr|z"Printable string found in form: %rr)rIrJTahoma)rrrrr`r{rrWrr@rr re_printable_stringrrrLrQra) rcr&rr form_storagerx form_datam found_strs r.r`zVBA_Parser.extract_form_stringss = yI%%$(#4&&K#.#C#C#E#E&&% &&&    ! ! !-C $ M M '3%/ 9CHHX.argsTFN)rgrhri disasmOnlyverboser,r0r.argsr7s! r0rzbefore pcodedmp) output_filezafter pcodedmpzError while running pcodedmp)rrrrrrWrrrrr:rZrLrrsysstderr processFilerar_getvalue)rcrroutputrrs r. extract_pcodezVBA_Parser.extract_pcode s 99- - -#%D 2   #%D 2   ' IIR S S S -------   @GGJJKKK')$rrrrr        $ "         > +,,,# $$T]Df$MMM#  *++++ > > > <========  >$*??#4#4D ##s1A B"#4BB"%A5E F %FF ctd|j|jS|jtt fvr d|_dS|js#tdd|_dS|jtd|tdt}|j D]}| drqtd| z|dd }|d }d }t|d kr|d  }|d vre| dr |dd}|dd d }| ds|||dkr|dd d }t|d krB|d dkr |ddksJ|d d}|dd}d|zdz}||tdt%t'|zd|_|}|D]V} | |vrPtd| tdd|_nW|jstd|jS)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 rUNFz see doc there N)r^rr_)rcrrdres r.r_zVBA_Parser_CLI.__init__s- -nd##,d=f=====r0Fctjr/tddtj|||dS)ap 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... r7rCNrstdoutisattyrNflushrjrcraros r. run_analysiszVBA_Parser_CLI.run_analysiss^ :      /r * * * * J      0+>>>>>r0c|j}|rtjdd}dddd}|D]u\}}}t|st |}t|st |}||d} ||||f| ddf v||jrtd dSdStd dS) a 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 ) r6-)TypeKeyword Description) column_width header_rowyellowredcyanrrkrlN)colorszVBA Stomping detection is experimental: please report any false positive/negative at https://github.com/decalage2/oletools/issuesz#No suspicious keyword or IOC found.) rr TableStreamrr%r write_rowrrrN) rcrarorrJ COLOR_TYPErsrr color_types r.print_analysiszVBA_Parser_CLI.print_analysiss;'  9'\3UWWWA%#J 29 ^ ^-+#G,,,"7mmG#K004"&{"3"3K'^^GT::  Wg{;ZQUW[D\ ]]]] GGIII) [Z[[[[[ [ [ 7 8 8 8 8 8r0ctjr/tddtjd|||DS)ax 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 rr7rc:g|]\}}}t|||S))rrr)r?)r;rsrrs r.r)z6VBA_Parser_CLI.print_analysis_json..sCmmm1GWk'7 LLLmmmr0rrs r.print_analysis_jsonz"VBA_Parser_CLI.print_analysis_jsonsz :      /r * * * * J     mm595H5HI]_j5k5kmmm mr0c |j}|rGdddd}|D]>\}}}||d}|r ||d|d|d|d}?|S) 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 rrrrNz{auto}z{/)rrrI)rcrrrrsrrrs r.colorize_keywordsz VBA_Parser_CLI.colorize_keywordss '  p$#J 29 p p-+'^^GT:: p'//jjjZaZaZacmcmcm9nooHr0Tc  ||_|r|sd}|jr|jd|j} n|j} tdtd| z td|jz|ri||||D]\} } } } |rt| }n| }tdtd| ztd | d t| |r td | d krtd d|vret dtjrt!jd}nd}|d|} tjr't!j||}n*#t($rtdYnwxYwt||D]J\} } }|Btdtd| d | td t|K |D]f\} } }|^tdtd|dd| d | td tt1|dgnP#t2$rC}td|ztddYd}~nd}~wwxYw|rAtdtd|}t||s||||r0tdt|ntdn#t>$rt2$ro}td|jd |d!tAj!tddtE|j|d}~wwxYwtd dS)"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===============================================================================zFILE: %szType: %srarozO-------------------------------------------------------------------------------z VBA MACRO %s z in file: z - OLE stream: zN- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - r7z (empty macro)r2z]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 outputNzVBA FORM STRING IN zVBA FORM Variable "rz" IN rzError parsing form: %srQrzP-CODE disassembly:zAMACRO SOURCE CODE WITH DEOBFUSCATED VBA STRINGS (EXPERIMENTAL): zNo VBA or XLM macros found.Error processing file rr3)#rrrarNrrrr\rr%rgrWrrrr colorclassColorrIr UnicodeErrorrr`rr}rrrrrrtr\ traceback print_excrr)rcra display_codehide_attributes vba_code_onlyshow_deobfuscated_codero show_pcoderdisplay_filenamer~rrWrvba_code_filtered backspacerbform_variablesrEpcodes r.r7zVBA_Parser_CLI.process_files)(   L > --1]]]DNNK  #}  h j++,,,[ 6 *di' ( ( (!!##P 5!!7KYd!eeeJNJaJaJcJc!5!5F[+|X&5,6x,@,@)),4)(OOO/L8999EKKKkIZIZIZ[\\\#5i(((,2244::!/2222 &)::: # -L!M!M!M#&:#4#4#6#6!80:0@AX0Y0YII07I4E4M4MfV_4`4` 1i$':#4#4#6#6!t8B8HI_I_`qIrIr8s8s$5#/iii # *g h h h h hi""3444?C?X?X?Z?Z++;[+{".h+++WbWbcdddi(((k*** ;FJFhFhFjFj@@Bk>)5!(OOO!EUcdjUkUkUkmxmxmx{F{F#GHHH!),,,!#nW&=">">??? @ !;;;HH5;<<<IIlTI::::::::;!(OOO/000 ..00E%LLL%K''(