
    jbk                         d dl Z d dlZd dlZd dlZd dlmZ ddlmZmZ ddl	m
Z
mZmZ  G d d          Z G d d	          Z G d
 d          Z G d d          Z G d d          Zd ZdededefdZdS )    N)Dict   )!extract_file_based_on_header_info(extract_all_files_from_central_directory)pretty_print_headersave_to_jsonsave_data_to_filec                   J    e Zd ZdZd Zed             Zd Zed             ZdS )EndOfCentralDirectoryRecordzO
    A class to provide details about the end of central directory record.
    c
                     || _         || _        || _        || _        || _        || _        || _        || _        |	| _        d S N		signaturenumber_of_this_disk#disk_where_central_directory_starts0number_of_central_directory_records_on_this_disk)total_number_of_central_directory_recordssize_of_central_directory$offset_of_start_of_central_directorycomment_lengthcomment)
selfr   r   r   r   r   r   r   r   r   s
             [/home/ubuntu/.hermes/hermes-agent/venv/lib/python3.11/site-packages/apkInspector/headers.py__init__z$EndOfCentralDirectoryRecord.__init__   sN     ##6 3V0@p=9b6)B&4X1,    c                    d}d}d}|                     dd          }||k     rrt          d||z
  |z
            }|                     |           |                    |          }|sn/|                    d          }|dk    r||z   }n||dz
  z  }||k     r|dk    rt	          d          |                     |           |                    d          }	t          j        d|                    d                    d         }
t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d	|                    d                    d         }t          j        d	|                    d                    d         }t          j        d|                    d                    d         }t          j        d
| d|                    |                    d                             dd          } | |	|
|||||||	  	        S )a  
        Method to locate the "end of central directory record signature" as the first step of the correct process of
        reading a ZIP archive. Should be noted that certain APKs do not follow the zip specification and declare multiple
        "end of central directory records". For this reason the search for the corresponding signature of the eocd starts
        from the end of the apk.

        :param apk_file: The already read/loaded data of the APK file e.g. with open('test.apk', 'rb') as apk_file
        :type apk_file: bytesIO
        :return: Returns the end of central directory record with all the information available if the corresponding signature is found. If not, then it returns None.
        :rtype: EndOfCentralDirectoryRecord or None
        i   r      s   PK   z:End of central directory record (EOCD) signature not found<H<I<sutf-8ignore)seekmaxreadrfind
ValueErrorstructunpackdecode)clsapk_file
chunk_sizeoffsetsignature_offset	file_sizepositionchunkeo_central_directory_offsetr   r   r   r   r   r   r   r   r   s                     r   parsez!EndOfCentralDirectoryRecord.parse   sm    
MM!Q''	y  1i&0:=>>HMM(###MM*--E ${{+>??2%%.69I.I+j1n$F y   r!!YZZZ1222MM!$$	$mD(--2B2BCCAF.4mD(--PQBRBR.S.STU.V+;A=x}}]^O_O_;`;`ab;c84:M$VWHXHX4Y4YZ[4\1$*M$a8H8H$I$I!$L!/5}T8==QRCSCS/T/TUV/W,tX]]1-=-=>>qA- 5N 5 5 5x}}^7T7TUUVWX__`giqrrs/<5%0

 

 
	
r   c           
      t    | j         | j        | j        | j        | j        | j        | j        | j        | j        d	S )t
        Represent the class as a dictionary.

        :return: returns the dictionary
        :rtype: dict
        r   r   r   s    r   to_dictz#EndOfCentralDirectoryRecord.to_dictT   sG     #'#;373[@D@u9=9g)-)G484]"1|

 

 
	
r   c                      | di |S )z
        Convert a dictionary back to an instance of the class.

        :param entry_dict: the dictionary
        :type entry_dict: dict
        :return: the instance of the class
        :rtype: EndOfCentralDirectoryRecord
         r=   r.   
