
    Zir                        S r SSK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
Jr  SSKrSSKr\R                  R                  \R                  R!                  \R                  R#                  \5      5      5      r\R                  R                  \R                  R)                  \S5      5      r\\R                  ;  a  \R                  R-                  S\5        SSKJr  SSKJrJrJr  SSKJr  SS	KJ r   S
r!Sr"\RF                  \RH                  \RJ                  \RL                  \RN                  \RF                  S.r( " S S\RR                  5      r*\RN                  S-   4S jr+\+" S5      r,S r-\R\                  S   S::  a  Sr/OSr/\0r1Sr2Sr3Sr4\Rj                  " S5      r6\6Rn                  S:X  d   e\Rj                  " S5      r8\8Rn                  S:X  d   eSr9Sr:Sr;Sr<Sr=Sr>Sr?/ SQr@SrAS rBS! rCS" rDS# rES$ rFS% rG " S& S'\H5      rI " S( S)\H5      rJS* rKS+\A4S, jrLS- rMS. rN " S/ S0\	R                  5      rPS8S1 jrQS2 rRS3 rSS8S4 jrTS5 rUS8S6 jrV\WS7:X  a  \R                  " \V" 5       5        gg)9a_  
oleobj.py

oleobj is a Python script and module to parse OLE objects and files stored
into various MS Office file formats (doc, xls, ppt, docx, xlsx, pptx, etc)

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

oleobj is part of the python-oletools package:
http://www.decalage.info/python/oletools
    )print_functionN)
