← retour aux outils back to tools

# PyInstaller Extractor

Extrait le contenu (bytecode compilé, modules embarqués) d'un exécutable généré par PyInstaller, utilisé pour rétro-analyser des malwares écrits en Python. Extracts the contents (compiled bytecode, embedded modules) of a PyInstaller-generated executable, used to reverse Python-based malware.

↗ https://github.com/extremecoders-re/pyinstxtractor

## Overview

pyinstxtractor unpacks executables built with PyInstaller — a common way to bundle a Python script and interpreter into a single standalone Windows/Linux binary — recovering the original `.pyc` bytecode files and bundled modules. This is a frequent first step when analyzing Python-based malware or commodity RATs distributed as PyInstaller EXEs, since the compiled `.pyc` files can then be decompiled back to readable Python source.

## Common Usage

Extract a PyInstaller executable’s contents

    python pyinstxtractor.py malware.exe

Output goes into a directory named _extracted/

    ls malware.exe_extracted/

## Full Analysis Workflow

Step 1: Extract the PyInstaller archive

    python pyinstxtractor.py sample.exe

→ -> creates sample.exe_extracted/ containing .pyc files, DLLs, and PYZ-extracted modules

    # Step 2: Identify the Python version used (needed for accurate decompilation)
    # pyinstxtractor prints this during extraction, e.g. "Python version: 3.9"

Step 3: Fix the .pyc header if needed (pyinstxtractor output sometimes lacks the magic number header expected by decompilers) and decompile

    python pycdc.py sample.exe_extracted/sample.pyc > sample_decompiled.py

Step 4: Review the recovered source for C2 URLs, persistence mechanisms, etc.

    grep -Ei "http|socket|exec|eval" sample_decompiled.py

## Tips

- The extracted main script is usually named after the original entry-point script referenced in the PyInstaller build (visible in the extraction log).
- Match the recovered `.pyc` magic number/Python version to the correct decompiler (`uncompyle6`/`decompyle3` for Python ≤3.8, `pycdc`/`pylingual` for newer versions) — mismatches produce garbled output.
- PYZ-packed modules (the compressed archive of stdlib/third-party imports) are extracted alongside the main script and are worth scanning too — malware sometimes hides logic in a bundled “helper” module rather than the entry point.

Help / Man page

    usage: pyinstxtractor.py [-h] filename

    PyInstaller Extractor - extracts a PyInstaller generated executable

    positional arguments:
      filename    the PyInstaller executable to extract

    optional arguments:
      -h, --help  show this help message and exit

    Output:
      Creates a directory <filename>_extracted/ containing:
        - the main script's compiled bytecode (.pyc, header may need fixing)
        - PYZ-00.pyz_extracted/  (bundled Python modules, auto-extracted)
        - bundled shared libraries / DLLs
        - struct.pyc            (used internally to help fix pyc headers)

    Prints detected Python version and PyInstaller version during extraction.

## Vue d’ensemble

pyinstxtractor décompacte les exécutables construits avec PyInstaller, une méthode courante pour empaqueter un script Python et son interpréteur en un seul binaire autonome Windows/Linux, en récupérant les fichiers bytecode `.pyc` d’origine et les modules embarqués. C’est souvent la première étape lors de l’analyse de malwares en Python ou de RATs commodity distribués sous forme d’exécutables PyInstaller, puisque les fichiers `.pyc` compilés peuvent ensuite être décompilés pour retrouver un code source Python lisible.

## Utilisation courante

    # Extraire le contenu d'un exécutable PyInstaller
    python pyinstxtractor.py malware.exe

    # La sortie est placée dans un répertoire nommé <filename>_extracted/
    ls malware.exe_extracted/

## Workflow d’analyse complet

    # Étape 1 : extraire l'archive PyInstaller
    python pyinstxtractor.py sample.exe

→ crée sample.exe_extracted/ contenant les fichiers .pyc, DLL et modules extraits du PYZ

    # Étape 2 : identifier la version de Python utilisée (nécessaire pour une décompilation précise)
    # pyinstxtractor l'affiche pendant l'extraction, par ex. "Python version: 3.9"

    # Étape 3 : corriger l'en-tête .pyc si nécessaire (la sortie de pyinstxtractor manque parfois
    # du nombre magique attendu par les décompilateurs) et décompiler
    python pycdc.py sample.exe_extracted/sample.pyc > sample_decompiled.py

    # Étape 4 : examiner le code source récupéré à la recherche d'URLs C2, de mécanismes de persistance, etc.
    grep -Ei "http|socket|exec|eval" sample_decompiled.py

## Conseils

- Le script principal extrait porte généralement le nom du script d’entrée original référencé dans le build PyInstaller (visible dans le journal d’extraction).
- Faites correspondre le nombre magique/la version Python du `.pyc` récupéré avec le bon décompilateur (`uncompyle6`/`decompyle3` pour Python ≤3.8, `pycdc`/`pylingual` pour les versions plus récentes) : une incompatibilité produit une sortie illisible.
- Les modules empaquetés en PYZ (l’archive compressée des imports stdlib/tiers) sont extraits aux côtés du script principal et méritent aussi d’être examinés : les malwares cachent parfois leur logique dans un module « helper » embarqué plutôt que dans le point d’entrée.

Aide / Page de manuel

    usage: pyinstxtractor.py [-h] filename

    PyInstaller Extractor - extracts a PyInstaller generated executable

    positional arguments:
      filename    the PyInstaller executable to extract

    optional arguments:
      -h, --help  show this help message and exit

    Output:
      Creates a directory <filename>_extracted/ containing:
        - the main script's compiled bytecode (.pyc, header may need fixing)
        - PYZ-00.pyz_extracted/  (bundled Python modules, auto-extracted)
        - bundled shared libraries / DLLs
        - struct.pyc            (used internally to help fix pyc headers)

    Prints detected Python version and PyInstaller version during extraction.