entry_dicts     r   	from_dictz%EndOfCentralDirectoryRecord.from_dictg        s  Z   r   N)	__name__
__module____qualname____doc__r   classmethodr7   r;   r@   r=   r   r   r   r      ss            4
 4
 [4
l
 
 
& 	! 	! [	! 	! 	!r   r   c                   4    e Zd ZdZd Zd Zed             ZdS )CentralDirectoryEntryzC
    A class representing each entry in the central directory.
    c                    || _         || _        || _        || _        || _        || _        || _        || _        |	| _        |
| _	        || _
        || _        || _        || _        || _        || _        || _        || _        || _        || _        d S r   version_made_byversion_needed_to_extractgeneral_purpose_bit_flagcompression_methodfile_last_modification_timefile_last_modification_datecrc32_of_uncompressed_datacompressed_sizeuncompressed_sizefile_name_lengthextra_field_lengthfile_comment_lengthdisk_number_where_file_startsinternal_file_attributesexternal_file_attributes$relative_offset_of_local_file_headerfilenameextra_fieldfile_commentoffset_in_central_directory)r   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   s                        r   r   zCentralDirectoryEntry.__init__x   s      /)B&(@%"4+F(+F(*D'.!2 0"4#6 -J*(@%(@%4X1 &(+F(((r   c                 @   i d| j         d| j        d| j        d| j        d| j        d| j        d| j        d| j        d	| j        d
| j	        d| j
        d| j        d| j        d| j        d| j        d| j        d| j        | j        | j        | j        dS )r9   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   )r\   r]   r^   rJ   r:   s    r   r;   zCentralDirectoryEntry.to_dict   s)   
t3
')G
 '(E
 !$"9	

 *4+K
 *4+K
 )$*I
 t3
  !7
  5
 !$"9
 "4#;
 ,T-O
 '(E
 '(E
  3D4]!
" #
$  + -+/+K)
 
 
 	
r   c                      | di |S )z
        Convert a dictionary back to an instance of the class.

        :param entry_dict: the dictionary
        :type entry_dict: dict
        :return: the instance of the class
        :rtype: CentralDirectoryEntry
        r=   r=   r>   s     r   r@   zCentralDirectoryEntry.from_dict   rA   r   N)rB   rC   rD   rE   r   r;   rF   r@   r=   r   r   rH   rH   t   sZ         G G G6
 
 
< 	! 	! [	! 	! 	!r   rH   c                   R    e Zd ZdZd Zeddefd            Zd Zed             Z	dS )	CentralDirectoryz
    The CentralDirectory containing all the CentralDirectoryEntry entries discovered.
    The entries are listed as a dictionary where the filename is the key.
    c                     || _         d S r   entries)r   re   s     r   r   zCentralDirectory.__init__   s    r   Neocdc                 	   |st                               |          }|                    |j                   |                                |j        k    rt          d          i }	 |                                }|                    d          }|dk    rnt          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }	t          j        d|                    d                    d         }
t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d	| d
|                    |                    d         	                    dd          }t          j        d	| d
|                    |                    d         	                    dd          }t          j        d	| d
|                    |                    d         	                    dd          }|}t          ||||	|
|||||||||||||||          }|||j        <    | |          S )a  
        Method that is used to parse the central directory header according to the specification
        https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT
        based on the offset provided by the end of central directory record: eocd.offset_of_start_of_central_directory.

        :param apk_file: The already read/loaded data of the APK file e.g. with open('test.apk', 'rb') as apk_file
        :type apk_file: bytesIO
        :param eocd: End of central directory record
        :type eocd: EndOfCentralDirectoryRecord
        :return: Returns a dictionary with all the entries discovered. The filename of each entry is used as the key. Besides the fields defined by the specification, each entry has an additional field named 'Offset in the central directory header', which includes the offset of the entry in the central directory itself.
        :rtype: CentralDirectory
        zDFailed to find the offset for the central directory within the file!Tr   s   PKr    r   r   r!   r"   r#   r$   r%   )r   r7   r&   r   tellr*   r(   r+   r,   r-   rH   r[   )r.   r/   rf   central_directory_entriesc_offsetr   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   rX   rY   rZ   r[   r\   r]   r^   central_directory_entrys                              r   r7   zCentralDirectory.parse   s     	?.44X>>Dd?@@@==??dGGGdeee$&!"	b}}H a((I///$mD(--2B2BCCAFO(.dHMM!<L<L(M(Ma(P%'-}T8==;K;K'L'LQ'O$!'tX]]15E5E!F!Fq!I*0-hmmA>N>N*O*OPQ*R'*0-hmmA>N>N*O*OPQ*R')/tX]]1=M=M)N)Nq)Q&$mD(--2B2BCCAFO &dHMM!4D4D E Ea H%}T8==3C3CDDQG!'tX]]15E5E!F!Fq!I"(-hmmA6F6F"G"G"J,2M$a@P@P,Q,QRS,T)'-}T8==;K;K'L'LQ'O$'-}T8==;K;K'L'LQ'O$39=x}}UVGWGW3X3XYZ3[0}%<)9%<%<%<hmmL\>]>]^^_`ahhiprz{{H -(A,>(A(A(A8==QcCdCdeefghoopw  zB  C  CK!=)C-@)C)C)CX]]SfEgEghhijkrrsz  }E  F  FL*2'&;!:<TVh+-HJd!24DFXZm-/GIa4h\+' '# Kb%&=&FGE"	bH s,---r   c                 H    d | j                                         D             S )r9   c                 >    i | ]\  }}||                                 S r=   r;   .0r[   entrys      r   
<dictcomp>z,CentralDirectory.to_dict.<locals>.<dictcomp>  s&    VVVoh%--//VVVr   )re   itemsr:   s    r   r;   zCentralDirectory.to_dict  s'     WVASASAUAUVVVVr   c                     i }|                                 D ]$\  }}t                              |          }|||<   % | |          S )z
        Convert a dictionary back to an instance of the class.

        :param entry_dict: the dictionary
        :type entry_dict: dict
        :return: the instance of the class
        :rtype: CentralDirectory
        rd   )rs   rH   r@   )r.   r?   re   r[   
entry_dataentry_instances         r   r@   zCentralDirectory.from_dict
  s\     $.$4$4$6$6 	/ 	/ Hj2<<ZHHN .GHs7####r   r   )
rB   rC   rD   rE   r   rF   r   r7   r;   r@   r=   r   r   rb   rb      s            8. 8.#> 8. 8. 8. [8.tW W W $ $ [$ $ $r   rb   c                   P    e Zd ZdZd Zedefd            Zd Zed             Z	dS )LocalHeaderRecordz5
    The local header for each entry discovered.
    c                     || _         || _        || _        || _        || _        || _        || _        || _        |	| _        |
| _	        || _
        || _        d S r   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   r[   r\   )r   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   r[   r\   s                r   r   zLocalHeaderRecord.__init__  sj    
 *C&(@%"4+F(+F(*D'.!2 0"4 &r   entry_of_interestc                    |                     |j                   |                    d          }|dk    st          j        d           dS t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }	t          j        d|                    d                    d         }
