python-uncompyle6 v3.4 releases: A cross-version Python bytecode decompiler

uncompyle6

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

Introduction

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

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 is the ability to deparse just fragments of source code and give source-code information around a given bytecode offset.

Python fragment deparsing given an instruction offset is useful in showing stack traces and can be encorporated into any program that wants to show a location in more detail than just a line number at runtime. This code can be also 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) a number of decompiling, uncompyle, uncompyle2, uncompyle3 forks around. Almost all 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 or so, another really good at Python 2.7, but that only. 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 are some serious refactoring and cleanup in this code base over those old forks.

This demonstrably does the best in decompiling Python across all Python versions. And even when there is another project that only provides decompilation for the 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 these. 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 are serious about testing, and use automated processes to find bugs. In the issue trackers for other decompilers, you will find a number of bugs we’ve found along the way. Very few to none of them are fixed in the other decompilers.

Changelog v3.4

The main change is to add a tree-transformation phase. This simplifies the code a little and allows us to turn if …: raise AssertionError into assert, and many if ..: else if … into if … elif ..

Use options –show=before and –show=after to see the before the tree transformation phase and after the tree transformation phase.

Most of the heavy lifting for this was done by x0ret.

Other changes:

  • Fix issue #275#283 (process to fix this bug is documented on wiki), #284
  • blacken more code
  • CircleCI adjustments for a changing CircleCi
  • Require more recent xdis for Python 3.8
  • Fix bugs in code using BUILD_LIST_UNPACK and variants

Installation

git clone https://github.com/rocky/python-uncompyle6.git
pip install -e

or

python setup.py install

Tutorial

Copyright (C) 2018 rocky 

Anastasis Vasileiadis

PC Technical || Penetration Tester || Ethical Hacker || Cyber Security Expert || Cyber Security Analyst || Information Security Researcher || Malware analyst || Malware Investigator || Reverse Engineering

SC ProDefence SRL - Cyber Security Services