PDFly Malware Exposed: Inside a Custom PyInstaller Threat Built to Evade Analysis

Listen to this Post

Featured Image

Introduction: When a PDF Is Anything but Harmless

Malware authors continue to abuse trusted file formats and developer tools to stay invisible for as long as possible. One of the latest examples is PDFly, a sophisticated PyInstaller-based malware strain designed to look like a legitimate PDF handler while quietly hiding heavily modified Python internals. Unlike common PyInstaller-packed malware, PDFly introduces custom structural changes and layered encryption to defeat automated extraction tools and slow down reverse engineering. This case highlights how threat actors are evolving beyond off-the-shelf packers and turning developer conveniences into stealth weapons.

PDFly and PDFClick: A Deceptive Malware Pair

PDFly first came to light after being spotted by security researcher Luke Acha, who shared early observations about its misleading appearance and evasive behavior. At a glance, the executable claims to be associated with PDF handling, a disguise that lowers suspicion and increases the chance of execution. Beneath that surface, however, sits encrypted Python 3.13 bytecode wrapped in a non-standard PyInstaller layout.

A closely related variant, PDFClick, exhibits the same evasion techniques, suggesting a shared codebase or tooling pipeline. Analysts confirmed this relationship after identifying two samples with matching behavior but different hashes: one for PDFClick and one for PDFly. Both binaries deliberately diverge from PyInstaller’s default structure, frustrating analysts who rely on automated unpacking workflows.

Modified PyInstaller Structure Blocks Standard Tools

Initial inspection quickly confirmed that both samples were PyInstaller executables, but attempts to extract their contents using common tools like pyinstxtractor-ng failed immediately. The failure was not accidental. The malware authors had modified the PyInstaller signature header, specifically altering the well-known MAGIC cookie that extraction tools depend on.

String analysis further reinforced the deception. Many readable strings appeared corrupted or padded with junk data, giving the impression of partial damage rather than intentional obfuscation. This combination of structural tampering and visual noise was enough to block most automated workflows at the first step.

Reverse Engineering Reveals Hidden Cookie Logic

A deeper dive using IDA Pro exposed how these executables deviated from standard PyInstaller stubs. Instead of placing the MAGIC cookie where tools expect it, the malware relocates it into a local variable inside the loader code. In this case, the cookie was stored in a variable identified as local_80, a clear departure from the stock implementation.

This subtle relocation was enough to break pyinstxtractor-ng’s assumptions. The tool simply could not locate the expected header, and extraction aborted. By patching the extractor to accept the modified magic value and disabling a non-critical assertion related to the “PYZ” marker, analysts were finally able to dump the embedded PYZ archive.

Extracted PYZ Still Encrypted Beyond Zlib

Even after successful extraction, the contents of the PYZ archive were unusable. While PyInstaller normally compresses Python bytecode using zlib, these samples added an extra encryption layer. Tools such as CAPA and IDAScope detected compression routines but found no obvious cryptographic libraries, suggesting a lightweight custom solution rather than standard encryption.

This pushed analysts toward the PyInstaller bootstrap files, particularly pyimod01_archive.pyc, where custom extraction logic often resides. Decompiling this file with PyLingual yielded partial Python 3.13-compatible output, enough to hint at XOR-based operations layered around decompression.

Two-Stage XOR Decryption Uncovered

The real breakthrough came from bytecode-level disassembly combined with assisted interpretation. The extraction logic revealed a carefully staged process. First, the encrypted data is passed through a generator expression that applies an XOR operation byte by byte. The XOR key used in this first stage is a 13-byte sequence:

bSCbZtkeMKAvyU.

Each byte of the payload is XORed with the corresponding key byte, cycling through the key using a modulo operation. Only after this step does the malware apply standard zlib.decompress() to the transformed data.

The process does not stop there. A second XOR stage follows decompression, this time using a shorter 7-byte key:

bKYFrLmy.

Finally, the resulting byte sequence is reversed before being unmarshaled into a Python code object. This full chain—XOR, decompress, XOR again, reverse—ensures that even if one layer is identified, the payload remains unreadable without the complete sequence.

Proving the Algorithm Without Executing Malware

By reconstructing the logic statically, researchers were able to validate the decryption routine without running the malware itself. The recovered algorithm clearly demonstrates intent and capability, while avoiding the risk of live execution. Once applied correctly, the result is clean, readable Python bytecode suitable for further static analysis.

This approach underscores an important defensive principle: full understanding of a threat does not require detonating it. With enough insight into the loader logic, analysts can safely extract and inspect malicious payloads offline.