t          j        d|                    d                    d         }t          j        d|                    d                    d         }t          j        d|                    d                    d         }	 t          j        d	| d
|                    |                    d                             dd          }t          j        d	| d
|                    |                    d                             dd          }n#  |j        }|j	        }Y nxY w | ||||||	|
|||||          S )ai  
        Method that attempts to read the local file header according to the specification https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT.

        :param apk_file: The already read/loaded data of the APK file e.g. with open('test.apk', 'rb') as apk_file
        :type apk_file: bytesIO
        :param entry_of_interest: The central directory header of the specific entry of interest
        :type entry_of_interest: CentralDirectoryEntry
        :return: Returns a dictionary with the local header information or None if it failed to find the header.
        :rtype: LocalHeaderRecord or None
        r   s   PKz0Does not seem to be the start of a local header!Nr    r   r   r!   r"   r#   r$   r%   )
r&   rZ   r(   loggingwarningr+   r,   r-   r[   r\   )r.   r/   r{   header_signaturerL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   r[   r\   s                   r   r7   zLocalHeaderRecord.parse1  s    	'LMMM#==++#666ONOOO4(.dHMM!<L<L(M(Ma(P%'-}T8==;K;K'L'LQ'O$!'tX]]15E5E!F!Fq!I*0-hmmA>N>N*O*OPQ*R'*0-hmmA>N>N*O*OPQ*R')/tX]]1=M=M)N)Nq)Q&$mD(--2B2BCCAFO &dHMM!4D4D E Ea H%}T8==3C3CDDQG!'tX]]15E5E!F!Fq!I<!=)@-=)@)@)@(--P`BaBabbcdellmtv~$m,E0B,E,E,Ex}}UgGhGhiijklsst{  ~F  G  G<,5/;s%'?AS')DF`.0@BTk	# # 	#s   BJ& &J8c                     | j         | j        | j        | j        | j        | j        | j        | j        | j        | j	        | j
        | j        dS )r9   rz   rz   r:   s    r   r;   zLocalHeaderRecord.to_dictZ  sZ     *.)G(,(E"&"9+/+K+/+K*.*I#3!%!7 $ 5"&"9+
 
 	
r   c                      | di |S )z
        Convert a dictionary back to an instance of the class.

        :param entry_dict: the dictionary
        :type entry_dict: dict
        :return: the instance of the class
        :rtype: LocalHeaderRecord
        r=   r=   r>   s     r   r@   zLocalHeaderRecord.from_dictp  rA   r   N)
