PyLingual: Toward Perfect Decompilation of Evolving High-Level Languages

Joshua Wiedemeier, Elliot Tarbet, Max Zheng, Sangsoo Ko, Jessica Ouyang, Sang Kil Cha

IEEE Symposium on Security and Privacy 2025 · Day 2 · Software Analysis and Reverse Engineering

Overview

This talk introduces PyLingual, a novel Python decompiler designed to achieve "perfect decompilation" even in the face of Python's rapidly evolving bytecode. Presented by Joshua Wiedemeier from the University of Texas at Dallas and his co-authors, the research addresses a critical gap in the cybersecurity landscape: the reliable reverse engineering of Python applications and malware. As Python solidifies its position as the most popular programming language globally, the demand for effective decompilation tools has surged, particularly given that Python-based malware and commercial products are frequently distributed as compiled executables.

Watch on YouTube

Visual summary for PyLingual: Toward Perfect Decompilation of Evolving High-Level Languages by Joshua Wiedemeier, Elliot Tarbet, Max Zheng, Sangsoo Ko, Jessica Ouyang, Sang Kil Cha
Visual summary for PyLingual: Toward Perfect Decompilation of Evolving High-Level Languages by Joshua Wiedemeier, Elliot Tarbet, Max Zheng, Sangsoo Ko, Jessica Ouyang, Sang Kil Cha

Key moments

  1. 0:00 Introduction to Pilingual and its real-world impact
  2. 1:47 Defining 'Perfect Decompilation' and its benefits
  3. 2:59 The core challenge: Python's bytecode instability
  4. 3:44 Pilingual's hybrid architecture and workflow explained
  5. 5:16 Pilingual's superior performance compared to existing decompilers
  6. 6:03 Future research: human-in-the-loop and malware analysis

PyLingual: Toward Perfect Decompilation of Evolving High-Level Languages

Speakers: Joshua Wiedemeier; Elliot Tarbet; Max Zheng; Sangsoo Ko; Jessica Ouyang; Sang Kil Cha (University of Texas at Dallas)

Conference: IEEE S&P

YouTube: https://www.youtube.com/watch?v=E7OfC7-yzzE

Overview

This talk introduces PyLingual, a novel Python decompiler designed to achieve "perfect decompilation" even in the face of Python's rapidly evolving bytecode. Presented by Joshua Wiedemeier from the University of Texas at Dallas and his co-authors, the research addresses a critical gap in the cybersecurity landscape: the reliable reverse engineering of Python applications and malware. As Python solidifies its position as the most popular programming language globally, the demand for effective decompilation tools has surged, particularly given that Python-based malware and commercial products are frequently distributed as compiled executables.

PyLingual distinguishes itself through an ambitious design philosophy centered on rigorous output verification, aiming to provide semantic equivalence guarantees without requiring access to the original source code. Its success is measurable, with the project's prototype implementation, offered as a free online web service, processing hundreds of Python bytecode files daily. The tool has already proven indispensable in real-world threat investigations, with numerous reports directly citing PyLingual as a crucial component in their Python analysis workflows.

The core innovation of PyLingual lies in its pursuit of perfect decompilation, a statically verifiable test of accuracy that ensures the decompiled source code, when recompiled, yields bytecode identical to the original. This talk details PyLingual's unique hybrid decompiler architecture, which integrates statistical machine learning with traditional program analysis to navigate the inherent instability of Python's bytecode. By providing verifiable decompilation support for modern Python versions, PyLingual not only advances the state of the art in reverse engineering but also significantly empowers the Python reversing and security community.

Background

▶ Watch: Introduction to Pilingual and its real-world impact (0:00)

The necessity for robust Python decompilation tools arises directly from Python's widespread adoption across diverse applications, including malware. While Python's high-level nature simplifies development, its distribution often involves compiling source code into bytecode and packaging it into executables, making the original source code inaccessible to end-users or analysts. This practice, while common for software distribution, presents a significant challenge for security researchers attempting to understand the functionality of malicious Python programs or proprietary applications.

