Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
python-uncompyle6 — A cross-version Python bytecode decompiler | Kitploit
Tools/GitHubGitHub/rocky/python-uncompyle6
Static AnalysisReverse EngineeringDebuggersBinary Analysis
GitHubrocky/python-uncompyle6

python-uncompyle6

A cross-version Python bytecode decompiler

View Repository
4.3k462161 day agoReviewed by Kitploit

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

|buildstatus| |Pypi Installs| |Latest Version| |Supported Python Versions|

|packagestatus|

.. contents::

uncompyle6

A native Python cross-version decompiler and fragment decompiler. The successor to decompyle, uncompyle, and uncompyle2.

I gave a talk on this at BlackHat Asia 2024 <https://youtu.be/H-7ZNrpsV50?si=nOaixgYHr7RbILVS>_.

Introduction

uncompyle6 translates Python bytecode back into equivalent Python source code. It accepts bytecodes from Python version 1.0 to version 3.8, spanning over 24 years of Python releases. We include Dropbox's Python 2.5 bytecode and some PyPy bytecodes.

Why this?

Ok, I'll say it: this software is amazing. It is more than your normal hacky decompiler. Using compiler_ technology, the program creates a parse tree of the program from the instructions; nodes at the upper levels that look a little like what might come from a Python AST. So we can really classify and understand what's going on in sections of Python bytecode.

Building on this, another thing that makes this different from other CPython bytecode decompilers can deparse just fragments of source code and give source-code information around a given bytecode offset.

I use the tree fragments to deparse fragments of code at run time inside my trepan_ debuggers_. For that, bytecode offsets are recorded and associated with fragments of the source code. This purpose, although compatible with the original intention, is yet a little bit different. See this_ for more information.

Python fragment deparsing, given an instruction offset, is useful in showing stack traces and can be incorporated into any program that wants to show a location in more detail than just a line number at runtime. This code can also be used when source code information does not exist and there is just bytecode. Again, my debuggers make use of this.

There were (and still are) several decompyle, uncompyle, uncompyle2, uncompyle3 forks around. Many of them come basically from the same code base, and (almost?) all of them are no longer actively maintained. One was really good at decompiling Python 1.5-2.3, another is really good at Python 2.7, but only that. Another handles Python 3.2 only; another patched that and handled only 3.3. You get the idea. This code pulls all of these forks together and moves forward. There is some serious refactoring and cleanup in this code base over those old forks. Even more experimental refactoring is going on in decompyle3_.

This demonstrably does the best in decompiling Python across all Python versions. And even when there is another project that only provides decompilation for a subset of Python versions, we generally do demonstrably better for those as well.

How can we tell? By taking Python bytecode that comes distributed with that version of Python and decompiling it. Among those that successfully decompile, we can then make sure the resulting programs are syntactically correct by running the Python interpreter for that bytecode version. Finally, in cases where the program has a test for itself, we can run the check on the decompiled code.

We use automated processes to find bugs. In the issue trackers for other decompilers, you will find several bugs we've found along the way. Very few of them are fixed in the other decompilers.

Requirements

The code in the git repository can be run from Python 2.4 to the latest Python version, except Python 3.0 through 3.2. Volunteers are welcome to address these deficiencies if there is a desire to do so.

The way it does this, though, is by segregating consecutive Python versions into git branches:

master Python 3.11 and up (uses poetry install, and newer Python idioms) python-3.6-to-3.10 Python 3.6 through 3.10 (uses newer f-strings, and more modern idioms, and more modern Type annotations) python-3.3-to-3.5 Python 3.3 through 3.5 (Generic Python 3) python-3.0-to-3.2 Python 3.0 through 3.2 (Early Python 3; 3.0 was in some areas closer to Python 2.6 than Python 2.7) python-2.4-to-2.7 Python 2.4 through 2.7 (Generic Python 2)

PyPy from Version 2.4 up works as well.

The bytecode files it can read have been tested on Python bytecodes from versions 1.4, 2.1-2.7, and 3.0-3.8 and later PyPy versions.

Installation

For recent Python releases (Python 3.11+), you can install from PyPI using the name uncompyle6::

pip install uncompyle6

For Python releases before 3.11, do not install using PyPI, but instead install using a file in the GitHub Releases section. Older Python used to use easy_install <https://python101.pythonlibrary.org/chapter29_pip.html#using-easy-install>_. But this is no longer supported on PyPi or newer Python versions. And vice versa, poetry nor pip, (the newer ways) are not supported on older Pythons.

If the Python version you are running uncompyle6 is between Python 2.4 through 2.7, use a tarball called uncompyle6_24-x.y.z.tar.gz.

If the Python version you are running uncompyle6 is between Python 3.0 through 3.2, use a tarball called uncompyle6_30-x.y.z.tar.gz.

If the Python version you are running uncompyle6 is between Python 3.3 through 3.5, use a tarball called uncompyle6_33-x.y.z.tar.gz.

If the Python version you are running uncompyle6 is between Python 3.6 through 3.11, use a tarball called uncompyle6_36-x.y.z.tar.gz.

If the Python version you are running uncompyle6 is 3.11 or later, use a called uncompyle6-x.y.z.tar.gz.

You can also try eggs or wheels that have the same version designation, e.g., uncompyle6-x.y.z-py39-none-any.whl for a Python 3.9 installation. *However, note that the version without the designation means Python 3.11 or greater.

Similarly a tarball with without _xx works only from Python 3.11 or greater.

Rationale for using Git Branches ++++++++++++++++++++++++++++++++

It is currently impossible (if not impractical) to have one Python source code of this complexity and with this many features that can run both Python 2.7 and Python 3.13+. The languages have drifted so much, and Packing is vastly different. In fact, the packaging practice for Python 3.11+ is incompatible with Python 2.7 (and before back to Python 2.4), which favored "easy_install".

Installation from source text ++++++++++++++++++++++++++++++

To install from source code, make sure you have the right Git branch. See the Requirements section for the Git branch names.

After setting the right branch::

$ pip install -e .  # set up to run from source tree

A GNU Makefile is also provided, so :code:make install (possibly as root or sudo) will do the steps above.

Running Tests

::

make check

A GNU makefile has been added to smooth over setting up and running the right command, and running tests from fastest to slowest.

If you have remake_ installed, you can see the list of all tasks including tests via :code:remake --tasks

Usage

Run

::

$ uncompyle6 compiled-python-file-pyc-or-pyo

For usage help:

::

$ uncompyle6 -h

Verification

In older versions of Python, it was possible to verify bytecode by decompiling it and then compiling using the Python interpreter for that bytecode version. Having done this, the bytecode produced could be compared with the original bytecode. However, as Python's code generation got better, this was no longer feasible.

If you want Python syntax verification of the correctness of the decompilation process, add the :code:--syntax-verify option. However since Python syntax changes. You should use this option if the bytecode is the right bytecode for the Python interpreter that will be checking the syntax.

You can also cross-compare the results with another version of uncompyle6 since there are sometimes regressions in decompiling specific bytecode, as the overall quality improves.

Download Tool