is_zipfile..)xglob)is_pptPptFilePptRecordExOleVbaActiveXAtom)	XmlParser)ensure_stdout_handles_unicodez0.60.1warning)debuginfor   errorcriticaldebug-olefilec                       \ rS rSrSrS rSrg)NullHandlerz   a  
Log Handler without output, to avoid printing messages if logging is not
configured by the main application.
Python 2.7 has logging.NullHandler, but this is necessary for 2.6:
see https://docs.python.org/2.6/library/logging.html section
configuring-logging-for-a-library
c                     g N )selfrecords     i/var/www/eduai.edurigo.com/question_generate/ques_gen_env/lib/python3.13/site-packages/oletools/oleobj.pyemitNullHandler.emit   s        r   N)__name__
__module____qualname____firstlineno____doc__r   __static_attributes__r   r   r   r   r   z   s    r   r      c                 (   U [         R                  R                  R                  ;   a)  [         R                  " U 5      nUR                  U5        U$ [         R                  " U 5      nUR                  [        5       5        UR                  U5        U$ )aR  
Create a suitable logger object for this module.
The goal is not to change settings of the root logger, to avoid getting
other modules' logs on the screen.
If a logger exists with same name, reuse it. (Else it would have duplicate
handlers and messages would be doubled.)
The level is set to CRITICAL+1 by default, to avoid any logging.
)loggingLoggermanager
loggerDict	getLoggersetLevel
addHandlerr   )namelevelloggers      r   
get_loggerr0      sr     w~~%%000 ""4(t$F km$
OOEMr   oleobjc                  J    [         R                  [        R                  5        g)z
Enable logging for this module (disabled by default).
This will set the module-specific logger level to NOTSET, which
means the main application controls the actual logging level.
N)logr+   r&   NOTSETr   r   r   enable_loggingr5      s     LL r       zJ{http://schemas.openxmlformats.org/package/2006/relationships}Relationshipz>{http://schemas.microsoft.com/office/2006/01/customui}customUIz>{http://schemas.microsoft.com/office/2009/07/customui}customUIz<L   z<Hi   i      )attachedTemplateexternalLinkexternalLinkPathexternalReferenceframe	hyperlinkofficeDocument	oleObjectpackageslideUpdateUrlslideMasterslideslideUpdateInfosubDocument	worksheet   d   c                     Uc*  [         R                  U R                  S5      5      S   nX!4$ [         R                  XUS-    5      S   nUS-  nX!4$ )a>  
Read an unsigned integer from the first 32 bits of data.

:param data: bytes string or stream containing the data to be extracted.
:param index: index to start reading from or None if data is stream.
:return: tuple (value, index) containing the read value (int),
         and the index to continue reading next time.
r8   r   )STRUCT_UINT32unpackreaddataindexvalues      r   read_uint32rS      a     }$$TYYq\215 > $$Ta%89!<
>r   c                     Uc*  [         R                  U R                  S5      5      S   nX!4$ [         R                  XUS-    5      S   nUS-  nX!4$ )aG  
Read an unsigned integer from the 16 bits of data following index.

:param data: bytes string or stream containing the data to be extracted.
:param index: index to start reading from or None if data is stream
:return: tuple (value, index) containing the read value (int),
         and the index to continue reading next time.
r6   r   )STRUCT_UINT16rM   rN   rO   s      r   read_uint16rW     rT   r   c                     [        X5      u  p!US:X  a  SU4$ Uc&  U R                  US-
  5      nU R                  S5      nOXX-   S-
   nXU-   S-
     nX-  nU[        :X  d   eX14$ )aU  
Read a length-prefixed ANSI string from data.

:param data: bytes string or stream containing the data to be extracted.
:param index: index in data where string size start or None if data is
              stream
:return: tuple (value, index) containing the read value (bytes string),
         and the index to start reading from next time.
r    r$   )rS   rN   	NULL_CHAR)rP   rQ   lengthansi_string	null_chars        r   read_length_prefixed_stringr^     s      ,MF{E{}iiq)IIaL	a0va(	 	!!!r   c                     S H:  n U R                  USS9n[        R                  SR                  X5      5        Us  $    [        R                  S5        U R                  SSS9$ ! [         a     Mp  f = f)zguess encoding of byte string to create unicode

Since this is used to decode path names from ole objects, prefer latin1
over utf* codecs if ascii is not enough
)asciilatin1utf8z	utf-16-leutf16strict)errorszdecoded using {0}: "{1}"zGfailed to guess encoding for string, falling back to ascii with replacer`   replace)decoder3   r   formatUnicodeErrorr   )rP   encodingresults      r   guess_encodingrl   1  s~     D	[[([;FII188JKM	 D KK % &;;wy;11	  		s   5A&&
A43A4c                 4   Uck  [        5       n[        [        5       HC  n[        U R	                  S5      5      nUS:X  a  [        U5      U4s  $ UR                  U5        ME     [        S5      eU R                  SX[        -   5      n[        XU 5      US-   4$ )aC  
Read a zero-terminated string from data

:param data: bytes string or stream containing an ansi string
:param index: index at which the string should start or None if data is
              stream
:return: tuple (unicode, index) containing the read string (unicode),
         and the index to start reading from next time.
r$   r   z&found no string-terminating zero-byte!    )		bytearrayxrangeSTR_MAX_LENordrN   rl   append
ValueErrorrQ   )rP   rQ   rk   _charend_idxs         r   read_zero_terminated_stringrx   C  s     }$Atyy|$Dqy%f-u44MM$	 %
 ABB**We;->?d12GAI==r   c                   0    \ rS rSrSrSrSrS	S jrS rSr	g)
OleNativeStreami_  z
OLE object contained into an OLENativeStream structure.
(see MS-OLEDS 2.3.6 OLENativeStream)

Filename and paths are decoded to unicode.
r$   r6   Nc                     SU l         SU l        SU l        SU l        SU l        SU l        SU l        SU l        X l        SU l	        SU l
        Ub  U R                  US9  gg)z
Constructor for OleNativeStream.
If bindata is provided, it will be parsed using the parse() method.

:param bindata: forwarded to parse, see docu there
:param package: bool, set to True when extracting from an OLE Package
                object
N)rP   )filenamesrc_pathunknown_shortunknown_long_1unknown_long_2	temp_pathactual_sizerP   rB   is_linkdata_is_streamparse)r   bindatarB   s      r   __init__OleNativeStream.__init__k  sm     !""	"JJGJ$ r   c                    [        US5      (       a
  SU l        SnO	SU l        SnU R                  (       dA  [        X5      u  U l        n[
        R                  SR                  U R                  5      5        [        X5      u  U l	        n[        X5      u  U l        n[        X5      u  U l        n[        X5      u  U l        n[        X5      u  U l        n[        X5      u  U l        n [        X5      u  U l        nU R                  (       a  Xl        OXX R                   -    U l        SU l        g! [&        [(        R*                  4 a-    [
        R                  S5        SU l        SU l        SU l         gf = f)a  
Parse binary data containing an OLENativeStream structure,
to extract the OLE object it contains.
(see MS-OLEDS 2.3.6 OLENativeStream)

:param data: bytes array or stream, containing OLENativeStream
             structure containing an OLE object
:return: None
rN   TNFr   z*OLE native data size = {0:08X} ({0} bytes)z$data is not embedded but only a link)hasattrr   rB   rS   native_data_sizer3   r   rh   rW   r~   rx   r|   r}   r   r   r   r   rP   r   IOErrorstructr   r   rP   rQ   s      r   r   OleNativeStream.parse  sN    4  "&DE"'DE ||+6t+C(D!5IIBvd3346 %0$<!E:4Gu:4Gu%0%="U%0%="U ;D H	&1$&>#De"" 	 u-=-='=>	 DL & 	II<=DL DDI		s   *AD2 2AE98E9)r   rP   r   r|   r   r   rB   r}   r   r   r   r~   NF
r   r   r    r!   r"   TYPE_LINKEDTYPE_EMBEDDEDr   r   r#   r   r   r   rz   rz   _  s     KM%.0r   rz   c                   0    \ rS rSrSrSrSrS	S jrS rSr	g)
	OleObjecti  z;
OLE 1.0 Object

see MS-OLEDS 2.2 OLE1.0 Format Structures
r$   r6   Nc                     SU l         SU l        SU l        SU l        SU l        SU l        SU l        Ub  U R                  U5        gg)a  
Constructor for OleObject.
If bindata is provided, it will be parsed using the parse() method.

:param bindata: bytes, OLE 1.0 Object structure containing OLE object

Note: Code can easily by generalized to work with byte streams instead
      of arrays just like in OleNativeStream.
N)ole_version	format_id
class_name
topic_name	item_namerP   	data_sizer   )r   r   s     r   r   OleObject.__init__  sM      	JJw r   c                 .   Sn[        X5      u  U l        n[        X5      u  U l        n[        R	                  SU R                  U R                  5        U R                  U R
                  U R                  4;   d   e[        X5      u  U l        n[        X5      u  U l	        n[        X5      u  U l
        n[        R	                  SU R                  U R                  U R                  5        U R                  U R
                  :X  a  [        X5      u  U l        n[        R	                  SU R                  [        U5      U-
  5        XX R                  -    U l        [        U R                  5      U R                  :X  d   eXU R                  -   S U l        gg)z
Parse binary data containing an OLE 1.0 Object structure,
to extract the OLE object it contains.
(see MS-OLEDS 2.2 OLE1.0 Format Structures)

:param data: bytes, OLE 1.0 Object structure containing an OLE object
:return:
r   z!OLE version=%08X - Format ID=%08Xz,Class name=%r - Topic name=%r - Item name=%rz)Declared data size=%d - remaining size=%dN)rS   r   r   r3   r   r   r   r^   r   r   r   r   lenrP   
extra_datar   s      r   r   OleObject.parse  sR    "-d":% +D 8		5""DNN	4~~$"4"4d6F6F!GGGG!<T!I!<T!I ;D H		@//4??DNN	D>>T/// %0$<!DNEIIAnnc$io7 5#78DItyy>T^^333"#7#89DO 0r   )r   rP   r   r   r   r   r   r   r   r   r   r   r   r   r     s     KM (!:r   r   c                     U(       d  U $ [        U 5      nX!:  a  U $ U R                  S5      nUS:X  a  U SU $ X#-
  nXA:  a  U SU $ U SX-
   XS -   $ )z@Create filename shorter than max_len, trying to preserve suffix..N)r   rfind)fnamemax_lenname_lenidx
suffix_lens        r   shorten_filenamer     sv     5zH
++c
C
byXgJXg $'$%d33r   ru   c                 6   [         R                  R                  U 5      R                  5       n[        R
                  " SX5      n[        U5      nSU;   a  UR                  SS5      nSU;   a  M  SU;   a  UR                  SS5      nSU;   a  M  [        XB5      $ )a  
Return filename that is save to work with.

Removes path components, replaces all non-whitelisted characters (so output
is always a pure-ascii string), replaces '..' and '  ' and shortens to
given max length, trying to preserve suffix.

Might return empty string
z[^a-zA-Z0-9._ -]r   r   z   )	ospathbasenamestripresubstrrf   r   )r|   replacementr   basepath
sane_fnames        r   sanitize_filenamer     s     ww)//1H+[CJZJ
*
''c2
 *
 *
''c2
 *
 J00r   c              #     #    / n/ nXU4 H  n[        UR                  S5      UR                  S5      5      nXxS-   S R                  5       n[        XsS9nU(       d  MT  UR                  S5      nUS:X  a  UR	                  U5        M~  U[        U5      S-
  :  a  UR	                  U5        M  UR	                  XxS 5        Uv   M     U H  nUv   M	     UR	                  S	5        [        [        5       HX  n	U HO  n
U[        U
5      -
  nUS:  a  M  S	R                  [        R                  " S
[        SU5      5      5      nX-   v   MQ     MZ     SU-  v   g7f)a  
Get some sane filenames out of path information, preserving file suffix.

Returns several canddiates, first with suffix, then without, then random
with suffix and finally one last attempt ignoring max_len using arg
`noname_index`.

In some malware examples, filename (on which we relied sofar exclusively
for this) is empty or " ", but src_path and tmp_path contain paths with
proper file names. Try to extract filename from any of those.

Preservation of suffix is especially important since that controls how
windoze treats the file.
/\r$   Nr   r   r      rY   abcdefghijklmnopqrstuvwxyz   zoleobj_%03d)maxr   r   r   rs   r   rangeMAX_FILENAME_ATTEMPTSjoinrandomsamplemin)r|   r}   tmp_pathr   noname_indexsuffixescandidates_without_suffix	candidater   ru   suffixleftover_lenr-   s                r   get_sane_embedded_filenamesr   '  sX      H "(3	)//#&	(=>!ef%++-	 &iA	 ooc""9%,,Y73y>!##%,,Y7 		$(/ 44 /	 / OOB()F"S[0La776==)E),R)>@ AD-  * ,
&&s   EEc              #   l  #    Sn [        U 5      nUR                  5        H  n[        UR                  5       5       H  u  p4[	        U[
        5      (       d  M  Sn [        UR                  5       5      nUS[        [        R                  5       [        R                  :w  a   Uc  Ml  UR                  5         M~  [        R                  SR                  UR                  U5      5        UR!                  5       nUv   Ub  UR                  5         M  M     M     Ub  UR                  5         gg! ["         aE    [        R%                  SR                  UR                  5      5        [        R                  SSS9   Nf = f! Ub  UR                  5         f f = f! Ub  UR                  5         f f = f7f)a  find ole streams in ppt

This may be a bit confusing: we get an ole file (or its name) as input and
as output we produce possibly several ole files. This is because the
data structure can be pretty nested:
A ppt file has many streams that consist of records. Some of these records
can contain data which contains data for another complete ole file (which
we yield). This embedded ole file can have several streams, one of which
can contain the actual embedded file we are looking for (caller will check
for these).
NzJFound record with embedded ole object in ppt (stream "{0}", record no {1})zCError reading data from {0} stream or interpreting it as OLE objectrY   Texc_info)r   iter_streams	enumerateiter_records
isinstancer	   nextiter_uncompressedr   olefileMAGICcloser3   r   rh   r-   get_data_as_olefiler   r   )r|   ppt_filestream
record_idxr   ole
data_starts          r   find_ole_in_pptr   f  s{     H8$++-F&/0C0C0E&F"
f&BCCC(%)&*B*B*D%E
%&9s7=='9:gmmK$ ?IIK 		 #F#)6&++z#BD %88:!	 ?IIK +) 'G .0 NN   # 5 %D%+VFKK%8: 		"t	4	5 ?IIK + NN  sh   F4AF F AD0$F )F ;AD0>F F40AE?<F>E??FFF F11F4c                   t   ^  \ rS rSrSrU 4S jrS rS rS rS r	SS jr
\R                  4S	 jrS
 rSrU =r$ )FakeFilei  al  create file-like object from data without copying it

BytesIO is what I would like to use but it copies all the data. This class
does not. On the downside: data can only be read and seeked, not written.

Assume that given data is bytes (str in py2, bytes in py3).

See also (and maybe can put into common file with):
ppt_record_parser.IterStream, ooxml.ZipSubFile
c                 d   > [         [        U ]  5         Xl        SU l        [        U5      U l        g)z&create FakeFile with given bytes data r   N)superr   r   rP   posr   size)r   rP   	__class__s     r   r   FakeFile.__init__  s'    h&(	I	r   c                     gNTr   r   s    r   readableFakeFile.readable      r   c                     gr   r   r   s    r   writableFakeFile.writable  s    r   c                     gr   r   r   s    r   seekableFakeFile.seekable  r   r   c                     [        [        U5      U R                  U R                  -
  5      nUS:X  a  gU R                  U R                  U R                  U-    USU& U =R                  U-  sl        U$ )zread into pre-allocated target r   N)r   r   r   r   rP   )r   targetn_datas      r   readintoFakeFile.readinto  s^    S[$))DHH"45Q;))DHHTXXf_=wFr   c                    U R                   U R                  :  a
  [        5       $ US:X  a  U R                  U R                   -
  nU R                  U R                   U R                   U-    nU =R                   U-  sl         U$ )zread and return data r   )r   r   bytesrP   )r   r   rk   s      r   rN   FakeFile.read  sa    88tyy 7NR<YY)F488DHHVO4Fr   c                 $   U[         R                  :X  a  UnObU[         R                  :X  a  U R                  U-   nO>U[         R                  :X  a  U R
                  U-   nO[        SR                  U5      5      eUS:  a  [        S5      eX0l        g)z!jump to another position in file z(invalid offset {0}, need SEEK_* constantr   z%Seek beyond start of file not allowedN)	ioSEEK_SETSEEK_CURr   SEEK_ENDr   rt   rh   r   )r   r   offsetnew_poss       r   seekFakeFile.seek  sx     R[[ Gr{{"hhnGr{{"ii#oGG$fVn. .Q;ABBr   c                     U R                   $ )z%tell where in file we are positioned )r   r   s    r   tellFakeFile.tell  s    xxr   )rP   r   r   )r   )r   r   r    r!   r"   r   r   r   r   r   rN   r   r   r  r  r#   __classcell__)r   s   @r   r   r     s>    	  "{{   r   r   c              #   &  #    Ub#  [         R                  S5        Un[        U5      nO[         R                  S5        U nU nSn [        R                  " U5      (       at  [        U5      (       a0  [         R                  SU -   5        [        U5       H	  nUv   SnM     [         R                  SU -   5        [        R                  " U5      nUv   GOGUc  [        U5      (       Ga
  Uc"  [        U5      nUR                  5        H  nM     [         R                  SU -   5        UR                  5        H  u  pvn UR                  [        [        R                  5      5      n	U	[        R                  :X  a]  UR%                  S5        [         R                  S	U-   5         [        R                  " U5      nUv   Ub  UR-                  5         SnM  M  [         R                  SU-   5        M     O)[         R)                  SR+                  U 5      5        Sv    Ub  UR-                  5         gg! [          a!    [         R#                  SU -   5        Sv    GM%  f = f! [&         a;    [         R)                  S
R+                  X5      5        [         R                  SSS9   Nf = f! Ub  UR-                  5         Snf f = f! [.         a*    [         R#                  SR+                  U 5      SS9  Sv    Nf = f! Ub  UR-                  5         f f = f7f)ztry to open somehow as zip/ole/rtf/... ; yield None if fail

If data is given, filename is (mostly) ignored.

yields embedded ole streams in form of OleFileIO.
Nz*working on data, file is not touched belowzworking on file by namezis ppt file: zis ole file: zis zip file: zzip is encrypted: r   z  unzipping ole: z@Error reading data from {0}/{1} or interpreting it as OLE objectrY   Tr   zunzip skip: z5open failed: {0} (or its data) is neither zip nor OLEzCaught exception opening {0})r3   r   r   r   	isOleFiler   r   r   	OleFileIOr   r
   iter_xmliter_non_xmlrN   r   r   RuntimeErrorr   r  r   r   rh   r   	Exception)
r|   rP   
xml_parserarg_for_olearg_for_zipr   ru   subfilefile_handleheads
             r   find_oler    s      			>?tn 			+,
C:[))k""834*;7CIC 8 HH_x/0##K0CI#z+'>'> !&{3
#,,.A / HH_x/0 ,6+B+B+D'K&++C,>?D 7==($$Q'HH07:;'%//<!	 ?IIK"&C + IInw671 ,E4 KKO)+J ?IIK ? $ II2X=>J # 5 %D%+VH%>@ 		"t	4	5 ?IIK"&C +  		077A 	 	!

 ?IIK s   ALBK K8 A'K <(H0$=K "I<5K 1K8 2(K K8 L0&IK IK AJ# J&"J##J&&J>>K 1K52K8 4K55K8 8LLc              #   (  #    U R                  SS[        5       H\  u  pn UR                  S   S:X  aB  UR                  S   R                  SS5      S   nU[        ;   a  X2R                  S   4v   MZ  M\  M^     g! [
        [        4 a     Mt  f = f7f)	zDiterate XML files looking for relationships to external objects
    NF
TargetModeExternalTyper   r$   Target)r  OOXML_RELATIONSHIP_TAGattribrsplitBLACKLISTED_RELATIONSHIP_TYPESAttributeErrorKeyError)r  ru   elemrelationship_types       r   find_external_relationshipsr&  '  s      !))$7MN
		{{<(J6$(KK$7$>$>sA$Fq$I!$(FF+[[-BBB G 7 O ) 	 	s)   BAA;2	B;BBBBc              #      #    U R                  SS[        [        45       H   u  pnUR                  S5      nUc  M  Uv   M"     g7f)a\  
iterate XML files looking for customUI to external objects or VBA macros
Examples of malicious usage, to load an external document or trigger a VBA macro:
https://www.trellix.com/en-us/about/newsroom/stories/threat-labs/prime-ministers-office-compromised.html
https://www.netero1010-securitylab.com/evasion/execution-of-remote-vba-script-in-excel
NFonLoad)r  TAG_CUSTOMUI_2007TAG_CUSTOMUI_2010get)r  ru   r$  customui_onloads       r   find_customUIr-  7  sF      !))$8IK\7]^
(+

%!! _s
   6A	Ac                 n	   [        U [        S-
  S9=(       d    SnU(       ap  [        R                  R	                  U5      (       d,  [
        R                  SU5        [        R                  " U5        [        R                  R                  X#5      nO>[        R                  R                  U 5      n[        R                  R                  XS5      n[        S5        [        SU -  5        SnSnSnSn	S	n
[        U 5      (       a  [
        R                  S
5        [        U 5      n
[        U
5       H=  u  pSn	[        SU< SU< 35        UR                  S5      (       d  M2  [        S5        M?     [        U
5       H  nSn	[        SU-  5        M     [!        XU
5       GHq  nUc  M	  UR#                  5        GHS  nSR                  U5      n[
        R%                  SU5        US   R'                  5       S:X  d  MD  S	n UR)                  U5      n[        SU-  5        [        S5        [+        U5      nUR2                  (       a  [
        R%                  S5        M  [        SUR4                  -  5        [        SUR6                  -  5        [        SUR8                  -  5        [;        UR4                  UR6                  UR8                  [        [=        U5      -
  S-
  U5       H1  nUS-   U-   n[        R                  R?                  U5      (       a  M1    O    [        SW-  5        [A        US5       nSn[C        [D        URF                  5      nU(       a  URI                  U5      nURK                  U5        U[=        U5      -  n[=        U5      U:w  a/  [
        R/                  S RM                  U[=        U5      5      5        O&[C        [D        URF                  U-
  5      nU(       a  M  S	S	S	5        Sn	UR1                  5         US-  nGMV     GMt     XxU	4$ ! [,         a/    [
        R/                  S5        SnUb  UR1                  5          GM  f = f! , (       d  f       No= f! [,         a1  n[
        R/                  S!RM                  WU5      5        Sn S	nANS	nAff = f! UR1                  5         f = f)"aE  find embedded objects in given file

if data is given (from xglob for encrypted zip files), then filename is
not used for reading. If not (usual case), then data is read from filename
on demand.

If output_dir is given and does not exist, it is created. If it is not
given, data is saved to same directory as the input file.
r   r   NONAMEzcreating output directory %szO-------------------------------------------------------------------------------zFile: %rr$   FNzJfile could be an OOXML file, looking for relationships with external linksTzFound relationship 'z' with external link zmhtml:z$Potential exploit for CVE-2021-40444zZFound customUI tag with external link or VBA macro %s (possibly exploiting CVE-2021-42292)r   zChecking stream %rr   zole10nativez3extract file embedded in OLE object from stream %r:zParsing OLE Packagez*** Not an OLE 1.0 Objectz0Object is not embedded but only linked to - skipzFilename = "%s"zSource path = "%s"zTemp path = "%s"ru   zsaving to file %swbr   zWanted to read {0}, got {1}zerror dumping to {0} ({1}))'r   MAX_FILENAME_LENGTHr   r   isdirr3   r   mkdirr   dirnameprintr   r
   r&  
startswithr-  r  listdirr   lower
openstreamrz   r  r   r   r   r|   r}   r   r   r   isfileopenr   DUMP_CHUNK_SIZEr   rN   writerh   )r|   rP   
output_dirr   fname_prefixbase_dirrQ   
err_streamerr_dumpingdid_dumpr  relationshipr   r   
path_partsstream_pathr   opkgembedded_fnamer   writern_dumped	next_sizeexcs                           r   process_filerM  D  s    #85H5JK  ww}}Z((HH3Z@HHZ ww||J;77??8,ww||H9 
&M	*x
 E JKHJ( " 	#x(
$?
$K LH\SYZ[  **<=	 %L
 $J/FHnqwwx 0 
3;++-J((:.KII*K8"~##%):: ^^J7FO'( )/0*62D <<II ' ((4==89+dmm;<)DNN:;&At}}dnn+c*o=A5'JN )3.?E77>>%00'J#-56eT*f#$$'9I9I$J	'#);;y#9D"LL.$D	1H"4yI5 #,I-3VIs4y-I!K %(+O,0,<,<x,G)II (i +  $H LLN
u (	 4~ H,,_ ! KK ;<!%J)2 +* ! 'KK <!'s!35"&K'
 LLNsU   =5PQ$2B6Q*
Q$4QQ
Q!Q$$
R.'RR"RR""R4c                     [         R                  R                  U 5      (       d%  [        R                  " SR                  U 5      5      eU $ )z;called by argument parser to see whether given file exists z{0} is not a file.)r   r   r:  argparseArgumentTypeErrorrh   )r|   s    r   existing_filerQ    s7    77>>(##(()=)D)DX)NOOOr   c           	         [        5         [        S[        -  5        [        S5        [        S5        [        S5        Sn[        R                  " US9nUR                  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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(9  UR                  S)S*SS+S,9  UR                  U 5      nUR                  (       a   U=R                  UR                  /-  sl        UR                  (       a  S-Ul        UR                  (       d  UR                  5         [        $ [         R"                  " [$        UR                     [&        R(                  S.S/9  [*        R-                  [         R.                  5        UR                  S0:X  a  [0        R2                  " 5         S1nS1nS1n[4        R6                  " UR                  UR8                  UR:                  UR<                  S29 HJ  u  pxn	U(       a  UR?                  S35      (       a  M%  [A        XURB                  5      u  pnXJ-  nX[-  nXl-  nML     [D        nU(       a	  U[F        -  nU(       a	  U[H        -  nU(       a	  U[J        -  nU$ )4zmain function, called when running this as script

Per default (cmd_line_args=None) uses sys.argv. For testing, however, can
provide other arguments.
z)oleobj %s - http://decalage.info/oletoolsz3THIS IS WORK IN PROGRESS - Check updates regularly!zGPlease report any issue at https://github.com/decalage2/oletools/issuesrY   z4usage: %(prog)s [options] <filename> [filename2 ...])usagez-r
store_true	recursivez)find files recursively in subdirectories.)actiondesthelpz-dr>  Nz(use specified directory to output files.)typerW  defaultrX  z-zz--zipzip_passwordziif the file is a zip archive, open first file from it, using the provided password (requires Python 2.6+))rW  rY  rZ  rX  z-fz
--zipfname	zip_fname*zoif the file is a zip archive, file(s) to be opened within the zip. Wildcards * and ? are supported. (default:*)z-lz
--loglevelloglevelstorezElogging level debug/info/warning/error/critical (default=%(default)s))rW  rV  rZ  rX  inputFILEz"Office files to parse (same as -i))nargsrY  metavarrX  z-iz--more-inputz7Additional file to parse (same as positional arguments))rY  rc  rX  z-vz	--verbosez2verbose mode, set logging to DEBUG (overwrites -l))rV  rX  r   z%(levelname)-8s %(message)s)r.   r   rh   r   F)rU  r[  r\  r   )&r   r5  __version__rO  ArgumentParseradd_argumentr   DEFAULT_LOG_LEVELrQ  
parse_args
more_inputr`  verboser^  
print_helpRETURN_ERR_ARGSr&   basicConfig
LOG_LEVELSsysstdoutr3   r+   r4   r   r5   r   
iter_filesrU  r[  r\  endswithrM  r>  RETURN_NO_DUMPRETURN_DID_DUMPRETURN_ERR_STREAMRETURN_ERR_DUMP)cmd_line_argsrS  parseroptionsany_err_streamany_err_dumpingany_did_dump	containerr|   rP   rA  rB  rC  
return_vals                 r   mainr    s    "#	
5
CD	
?@	 9 :	"IBE$$51F
 \H  J
3\4G  I
gN $,  -
 l3 #6  7
 lG 15  6 sA  C n3*  + k,/  0 .G',,//" ==
 j)9)9:3::<> LL ?*  NOL W]]g6G6G*1*>*>'.'8'8: 	"	T
 **3//););< 	*
$& :  Jo%
''
o%
r   __main__r   )Yr"   
__future__r   r&   r   rO  r   r   ro  r   zipfiler   r   r   r   normpathabspathr4  __file___thismodule_dirr   _parent_dirinsertoletools.thirdpartyr   oletools.ppt_record_parserr   r   r	   oletools.ooxmlr
   oletools.common.io_encodingr   rd  rg  DEBUGINFOWARNINGERRORCRITICALrn  Handlerr   r0   r3   r5   version_inforZ   r   rp   r  r)  r*  StructrL   r   rV   rq   r<  rs  rt  rl  ru  rv  r!  r1  r   rS   rW   r^   rl   rx   objectrz   r   r   r   r   r   	RawIOBaser   r  r&  r-  rM  rQ  r  r   exitr   r   r   <module>r     s  T &    	 	 
 	    ''""277??277??83L#MNggrww||OTBCchhHHOOA{# %F F $ E& (  !--!,,!//!--!**&}}.
	'// 	 #++A- 8 ! A!I IFe T T 
 d#Q  d#Q     " &    
"" 82$>8Sf SlA: A:H4* -0112<'~(VAr|| AHOd 
"q-n`F zHHTV r   