PDFly Variant Uses Custom PyInstaller To Evade Malware Analysis

A sophisticated PyInstaller-based malware variant called PDFly, which employs custom modifications to dodge common analysis tools.

First spotted by Luke Acha on X in a post highlighting its deceptive nature, PDFly masquerades as a PDF handler but packs encrypted Python 3.13 bytecode.

A close cousin, PDFClick, shares identical evasion tricks. Analysts identified two samples via their SHA-256 hashes: PDFClick (09474277051fc387a9b43f7f08a9bf4f6817c24768719b21f9f7163d9c5c8f74) and PDFly (8c9d9150efa35278afcb23f2af4c4babcc4dd55acd9e839bed4c04cb5a8d9c3f).

These executables alter PyInstaller’s standard structure, making extraction a challenge for tools like pyinstxtractor-ng.

Manual Extraction Reveals Custom Evasion Layers

Initial scans confirm these are modified PyInstaller binaries. Standard pyinstxtractor-ng fails because the MAGIC cookie PyInstaller’s signature header is altered, and strings appear garbled with partial junk data.

Reverse-engineering in IDA Pro exposes the changes: the cookie hides in variable local_80, differing from stock PyInstaller.

Researchers patched pyinstxtractor-ng by replacing the magic value and disabling a non-essential “PYZ\0” assert. Extraction succeeds, but the PYZ archive contents remain gibberish compressed yet encrypted beyond zlib alone.

Tools like CAPA and IDAScope detect only compression, no obvious ciphers in the stub. Attention shifts to bootstrap files, especially pyimod01_archive.pyc.

PDFly Evades Malware Analysis (Source: Samplepedia)
PDFly Evades Malware Analysis (Source: Samplepedia)

Decompiling with PyLingual yields partial Python 3.13 code revealing XOR decryption. Full insight comes from bytecode disassembly fed into an AI assistant for interpretation. Key snippets show a two-stage XOR process wrapping decompression.

First, a generator expression XORs input data:

LOAD_CONST 5 (code object <genexpr>)
LOAD_GLOBAL 21 (NULL + enumerate)
LOAD_FAST_CHECK 8 (obj)  # Encrypted data

The generator uses key b’SCbZtkeMKAvyU’ (13 bytes): for each byte b at index i, compute key[i % 13] ^ b. Post-XOR, zlib.decompress runs:

LOAD_GLOBAL 22 (zlib)
LOAD_ATTR 24 (decompress)
LOAD_FAST 8 (obj)

A second generator applies key b’KYFrLmy’ (7 bytes) identically: key[i % 7] ^ b. Finally, reverse the bytes (data[::-1]) and unmarshal. Custom pyinstxtractor-ng with this chain XOR1, decompress, XOR2, reverse unlocks clean bytecode.

data = bytes(b ^ xor_key1[i % len(xor_key1)] for i, b in enumerate(data))
data = zlib.decompress(data)
data = bytes(b ^ xor_key2[i % len(xor_key2)] for i, b in enumerate(data))
data = data[::-1]

This proves the algorithm without full malware execution.

Generic Extractor Handles Variant Families

To tackle similar samples with varying cookies and keys, a robust script emerged: pyinstaller-mod-extractor-ng.py on GitHub (struppigel/hedgehog-tools).

It automates cookie hunting in the PE overlay. Starting at overlay_offset, it scans 32-byte windows, parsing potential cookies (8-byte magic + pkg_len, toc_offset, toc_len, pyver).

Validation checks bounds: 0 < pkg_len < file_size, toc within pkg, pyver 20-400. Valid hits return the magic byte.

PDFly Evades Malware Analysis (Source: Samplepedia)
PDFly Evades Malware Analysis (Source: Samplepedia)

XOR keys auto-extract from pyimod01_archive.pyc. Skip the 16-byte pyc header, marshal-load the code object, hunt co_consts for ZlibArchiveReader.extract.<genexpr>.

Grab bytes constants:

for genexpr_const in extract_const.co_consts:
    if isinstance(genexpr_const, bytes) and len(genexpr_const) > 0:
        xor_keys.append(genexpr_const)

According to Samplepedia, this yields key1 and key2 dynamically. Plugging both into extraction decrypts PYZ across samples. The tool shines against evasion chains in ransomware loaders or droppers mimicking legit apps like PDF readers.

These tactics highlight PyInstaller’s abuse in custom malware: altered stubs block automated unpacking, while embedded Python decryption delays analysis.

Defenders should scan for overlay anomalies and non-standard pyc behaviors. Full bytecode extraction enables safe static review though this covers decryption only, not payload intent. Update sandboxes with such scripts to stay ahead of PyInstaller mods.

Follow us on Google News , LinkedIn and X to Get More Instant UpdatesSet Cyberpress as a Preferred Source in Google.

Varshini
Varshini
Varshini is a Cyber Security expert in Threat Analysis, Vulnerability Assessment, and Research. Passionate about staying ahead of emerging Threats and Technologies..

Trending News

Related Stories