Exemple #1
0
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)
def print_archive_items(executable):
    logger.info('PyInstaller bundle is "%s"', executable)

    path = os.path.join(os.path.basename(executable) + '_extracted')
    logger.info('Extracted bundle files to "%s"', path)
    makedirs(path, exist_ok=True)

    logger.info('Got items from PKG')
    arch = CArchiveReader(executable)
    pyzlist = []
    for toc in arch.toc:
        logger.debug('toc: %s', toc)
        dpos, dlen, ulen, flag, typcd, nm = toc
        if nm.endswith('.pyz') and typcd in ('z', 'Z'):
            pathnm = os.path.join(path, nm)
            makedirs(os.path.dirname(pathnm), exist_ok=True)
            with arch.lib:
                arch.lib.seek(arch.pkg_start + dpos)
                with open(pathnm, 'wb') as f:
                    f.write(arch.lib.read(dlen))
            pyzlist.append(pathnm)
        else:
            logger.info('    %s (%d)', nm, ulen)

    for pyz in pyzlist:
        logger.info('Got items from "%s"', pyz)
        arch = ZlibArchive(pyz)
        for name in arch.toc:
            logger.info('    %s', name)
def get_archive(name):
    if not stack:
        if name[-4:].lower() == '.pyz':
            return ZlibArchive(name)
        return CArchiveReader(name)
    parent = stack[-1][1]
    try:
        return parent.openEmbedded(name)
    except KeyError:
        return None
    except (ValueError, RuntimeError):
        ndx = parent.toc.find(name)
        dpos, dlen, ulen, flag, typcd, name = parent.toc[ndx]
        x, data = parent.extract(ndx)
        tempfilename = tempfile.mktemp()
        cleanup.append(tempfilename)
        open(tempfilename, 'wb').write(data)
        if typcd == 'z':
            return ZlibArchive(tempfilename)
        else:
            return CArchiveReader(tempfilename)
 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]
    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'))
Exemple #6
0
def repacker(executable, obfpath, entry=None):
    logger.info('Repack PyInstaller bundle "%s"', executable)

    obfpath = os.path.normpath(obfpath)
    logger.info('Obfuscated scripts in the path "%s"', obfpath)

    name, ext = os.path.splitext(os.path.basename(executable))
    entry = name if entry is None else entry
    logger.info('Entry script name: %s', entry)

    arch = CArchiveReader(executable)
    logic_toc = []

    obfentry = os.path.join(obfpath, entry + '.py')
    if not os.path.exists(obfentry):
        raise RuntimeError('No obfuscated script "%s" found', obfentry)

    path = os.path.join(name + '_extracted')
    logger.info('Extracted bundle files to "%s"', path)
    if not os.path.exists(path):
        os.makedirs(path)

    for item in arch.toc:
        logger.debug('toc: %s', item)
        dpos, dlen, ulen, flag, typcd, nm = item
        pathnm = os.path.join(path, nm)
        with arch.lib:
            arch.lib.seek(arch.pkg_start + dpos)
            with open(pathnm, 'wb') as f:
                f.write(arch.lib.read(dlen))

            if nm.endswith('.pyz') and typcd in ('z', 'Z'):
                logger.info('Extract pyz file "%s"', pathnm)
                repack_pyz(pathnm, obfpath)
                patched = 1
            elif name == nm:
                patched = 1
                pathnm = obfentry
            else:
                patched = 0
            logic_toc.append((patched, dlen, ulen, flag, typcd, nm, pathnm))

    append_runtime_files(logic_toc, obfpath)

    obfname = os.path.join(name + '_obf' + ext)
    shutil.copy2(executable, obfname)
    repack_exe(path, obfname, logic_toc, obfentry)
Exemple #7
0
def process_pyinstaller_archive(ctx):
    # 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(ctx.orig_prog)
    except:
        # Silence all PyInstaller exceptions here
        return
    logging.info("Opened PyInstaller archive!")

    with PyInstallHook(ctx.archive, pyi_ar) as h:
        h.process()
def repacker(executable, items):
    logger.info('Repack PyInstaller bundle "%s"', executable)

    name, ext = os.path.splitext(os.path.basename(executable))
    arch = CArchiveReader(executable)
    logic_toc = []

    path = os.path.join(name + '_extracted')
    logger.info('Extracted bundle files to "%s"', path)
    makedirs(path, exist_ok=True)

    for toc in arch.toc:
        logger.debug('toc: %s', toc)
        dpos, dlen, ulen, flag, typcd, nm = toc
        pathnm = os.path.join(path, nm)
        makedirs(os.path.dirname(pathnm), exist_ok=True)
        with arch.lib:
            arch.lib.seek(arch.pkg_start + dpos)
            with open(pathnm, 'wb') as f:
                f.write(arch.lib.read(dlen))

            if nm.endswith('.pyz') and typcd in ('z', 'Z'):
                logger.info('Extract pyz file "%s"', pathnm)
                patched = repack_pyz(pathnm, items)
            elif nm in items:
                patched = 1
                pathnm = items[nm]
            else:
                patched = 0
            logic_toc.append((patched, dlen, ulen, flag, typcd, nm, pathnm))

    output = os.path.join(name + '-patched' + ext)
    logger.info('Copy "%s" to "%s"', executable, output)
    shutil.copy2(executable, output)

    repack_exe(path, output, logic_toc)