rB   rC   rD   rE   r   rF   rH   r7   r;   r@   r=   r   r   rx   rx     s         ' ' '$ &#0E &# &# &# [&#P
 
 
, 	! 	! [	! 	! 	!r   rx   c                       e Zd ZdZdededeeef         fdZ	e
ddefd            Ze
	 	 ddedefd
            Zd Zd Zd ZddefdZdeeef         fdZd Zd Zd	S )ZipEntryz
    Is the actual APK represented as a composition of the previous classes, which are: the EndOfCentralDirectoryRecord, the CentralDirectory and a dictionary of values of LocalHeaderRecord.
    rf   central_directorylocal_headersc                 >    || _         || _        || _        || _        d S r   )ziprf   r   r   )r   	zip_bytesrf   r   r   s        r   r   zZipEntry.__init__  s&    	!2*r   Trawc                    |r|}nNt          |d          5 }t          j        |                                          }ddd           n# 1 swxY w Y   t                              |          }t                              ||          }i }|j        D ]4}t                              ||j        |                   }	|	r
|	||	j	        <   5 | ||||          S )a  
        Method to start processing an APK. The raw (bytes) APK may be passed or the path to it.

        :param inc_apk: the incoming apk, either path or bytes
        :type inc_apk: str or bytesIO
        :param raw: boolean flag to specify whether it is the raw apk in bytes or not
        :type raw: bool
        :return: returns the instance of the class
        :rtype: ZipEntry
        rbN)
