zoukankan      html  css  js  c++  java
  • 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()
    

    有需要的可以自行拷贝

    不论你在什么时候开始,重要的是开始之后就不要停止。 不论你在什么时候结束,重要的是结束之后就不要悔恨。
  • 相关阅读:
    h.264并行解码算法2D-Wave实现(基于多核共享内存系统)
    h.264并行解码算法2D-Wave实现(基于多核非共享内存系统)
    h.264 去块滤波
    h.264并行解码算法分析
    phpstrom 快速定位到当前编辑文件
    省市区多级联动js代码
    原生js开发,无依赖、轻量级的现代浏览器图片懒加载插件,适合在移动端开发使用
    Let’s Encrypt 通配符证书,泛域名https证书申请配置
    js 获取链接参数的方法
    秒杀、抢购解决方案
  • 原文地址:https://www.cnblogs.com/yunhgu/p/14990775.html
Copyright © 2011-2022 走看看