예제 #1
0
파일: pyinstaller.py 프로젝트: d42/staticx
def process_pyinstaller_archive(ar, prog):
    # See utils/cliutils/archive_viewer.py

    # If PyInstaller is not installed, do nothing
    try:
        from PyInstaller.archive.readers import CArchiveReader, NotAnArchiveError
    except ImportError:
        return

    # Attempt to open the program as PyInstaller archive
    try:
        pyi_ar = CArchiveReader(prog)
    except:
        # Silence all PyInstaller exceptions here
        return
    logging.info("Opened PyInstaller archive!")

    # Create a temporary directory
    # TODO PY3: Use tempfile.TemporaryDirectory and cleanup()
    tmpdir = tempfile.mkdtemp(prefix='staticx-pyi-')

    try:
        # Process the archive, looking at all shared libs
        for n, item in enumerate(pyi_ar.toc.data):
            (dpos, dlen, ulen, flag, typcd, name) = item

            # Only process binary files
            # See xformdict in PyInstaller.building.api.PKG
            if typcd != 'b':
                continue

            # Extract it to a temporary location
            x, data = pyi_ar.extract(n)
            tmppath = os.path.join(tmpdir, name)
            directory = os.path.dirname(tmppath)
            if not os.path.exists(directory):
                os.makedirs(directory)
            logging.debug("Extracting to {}".format(tmppath))
            with open(tmppath, 'wb') as f:
                f.write(data)

            # Silence "you do not have execution permission" warning from ldd
            make_executable(tmppath)

            # Add any missing libraries to our archive
            for libpath in get_shobj_deps(tmppath):
                lib = os.path.basename(libpath)

                if lib in ar.libraries:
                    logging.debug("{} already in staticx archive".format(lib))
                    continue

                if pyi_ar.toc.find(lib) != -1:
                    logging.debug(
                        "{} already in pyinstaller archive".format(lib))
                    continue

                ar.add_library(libpath)
    finally:
        shutil.rmtree(tmpdir)
예제 #2
0
 def extract_pyc_header(self, arch: CArchiveReader) -> bytes:
     ndx = arch.toc.find('pyimod01_os_path')
     x, data = arch.extract(ndx)
     with io.BytesIO(data) as buffer:
         buffer.seek(0)
         float_version, _, _, _, _, _, _ = load_module_from_file_object(
             buffer)
     if float_version >= 3.7:
         return data[:16]
     if float_version >= 3.3:
         return data[:12]
     return data[:8]
예제 #3
0
    def extract_to(self, extracted_dir: Path):
        extracted_dir.mkdir(parents=True, exist_ok=True)

        arch = CArchiveReader(self.path)
        pyc_header = self.extract_pyc_header(arch)

        for dpos, dlen, ulen, flag, typcd, nm in arch.toc.data:
            ndx = arch.toc.find(nm)
            x, data = arch.extract(ndx)
            """
            'm': 'PYMODULE',
            's': 'PYSOURCE',
            'b': 'EXTENSION',
            'z': 'PYZ',
            'a': 'PKG',
            'x': 'DATA',
            'b': 'BINARY',
            'Z': 'ZIPFILE',
            'b': 'EXECUTABLE',
            'd': 'DEPENDENCY',
            'o': 'OPTION',
            """
            name = nm
            if typcd in ('s', 'm'):
                name += '.pyc'

            print(name)
            file_path = extracted_dir / name
            file_path.parent.mkdir(parents=True, exist_ok=True)
            with (file_path).open('wb+') as fp:
                if typcd == 's':
                    fp.write(pyc_header)
                fp.write(data)

                if typcd in ('s', 'm'):
                    self.extract_source(fp, extracted_dir / (nm + '.py'))