openioBytesIOr(   r   r7   rb   re   rx   r[   )
r.   inc_apkr   r/   apkrf   r   r   rq   local_header_entrys
             r   r7   zZipEntry.parse  s     	2HHgt$$ 2:chhjj112 2 2 2 2 2 2 2 2 2 2 2 2 2 2*00::,228TBB&. 	P 	PE!2!8!8CTC\]bCc!d!d! P=O09:s8T#4mDDDs   'A		AANc                     |r|s5t                               |          }t                              ||          }|t                              ||j        |                   i} | ||||          S )a  
        Similar to parse, but instead of parsing the entire APK, it only targets the specified file.

        :param apk_file: The apk file expected raw
        :type apk_file: bytesIO
        :param filename: the filename of the file to be parsed
        :type filename: str
        :param eocd: Optionally, the instance of the end of central directory from the APK
        :type eocd: EndOfCentralDirectoryRecord(, optional)
        :param central_directory: Optionally, the instance of the central directory record
        :type central_directory: CentralDirectory(, optional)
        :return: returns the instance of the class
        :rtype: ZipEntry
        )r   r7   rb   rx   re   )r.   r/   r[   rf   r   local_headers         r   parse_singlezZipEntry.parse_single  s{    "  	G, 	G.44X>>D 0 6 6x F F "3"9"9(DUD]^fDg"h"his8T#4lCCCr   c                     | j                                         | j                                        d | j                                        D             dS )r9   c                 >    i | ]\  }}||                                 S r=   rn   ro   s      r   rr   z$ZipEntry.to_dict.<locals>.<dictcomp>  s&    jjjOHehjjjr   )end_of_central_directoryr   r   )rf   r;   r   r   rs   r:   s    r   r;   zZipEntry.to_dict  sV     )-	(9(9(;(;!%!7!?!?!A!AjjtOaOgOgOiOijjj
 
 	
r   c                     || j         j        v r$| j         j        |                                         S t          d| d          )aN  
        Method to retrieve the central directory entry for a specific filename.

        :param filename: the filename of the file to search for in the central directory
        :type filename: str
        :return: returns a dictionary of the central directory entry or None if the filename is not found
        :rtype: dict
        Key: z4 was not found within the central directory entries!)r   re   r;   KeyErrorr   r[   s     r    get_central_directory_entry_dictz)ZipEntry.get_central_directory_entry_dict  sL     t-555)1(;CCEEEa8aaabbbr   c                 x    || j         v r| j         |                                         S t          d| d          )a<  
        Method to retrieve the local header of a specific filename.

        :param filename: the filename of the entry to search for among the local headers
        :type filename: str
        :return: returns a ditionary of the local header entry or None if the filename is not found
        :rtype: dict
        r   z- was not found within the local headers list!)r   r;   r   r   s     r   get_local_header_dictzZipEntry.get_local_header_dict  sF     t)))%h/77999Z8ZZZ[[[r   Fsavec                     t          | j        |                     |          |                     |                    d         }|rt	          d| |           |S )a  
        Method to utilize the extract module and extract a single entry from the APK based on the filename.

        :param name: the name of the file to be read/extracted
        :type name: str
        :param save: boolean to define whether the extracted file should be saved as well or not
        :type save: bool(, optional)
        :return: returns the raw bytes of the filename that was extracted
        :rtype: bytes
        r   
EXTRACTED_)r   r   r   r   r	   )r   namer   extracted_files       r   r(   zZipEntry.read  sm     ;48TE_E_`dEeEe;?;`;`ae;f;fh hhik 	C1411>BBBr   returnc                     | j         j        S )z
        List of information about the entries in the central directory.

        :return: returns a dictionary where the keys are the filenames and the values are each an instance of the CentralDirectoryEntry
        :rtype: dict
        )r   re   r:   s    r   infolistzZipEntry.infolist  s     %--r   c                 H    d | j                                         D             S )z
        List of the filenames included in the central directory.

        :return: returns the list of the filenames
        :rtype: list
        c                     g | ]}|S r=   r=   )rp   vls     r   
<listcomp>z%ZipEntry.namelist.<locals>.<listcomp>  s    >>>r>>>r   )r   r;   r:   s    r   namelistzZipEntry.namelist  s'     ?>T3;;==>>>>r   c                    t           j                            ||          }t          | j        |                                 d         |                                 d         |          st          j        d|            dS dS )z
        Extracts all the contents of the APK.

        :param extract_path: where to extract it
        :type extract_path: str
        :param apk_name: the name of the apk
        :type apk_name: str
        r   r   zExtraction successful for: N)ospathjoinr   r   r;   r}   info)r   extract_pathapk_nameoutput_paths       r   extract_allzZipEntry.extract_all  s     gll<::7$,,..QdBe8<8WYdf f 	CLAxAABBBBB	C 	Cr   )T)NN)F)rB   rC   rD   rE   r   rb   r   strrx   r   rF   boolr7   r   r;   r   r   r(   rH   r   r   r   r=   r   r   r   r   }  se        +(C +Xh + $S*;%; <+ + + + E E E E E [E2 RV;?D D4O D(8D D D [D,
 
 
c c c\ \ \ t    ".$s$99: . . . .? ? ?C C C C Cr   r   c                    | r|st          j        d           dS t          d           | D ]h}|dk    s|dk    r?t          |ddt	          t          | |                              d| |                     Mt          |dd| |                     it          d	           |D ]}t          |dd||                     dS )
a  
    Prints out the details for both the central directory header and the local file header. Useful for the CLI.

    :param cd_h_of_file: central directory header of a filename as it may be retrieved from headers_of_filename
    :type cd_h_of_file: dict
    :param local_header_of_file: local header dictionary of a filename as it may be retrieved from headers_of_filename
    :type local_header_of_file: dict
    z!Are you sure the filename exists?NzCENTRAL DIRECTORYz$Relative offset of local file headerz&Offset in the central directory header40z : z | zLOCAL HEADER)r}   r   r   printhexint)cd_h_of_filelocal_header_of_fileks      r   print_headers_of_filenamer     s     3 8999+,,, 1 1666!?g:g:gQMMMc#l1o"6"677MMLOMMNNNNQ///l1o//0000'''! 5 5333.q13344445 5r   header_typeexportshowc                     |r)| D ]&}t          |           t          | |                    '|rt          | d| d|            dS dS )av  
    Print information for each entry for the central directory header and allow to possibly export to JSON.

    :param entries: The dictionary with all the entries for the central directory
    :type entries: dict
    :param apk_name: String with the name of the APK, so it can be used for the export.
    :type apk_name: str
    :param header_type: What type of header that is, either central_directory or local, to be used for the export
    :type header_type: str
    :param export: Boolean for exporting or not to JSON
    :type export: bool
    :param show: Boolean for printing or not the entries
    :type show: bool
    _z_header.jsonN)r   r   r   )re   r   r   r   r   rq   s         r   show_and_save_info_of_headersr   +  sz      " 	" 	"E&&&'%.!!!! G<<;<<<gFFFFFG Gr   )r   r}   r   r+   typingr   extractr   r   helpersr   r   r	   r   rH   rb   rx   r   r   r   r   r   r=   r   r   <module>r      s   				  				        ` ` ` ` ` ` ` ` I I I I I I I I I If! f! f! f! f! f! f! f!RG! G! G! G! G! G! G! G!TZ$ Z$ Z$ Z$ Z$ Z$ Z$ Z$z_! _! _! _! _! _! _! _!DTC TC TC TC TC TC TC TCn5 5 5.G# Gt G[_ G G G G G Gr   