The primary hurdle in Python decompilation stems from the core Python development team's design philosophy: they prioritize language evolution and flexibility over bytecode stability. Unlike some other languages, Python intentionally provides no forward or backward compatibility guarantees at the bytecode level. This means that with each new Python version (e.g., Python 3.6 through 3.12), significant changes occur: new instructions are introduced, existing instructions are modified, and even fundamental mechanisms can be completely overhauled. A prime example is Python 3.11, which dramatically revamped its exception handling mechanism, moving critical control flow information from the instruction stream to a brand-new metadata table. This constant flux in bytecode structure is independent of, and compounded by, continuously improving compiler optimizations, which can further obscure the original high-level logic.

Existing Python decompilers have struggled to keep pace with this rapid evolution. Tools like uncompyle6 and decompile3 rely on expertly crafted bytecode grammars. While effective for the Python versions they were designed for, their support typically lags significantly behind Python's release cycle, often by five years or more. For instance, their support might only extend up to Python 3.8, rendering them largely ineffective for analyzing modern Python applications or malware compiled with newer interpreters. Another decompiler, PIC CDC, attempts to improve version coverage by using a more conservative approach based on top-of-stack tracking. However, this method comes at the cost of completeness, often failing to fully decompile complex bytecode sequences. These limitations highlight a critical need for a decompiler that can reliably handle the "cross-version invariance" challenge posed by Python's evolving bytecode, a problem that PyLingual directly addresses.

Key Findings

▶ Watch: The core challenge: Python's bytecode instability (2:59)

The central and most significant finding presented by the PyLingual team is the profound success of their novel decompiler design, which fundamentally redefines the approach to Python decompilation. PyLingual’s core contribution is the concept of perfect decompilation, a rigorous, statically verifiable test that guarantees semantic equivalence between the original bytecode and the decompiled source code. This verification step, independent of the decompilation process itself, allows PyLingual to measurably improve decompilation outcomes by testing that every instruction and semantically important metadata table of the recompiled output exactly matches the original bytecode. This shifts the burden of gaining user trust from the decompiler's internal correctness to a transparent and verifiable outcome, thereby unlocking a vast design space for experimental decompilers.

Empirically, PyLingual has demonstrably outperformed all other popular Python decompilers. In extensive evaluations, the team compiled 3,000 source code files from the Python Package Index (PyPI) across Python versions 3.6 through 3.12. When compared against uncompyle6, decompile3, and PIC CDC, PyLingual consistently achieved perfect decompilation for a greater number of bytecode files. This superior performance is critical, as it confirms PyLingual's ability to handle the complexities of modern and evolving Python bytecode far more effectively than its predecessors, which often lag years behind Python's release cycle.

Beyond its technical prowess, PyLingual has achieved significant real-world impact and community adoption. Since its release as a free online web service at pilingual.io, the platform has seen a steadily increasing stream of requests, now decompiling hundreds of Python bytecode files daily. This success has been amplified through community engagement, including talks at events like PyCon US and Black Hat USA, leading to a well-received open-source code release. Crucially, PyLingual has become an "indispensable tool" in recent threat investigations of Python malware, with an increasing number of reports directly citing it as a key component in Python analysis workflows. This widespread adoption and validation by the security community underscore PyLingual's practical utility and its role in advancing Python reverse engineering capabilities.

Technical Deep Dive

▶ Watch: Pilingual's hybrid architecture and workflow explained (3:44)

PyLingual's architecture is a testament to addressing the unique challenges posed by Python's rapidly evolving bytecode. The foundation of its design is the concept of perfect decompilation, which serves as both a guiding philosophy and a rigorous verification mechanism. Perfect decompilation is defined as a statically verifiable test of decompilation accuracy that provides semantic equivalence guarantees without requiring knowledge of the original source code. This is achieved by taking the decompiled source code, compiling it with the original bytecode's compiler, and then testing that the resulting bytecode is identical to the original bytecode, instruction by instruction, and metadata table by metadata table. This robust verification step is crucial because it frees the decompiler from needing to be "correct by construction," allowing for more experimental and flexible decompiler designs.

