• python使用pyinstaller打包后反解析


    """
    PyInstaller Extractor v1.9 (Supports pyinstaller 3.3, 3.2, 3.1, 3.0, 2.1, 2.0)
    Author : Extreme Coders
    E-mail : extremecoders(at)hotmail(dot)com
    Web    : https://0xec.blogspot.com
    Date   : 29-November-2017
    Url    : https://sourceforge.net/projects/pyinstallerextractor/
    
    For any suggestions, leave a comment on
    https://forum.tuts4you.com/topic/34455-pyinstaller-extractor/
    
    This script extracts a pyinstaller generated executable file.
    Pyinstaller installation is not needed. The script has it all.
    
    For best results, it is recommended to run this script in the
    same version of python as was used to create the executable.
    This is just to prevent unmarshalling errors(if any) while
    extracting the PYZ archive.
    
    Usage : Just copy this script to the directory where your exe resides
            and run the script with the exe file name as a parameter
    
    C:path	oexe>python pyinstxtractor.py <filename>
    $ /path/to/exe/python pyinstxtractor.py <filename>
    
    Licensed under GNU General Public License (GPL) v3.
    You are free to modify this source.
    
    CHANGELOG
    ================================================
    
    Version 1.1 (Jan 28, 2014)
    -------------------------------------------------
    - First Release
    - Supports only pyinstaller 2.0
    
    Version 1.2 (Sept 12, 2015)
    -------------------------------------------------
    - Added support for pyinstaller 2.1 and 3.0 dev
    - Cleaned up code
    - Script is now more verbose
    - Executable extracted within a dedicated sub-directory
    
    (Support for pyinstaller 3.0 dev is experimental)
    
    Version 1.3 (Dec 12, 2015)
    -------------------------------------------------
    - Added support for pyinstaller 3.0 final
    - Script is compatible with both python 2.x & 3.x (Thanks to Moritz Kroll @ Avira Operations GmbH & Co. KG)
    
    Version 1.4 (Jan 19, 2016)
    -------------------------------------------------
    - Fixed a bug when writing pyc files >= version 3.3 (Thanks to Daniello Alto: https://github.com/Djamana)
    
    Version 1.5 (March 1, 2016)
    -------------------------------------------------
    - Added support for pyinstaller 3.1 (Thanks to Berwyn Hoyt for reporting)
    
    Version 1.6 (Sept 5, 2016)
    -------------------------------------------------
    - Added support for pyinstaller 3.2
    - Extractor will use a random name while extracting unnamed files.
    - For encrypted pyz archives it will dump the contents as is. Previously, the tool would fail.
    
    Version 1.7 (March 13, 2017)
    -------------------------------------------------
    - Made the script compatible with python 2.6 (Thanks to Ross for reporting)
    
    Version 1.8 (April 28, 2017)
    -------------------------------------------------
    - Support for sub-directories in .pyz files (Thanks to Moritz Kroll @ Avira Operations GmbH & Co. KG)
    
    Version 1.9 (November 29, 2017)
    -------------------------------------------------
    - Added support for pyinstaller 3.3
    - Display the scripts which are run at entry (Thanks to Michael Gillespie @ malwarehunterteam for the feature request)
    
    """
    
    from __future__ import print_function
    import os
    import struct
    import marshal
    import zlib
    import sys
    import imp
    import types
    from uuid import uuid4 as uniquename
    
    
    class CTOCEntry:
        def __init__(self, position, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name):
            self.position = position
            self.cmprsdDataSize = cmprsdDataSize
            self.uncmprsdDataSize = uncmprsdDataSize
            self.cmprsFlag = cmprsFlag
            self.typeCmprsData = typeCmprsData
            self.name = name
    
    
    class PyInstArchive:
        PYINST20_COOKIE_SIZE = 24           # For pyinstaller 2.0
        PYINST21_COOKIE_SIZE = 24 + 64      # For pyinstaller 2.1+
        MAGIC = b'MEI1413121316'  # Magic number which identifies pyinstaller
    
        def __init__(self, path):
            self.filePath = path
    
    
        def open(self):
            try:
                self.fPtr = open(self.filePath, 'rb')
                self.fileSize = os.stat(self.filePath).st_size
            except:
                print('[*] Error: Could not open {0}'.format(self.filePath))
                return False
            return True
    
    
        def close(self):
            try:
                self.fPtr.close()
            except:
                pass
    
    
        def checkFile(self):
            print('[*] Processing {0}'.format(self.filePath))
            # Check if it is a 2.0 archive
            self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET)
            magicFromFile = self.fPtr.read(len(self.MAGIC))
    
            if magicFromFile == self.MAGIC:
                self.pyinstVer = 20     # pyinstaller 2.0
                print('[*] Pyinstaller version: 2.0')
                return True
    
            # Check for pyinstaller 2.1+ before bailing out
            self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET)
            magicFromFile = self.fPtr.read(len(self.MAGIC))
    
            if magicFromFile == self.MAGIC:
                print('[*] Pyinstaller version: 2.1+')
                self.pyinstVer = 21     # pyinstaller 2.1+
                return True
    
            print('[*] Error : Unsupported pyinstaller version or not a pyinstaller archive')
            return False
    
    
        def getCArchiveInfo(self):
            try:
                if self.pyinstVer == 20:
                    self.fPtr.seek(self.fileSize - self.PYINST20_COOKIE_SIZE, os.SEEK_SET)
    
                    # Read CArchive cookie
                    (magic, lengthofPackage, toc, tocLen, self.pyver) = 
                    struct.unpack('!8siiii', self.fPtr.read(self.PYINST20_COOKIE_SIZE))
    
                elif self.pyinstVer == 21:
                    self.fPtr.seek(self.fileSize - self.PYINST21_COOKIE_SIZE, os.SEEK_SET)
    
                    # Read CArchive cookie
                    (magic, lengthofPackage, toc, tocLen, self.pyver, pylibname) = 
                    struct.unpack('!8siiii64s', self.fPtr.read(self.PYINST21_COOKIE_SIZE))
    
            except:
                print('[*] Error : The file is not a pyinstaller archive')
                return False
    
            print('[*] Python version: {0}'.format(self.pyver))
    
            # Overlay is the data appended at the end of the PE
            self.overlaySize = lengthofPackage
            self.overlayPos = self.fileSize - self.overlaySize
            self.tableOfContentsPos = self.overlayPos + toc
            self.tableOfContentsSize = tocLen
    
            print('[*] Length of package: {0} bytes'.format(self.overlaySize))
            return True
    
    
        def parseTOC(self):
            # Go to the table of contents
            self.fPtr.seek(self.tableOfContentsPos, os.SEEK_SET)
    
            self.tocList = []
            parsedLen = 0
    
            # Parse table of contents
            while parsedLen < self.tableOfContentsSize:
                (entrySize, ) = struct.unpack('!i', self.fPtr.read(4))
                nameLen = struct.calcsize('!iiiiBc')
    
                (entryPos, cmprsdDataSize, uncmprsdDataSize, cmprsFlag, typeCmprsData, name) = 
                struct.unpack( 
                    '!iiiBc{0}s'.format(entrySize - nameLen), 
                    self.fPtr.read(entrySize - 4))
    
                name = name.decode('utf-8').rstrip('')
                if len(name) == 0:
                    name = str(uniquename())
                    print('[!] Warning: Found an unamed file in CArchive. Using random name {0}'.format(name))
    
                self.tocList.append( 
                                    CTOCEntry(                      
                                        self.overlayPos + entryPos, 
                                        cmprsdDataSize,             
                                        uncmprsdDataSize,           
                                        cmprsFlag,                  
                                        typeCmprsData,              
                                        name                        
                                    ))
    
                parsedLen += entrySize
            print('[*] Found {0} files in CArchive'.format(len(self.tocList)))
    
    
    
        def extractFiles(self):
            print('[*] Beginning extraction...please standby')
            extractionDir = os.path.join(os.getcwd(), os.path.basename(self.filePath) + '_extracted')
    
            if not os.path.exists(extractionDir):
                os.mkdir(extractionDir)
    
            os.chdir(extractionDir)
    
            for entry in self.tocList:
                basePath = os.path.dirname(entry.name)
                if basePath != '':
                    # Check if path exists, create if not
                    if not os.path.exists(basePath):
                        os.makedirs(basePath)
    
                self.fPtr.seek(entry.position, os.SEEK_SET)
                data = self.fPtr.read(entry.cmprsdDataSize)
    
                if entry.cmprsFlag == 1:
                    data = zlib.decompress(data)
                    # Malware may tamper with the uncompressed size
                    # Comment out the assertion in such a case
                    assert len(data) == entry.uncmprsdDataSize # Sanity Check
    
                with open(entry.name, 'wb') as f:
                    f.write(data)
    
                if entry.typeCmprsData == b's':
                	print('[+] Possible entry point: {0}'.format(entry.name))
    
                elif entry.typeCmprsData == b'z' or entry.typeCmprsData == b'Z':
                    self._extractPyz(entry.name)
    
    
        def _extractPyz(self, name):
            dirName =  name + '_extracted'
            # Create a directory for the contents of the pyz
            if not os.path.exists(dirName):
                os.mkdir(dirName)
    
            with open(name, 'rb') as f:
                pyzMagic = f.read(4)
                assert pyzMagic == b'PYZ' # Sanity Check
    
                pycHeader = f.read(4) # Python magic value
    
                if imp.get_magic() != pycHeader:
                    print('[!] Warning: The script is running in a different python version than the one used to build the executable')
                    print('    Run this script in Python{0} to prevent extraction errors(if any) during unmarshalling'.format(self.pyver))
    
                (tocPosition, ) = struct.unpack('!i', f.read(4))
                f.seek(tocPosition, os.SEEK_SET)
    
                try:
                    toc = marshal.load(f)
                except:
                    print('[!] Unmarshalling FAILED. Cannot extract {0}. Extracting remaining files.'.format(name))
                    return
    
                print('[*] Found {0} files in PYZ archive'.format(len(toc)))
    
                # From pyinstaller 3.1+ toc is a list of tuples
                if type(toc) == list:
                    toc = dict(toc)
    
                for key in toc.keys():
                    (ispkg, pos, length) = toc[key]
                    f.seek(pos, os.SEEK_SET)
    
                    fileName = key
                    try:
                        # for Python > 3.3 some keys are bytes object some are str object
                        fileName = key.decode('utf-8')
                    except:
                        pass
    
                    # Make sure destination directory exists, ensuring we keep inside dirName
                    destName = os.path.join(dirName, fileName.replace("..", "__"))
                    destDirName = os.path.dirname(destName)
                    if not os.path.exists(destDirName):
                        os.makedirs(destDirName)
    
                    try:
                        data = f.read(length)
                        data = zlib.decompress(data)
                    except:
                        print('[!] Error: Failed to decompress {0}, probably encrypted. Extracting as is.'.format(fileName))
                        open(destName + '.pyc.encrypted', 'wb').write(data)
                        continue
    
                    with open(destName + '.pyc', 'wb') as pycFile:
                        pycFile.write(pycHeader)      # Write pyc magic
                        pycFile.write(b'' * 4)      # Write timestamp
                        if self.pyver >= 33:
                            pycFile.write(b'' * 4)  # Size parameter added in Python 3.3
                        pycFile.write(data)
    
    
    def main():
        if len(sys.argv) < 2:
            print('[*] Usage: pyinstxtractor.py <filename>')
    
        else:
            arch = PyInstArchive(sys.argv[1])
            if arch.open():
                if arch.checkFile():
                    if arch.getCArchiveInfo():
                        arch.parseTOC()
                        arch.extractFiles()
                        arch.close()
                        print('[*] Successfully extracted pyinstaller archive: {0}'.format(sys.argv[1]))
                        print('')
                        print('You can now use a python decompiler on the pyc files within the extracted directory')
                        return
    
                arch.close()
    
    
    if __name__ == '__main__':
        main()
    

    有需要的可以自行拷贝

    不论你在什么时候开始,重要的是开始之后就不要停止。 不论你在什么时候结束,重要的是结束之后就不要悔恨。
  • 相关阅读:
    WeTest与腾讯安全联合推出小程序质量方案,助力私域流量2.0新增长
    【福利】腾讯WeTest专有云,限时开放招募体验官
    新官网 心体验,腾讯WeTest全新产品功能与解决方案发布!
    大会回顾丨游戏用户体验优化如何实践,看大咖怎么说(附PPT下载)
    【福利】腾讯WeTest专有云解决方案,限时开放招募体验官
    【干货分享】研效优化实践:AI算法助力深层BUG挖掘
    WeTest小程序质量专项方案推出,小程序异常监控内测招募中
    WeTest.net全球能力开放:锻造高品质产品,构建全球竞争力
    腾讯WeTest即将亮相MTSC2021中国互联网测试开发大会
    压测大师链路监控服务开放免费体验预约
  • 原文地址:https://www.cnblogs.com/yunhgu/p/14990775.html
Copyright © 2020-2023  润新知