Toward a Generic Extractor for Modified PyInstaller Malware

Recognizing that future samples might change cookies or XOR keys, researchers moved beyond one-off fixes. The result was a more robust extraction script, pyinstaller-mod-extractor-ng.py, published on GitHub as part of the hedgehog-tools collection.

This tool takes a heuristic approach. Instead of assuming a fixed MAGIC cookie, it scans the PE overlay in sliding 32-byte windows, testing each candidate as a potential PyInstaller cookie. It validates findings by checking structural constraints such as package length, table-of-contents offsets, and plausible Python version numbers.

Once a valid cookie is identified, the extractor turns to pyimod01_archive.pyc to recover XOR keys dynamically. By skipping the pyc header, unmarshaling the code object, and scanning constants for generator expressions tied to ZlibArchiveReader.extract, the script can automatically recover embedded byte keys. These keys are then applied in the correct sequence to decrypt the PYZ archive.

Malware Families and Real-World Abuse

According to Samplepedia, this approach works reliably across multiple samples, even when keys and cookies vary. That flexibility makes it especially valuable against malware families that rely on PyInstaller modifications as a core evasion tactic.

These techniques are not limited to niche samples. Ransomware loaders, initial access trojans, and droppers increasingly use PyInstaller because it allows attackers to blend malicious logic with legitimate Python tooling. By masquerading as everyday applications like PDF readers, these threats gain both technical and psychological advantages.

Implications for Defenders and Analysts

The PDFly case illustrates how PyInstaller abuse has matured. Altered stubs break automated unpackers, while custom decryption logic delays human analysis. Together, these tactics buy attackers valuable time, especially during early stages of a campaign.

Defenders should watch for anomalies such as unusual PE overlays, modified PyInstaller headers, and non-standard pyc behavior. Sandboxes and static analysis pipelines need to evolve alongside these threats, incorporating heuristic cookie detection and flexible decryption logic rather than relying on fixed signatures.

While the techniques described here focus on decryption and extraction, they form a crucial first step. Only after bytecode is recovered can analysts fully assess payload intent, command-and-control logic, or destructive capabilities.

What Undercode Say:

PyInstaller Is No Longer “Low Effort” Malware

For years, PyInstaller-packed malware was often dismissed as amateur or commodity-level. PDFly challenges that assumption. By customizing the loader, altering internal signatures, and layering lightweight encryption, the attackers demonstrate a deep understanding of both PyInstaller internals and analyst workflows.

Evasion Through Subtlety, Not Heavy Crypto

What stands out is the restraint. Instead of heavyweight encryption libraries that raise red flags, PDFly relies on XOR operations and data reversal—simple techniques, but applied intelligently. This keeps the stub small, avoids obvious crypto indicators, and complicates automated detection.

Python 3.13 Adoption Signals Forward Planning

The use of Python 3.13 bytecode is another notable detail. Many analysis tools lag behind the newest Python versions, and attackers are clearly exploiting that gap. This choice suggests forward planning rather than opportunistic reuse of old code.

Tooling Arms Race Is Accelerating

The rapid development of generic extractors like pyinstaller-mod-extractor-ng shows that defenders can adapt quickly. However, it also signals an ongoing arms race. As extractors improve, malware authors will continue to tweak cookies, keys, and loader logic.

Static Analysis Still Wins When Done Right

Despite the complexity, this case proves that careful static analysis can unravel even well-defended malware. By understanding how the loader works, analysts avoided execution and still recovered the payload cleanly. This is a reminder that patience and methodology remain powerful defensive tools.

Fact Checker Results

Technical Claims Validation

✅ PDFly and PDFClick both use modified PyInstaller loaders confirmed through reverse engineering.
✅ The two-stage XOR plus zlib decompression chain is accurately reconstructed from bytecode analysis.
❌ No direct evidence yet links these samples to a known threat actor or campaign.

Prediction

Where This Trend Is Heading

🔮 PyInstaller-based malware will increasingly adopt custom loaders to evade signature-based tools.
🔮 More threats will move to newer Python versions to stay ahead of analysis ecosystems.
🔮 Defensive tooling will shift toward heuristic and behavior-based extraction rather than fixed patterns.

🕵️‍📝✔️Let’s dive deep and fact‑check.

References:

Reported By: cyberpress.org
Extra Source Hub (Possible Sources for article):
https://www.twitter.com
Wikipedia
OpenAi & Undercode AI

Image Source:

Unsplash
Undercode AI DI v2
Bing

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow UndercodeNews & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin | 🦋BlueSky | 🐘Mastodon