The core challenge PyLingual addresses is the lack of cross-version invariance in Python bytecode. The Python core development team intentionally makes no guarantees about bytecode stability, meaning new Python versions frequently introduce new instructions, modify existing ones, and even overhaul fundamental mechanisms. For instance, Python 3.11 completely re-architected its exception handling, moving control flow information from the instruction stream to a dedicated metadata table. To cope with this dynamic environment, PyLingual adopts a hybrid decompiler architecture that strategically integrates statistical machine learning (ML) components with traditional program analysis techniques. This hybrid approach allows PyLingual to leverage version-specific ML for unstable, high-frequency bytecode details, while relying on more stable, programmatic analysis for higher-level abstractions that remain consistent across versions.

PyLingual divides the decompilation process into three distinct subtasks:

  1. Bytecode Segmentation: This initial step involves classifying each instruction within its context as either the beginning of a statement, internal to a statement, or the end of a statement. This segmentation is crucial for establishing a precise association between the original bytecode and the source code statements that will be translated. It effectively delineates the boundaries of high-level language constructs within the low-level bytecode.
  1. Statement Translation: Following segmentation, the translation model converts each identified bytecode statement into its corresponding source code statement. The talk mentions the use of "pre-processing tricks" to enhance the accuracy and capacity of this translator, details of which are elaborated in the associated paper. This stage is where the raw bytecode operations are mapped to understandable Python syntax, such as if, while, for, function calls, and variable assignments.
  1. Control Flow Reconstruction: This final subtask aims to reassemble the translated source code statements into a coherent, executable program structure. The first step involves creating a control flow graph (CFG). Python's bytecode is conducive to reliable CFG generation because it contains no indirect jumps, and code object entry and exit points are well-defined. Once the CFG is constructed, the source code statements (associated with their original bytecode segments) are attached to the basic blocks within the CFG. Finally, these source code statements are assembled according to the graph's structure, reconstructing loops, conditionals, and function bodies. The talk notes that the exact mechanisms and heuristics used for this reconstruction are an active area of development within the open-source project.

By combining the rigor of perfect decompilation with a flexible, hybrid architecture that intelligently deploys ML and traditional program analysis, PyLingual effectively navigates the complexities of Python's evolving bytecode. This methodical approach ensures not only high accuracy but also adaptability to future Python versions, a critical advantage over previous decompiler designs.

Demo / Proof of Concept

▶ Watch: Pilingual's superior performance compared to existing decompilers (5:16)

The practical demonstration and proof of concept for PyLingual are multifaceted, highlighting its accessibility and real-world utility. The primary demonstration is the free online web service available at pilingual.io. This platform allows users to directly upload Python bytecode files and receive decompiled source code, showcasing the decompiler's capabilities in a user-friendly manner. The service's rapidly increasing usage, handling hundreds of Python bytecode files daily, serves as compelling evidence of its functionality and value to the community.

Furthermore, the PyLingual project has embraced an open-source model, with its code available on GitHub at github.com/scutd/pilingual. This open release not only serves as a transparent proof of concept for the underlying technology but also fosters community involvement, enabling other researchers and developers to contribute to its ongoing improvement. The talk explicitly mentions that the control flow reconstruction mechanisms and heuristics are an active area of development within this open-source release, inviting collaboration.

The scale of data processed by PyLingual further underscores its robustness as a proof of concept. The online service has processed over 130,000 Python bytecode files, providing a massive dataset for evaluation and future research. This includes over 2,000 samples confirmed as malicious by VirusTotal and over 500 samples utilizing PyInstaller (referred to as pymer in the transcript) for sophisticated obfuscation. This extensive dataset, derived from real-world usage, demonstrates PyLingual's efficacy across a wide range of Python applications, including those designed to evade analysis. The existence and active use of these platforms solidify PyLingual's position as a thoroughly tested and practically validated tool.

Defensive Implications

▶ Watch: Future research: human-in-the-loop and malware analysis (6:03)

PyLingual offers significant and immediate benefits for cybersecurity defenders, particularly those engaged in malware analysis, incident response, and threat intelligence. Its ability to achieve "perfect decompilation" across a wide range of Python versions directly translates into more accurate and reliable analysis of Python-based threats.

Firstly, PyLingual drastically improves the speed and accuracy of Python malware analysis. Traditional decompilers often fail or produce incomplete, incorrect output for modern Python malware, forcing analysts to resort to time-consuming manual reverse engineering or dynamic analysis. With PyLingual, defenders can quickly obtain high-fidelity source code, enabling them to understand malware functionality, identify command-and-control (C2) mechanisms, extract indicators of compromise (IOCs), and develop effective countermeasures more rapidly.

Secondly, the tool is crucial for unraveling sophisticated obfuscation techniques. The talk specifically mentions over 500 uploaded samples using PyInstaller (pymer) for obfuscation. PyLingual's capacity to handle such obfuscated bytecode is invaluable for threat actors frequently employ these methods to hinder analysis. By effectively reversing obfuscated Python code, defenders can gain deeper insights into attacker tactics, techniques, and procedures (TTPs), leading to improved detection and prevention strategies. The planned large-scale study of Python malware and obfuscation techniques, leveraging the 130,000 bytecode files uploaded to PyLingual's service, aims to "identify previously unexplored Python malware and develop automatic reversing techniques for popular Python obfuscators," directly contributing to the defensive posture.

Thirdly, PyLingual facilitates proactive threat intelligence gathering. By enabling comprehensive analysis of Python malware, security teams can better understand emerging threats, track malware families, and predict future attack vectors. This proactive stance helps organizations anticipate and mitigate risks before they materialize into full-blown incidents.

Finally, the project's future research thrusts, such as human-in-the-loop decompilation with error localization and differential analysis tooling, promise to further empower defenders. This approach will minimize the expertise and effort required to refine imperfectly decompiled code, making advanced analysis accessible to a broader range of security professionals. Ultimately, PyLingual equips defenders with a powerful, verifiable tool to effectively combat the growing wave of Python-based cyber threats.

Key Takeaways

  • Python Bytecode Instability is the Core Challenge: Python's rapid evolution, with new instructions and overhauled mechanisms in each version, makes reliable cross-version decompilation exceptionally difficult for traditional tools.
  • "Perfect Decompilation" Redefines Accuracy: PyLingual introduces a verifiable test for semantic equivalence, ensuring that recompiled decompiled source code precisely matches the original bytecode, thereby building trust in the decompiler's output.
  • Hybrid Architecture is Key to Adaptability: By combining version-specific machine learning for unstable bytecode details and programmatic analysis for stable abstractions, PyLingual effectively handles Python's evolving bytecode.
  • PyLingual Outperforms Existing Decompilers: Extensive evaluations show PyLingual perfectly decompiles significantly more bytecode files across Python versions 3.6-3.12 than uncompyle6, decompile3, and PIC CDC.
  • Critical Tool for Python Malware Analysis: PyLingual has become an indispensable tool in real-world threat investigations, aiding in the analysis of Python malware and the reverse engineering of obfuscated code.
  • Future Focus on Human-in-the-Loop and Large-Scale Studies: Upcoming research will explore iterative human refinement of decompiled code and conduct large-scale studies of Python malware and obfuscation techniques using its vast dataset.

About the Speaker(s)

Joshua Wiedemeier is the lead speaker for the PyLingual project, representing the University of Texas at Dallas. He, along with his co-authors Elliot Tarbet, Max Zheng, Sangsoo Ko, Jessica Ouyang, and Sang Kil Cha, are researchers affiliated with the University of Texas at Dallas. Their work focuses on advancing the field of program analysis and reverse engineering, particularly for high-level languages like Python, to address critical challenges in cybersecurity.

All talks from IEEE Symposium on Security and Privacy 2025