typeanalysisfamilycoinminerconfidencemediumcreated2026-05-26updated2026-05-26compilerpemalware-familycryptominerdefense-evasionpython-pyinstaller
SHA-256: 801fbba19b4d4828191e87e7311480deaf81e84482dab70adf38d61afd01c1fa

coinminer: 801fbba1 — PyInstaller bootloader, Sep 2018 MSVC build, embedded Python payload

Executive Summary

PyInstaller-packaged PE32 dropper (compiled Sep 2018 with MSVC 14.0). The outer binary is a stock PyInstaller C bootloader that extracts a ~560 KB CFFI archive to a _MEI temp directory, loads an embedded Python DLL, and executes the marshalled Python payload. No mining pool strings are visible in the outer binary; actual coinminer logic lives inside the compressed overlay. Static triage tooling (floss, capa) were non-functional during analysis due to argument error and missing signatures, respectively.

What It Is

  • File: PE32 executable (GUI) Intel 80386, 6 sections ^[file.txt]
  • Size: 819,100 bytes (799.9 KB) ^[rabin2-info.txt]
  • Compiled: Tue Sep 4 14:43:33 2018 UTC ^[pefile.txt:34] ^[rabin2-info.txt]
  • Linker: MSVC 14.0 (Visual Studio 2015 RTM). Rich header shows Utc1900_C(24210) x17, Utc1900_CPP(24123) x29, Utc1810_CPP(40116) x172, Masm1210(40116) x12 ^[rabin2-info.txt]
  • Signed: false; checksum 0x00000000 ^[rabin2-info.txt]
  • ASLR / DEP: enabled (DllCharacteristics: 0x8140 = DYNAMIC_BASE | NX_COMPAT | TERMINAL_SERVER_AWARE) ^[pefile.txt:74]
  • Subsystem: Windows GUI ^[file.txt]
  • Overlay: 569,756 bytes starting at raw offset 0x3CE00, zlib-compressed PyInstaller CFFI archive ^[binwalk.txt]

How It Works

The binary is a PyInstaller single-file bootloader that performs the following at runtime ^[r2:entry0] ^[r2:fcn.00402520] ^[r2:fcn.00401bc0]:

  1. CRT initialisation — standard MSVC entry0main() → PyInstaller bootstrap ^[r2:entry0]
  2. Archive resolution — locates the CFFI archive appended past the PE sections (overlay at 0x3CE00, size ~570 KB) ^[binwalk.txt]
  3. Extraction — decompresses the archive to %TEMP%\_MEI<XXXX> using zlib/inflate 1.2.8 ^[strings.txt:79-84] ^[binwalk.txt]
  4. Python runtime bootstrap — loads python<ver>.dll via LoadLibrary, resolves CPython API procs (Py_Initialize, PyMarshal_ReadObjectFromString, PyEval_EvalCode, etc.) ^[strings.txt:119-212]
  5. Script execution — unmarshals the embedded Python code object and runs __main__.py ^[strings.txt:104-111]
  6. Cleanup — deletes the temp directory on exit unless _MEIPASS2 env var is set (used for debugging) ^[strings.txt:115]

The overlay contains the actual coinminer payload. Because it is zlib-stream compressed and structurally a PyInstaller CFFI archive, mining pool URLs, wallet addresses, or miner parameters are not observable without extracting and decompiling the embedded .pyc files.

Decompiled Behaviour

  • entry0 (0x004079d3): MSVC CRT entry. Calls initialisers, then main(0, NULL, NULL) ^[r2:entry0]
  • main (0x00401000): Three calls: (1) resolve archive status struct, (2) convert argv/envp to UTF-8 via WideCharToMultiByte / MultiByteToWideChar, (3) call fcn.00402520 (PyInstaller bootstrap core) ^[r2:main]
  • fcn.00402520: Allocates ARCHIVE_STATUS struct; checks _MEIPASS2; builds extraction path under GetTempPathW; calls fcn.00402110 to iterate TOC entries and extract files; calls SetDllDirectoryW to the _MEI folder; then launches the Python interpreter with the unmarshalled script. ^[r2:fcn.00402520]
  • fcn.00401bc0: TOC walker. Formats nested paths via %s%s%s%s%s and %s%s%s%s%s%s%s; opens .pkg and .exe members; copies out bytes via fwrite. ^[r2:fcn.00401bc0]

No anti-debug checks, no VM detection, no API hashing — behaviour is entirely that of a stock PyInstaller bootloader circa 2018.

C2 Infrastructure

Not statically observable. The outer binary contains only generic PyInstaller error strings and MSVC CRT locale strings. No hardcoded IPs, domains, pool URLs, or wallet addresses are present in the PE sections or imports. Pool/C2 configuration is assumed to reside inside the compressed Python payload in the overlay. ^[strings.txt]

Interesting Tidbits

  • floss.txt is a tool-usage error (the triage script passed the sample path to --no instead of sample), yielding no decoded strings. ^[floss.txt]
  • capa.txt failed with missing default signature path — signatures were never installed on this station. ^[capa.txt]
  • binwalk.txt identified 15 zlib-compressed blocks and a PNG icon in .rsrc, confirming the overlay is a multi-member archive. ^[binwalk.txt]
  • The .rsrc section contains 7 icon groups (typical of PyInstaller inheriting default Python icons). ^[pefile.txt:159-492]
  • Rich header heavy use of Utc1810_CPP(40116) (172 counts) with Linker1400 suggests the CRT static library was built with VS 2013 toolset while the final link used VS 2015 — common in PyInstaller's own build pipeline. ^[rabin2-info.txt]
  • The c:/PyI partial path fragment at line 1090 of strings.txt hints the build environment had a PyI directory (PyInstaller source). ^[strings.txt:1090]
  • There are no suspicious imports in the PE: imports are entirely standard Win32 + Python CRT APIs. Threat activity will manifest in child processes spawned from %TEMP%\_MEI*. ^[pefile.txt:249-363]

How To Mess With It (Homelab Replication)

  • Toolchain: Install PyInstaller (pip install pyinstaller==3.4 for 2018-era behaviour) on a Windows research VM with Python 2.7 or 3.6.
  • Build a onefile payload: pyinstaller --onefile --windowed --name=miner_stub your_script.py
  • Extraction test: Run the stub, then inspect %TEMP% for a _MEI folder. Or use pyinstxtractor.py against the built EXE to dump the embedded archive.
  • Verification: strings on the output EXE should show _MEIPASS, PyInstaller, Py_Initialize, and zlib blocks in the overlay. Compare entropy and section layout to this sample.
  • Learning outcome: Recognising that the outer binary is benign infrastructure and the actual threat lives in the overlay prevents triage teams from stopping analysis after a benign-looking import table.

Deployable Signatures

YARA rule

rule PyInstallerBootloader_Coinminer_2018 {
    meta:
        description = "PyInstaller single-file bootloader with embedded coinminer payload (2018-era)"
        author = "Titus"
        date = "2026-05-26"
        sha256 = "801fbba19b4d4828191e87e7311480deaf81e84482dab70adf38d61afd01c1fa"
    strings:
        $pyi1 = "PyInstaller: FormatMessageW failed." ascii wide
        $pyi2 = "_MEIPASS2" ascii wide
        $pyi3 = "pyi-runtime-tmpdir" ascii wide
        $pyi4 = "Installing PYZ: Could not get sys.path" ascii wide
        $pyi5 = "Failed to execute script %s" ascii wide
        $pyi6 = "base_library.zip" ascii wide
        $inflate = "inflate 1.2.8 Copyright 1995-2013 Mark Adler" ascii wide
    condition:
        uint16(0) == 0x5a4d and
        4 of ($pyi*) and
        $inflate and
        filesize > 500KB
}

Sigma rule

Not suitable — the outer binary exhibits no unique process-level behaviour beyond generic PyInstaller extraction. Sigma should target the child process: python.exe or renamed miner executable spawned from %TEMP%\_MEI* within seconds of parent launch.

IOC list

  • SHA-256: 801fbba19b4d4828191e87e7311480deaf81e84482dab70adf38d61afd01c1fa
  • Temp path pattern: %TEMP%\_MEI*\* (PyInstaller extraction directory)
  • Mutex / named pipe: not observed in outer binary
  • Registry: not observed in outer binary

Behavioural fingerprint

PE32 GUI executable compiled with MSVC 2015, containing a ~560 KB zlib-compressed overlay. At runtime extracts its payload to a _MEI-prefixed temp directory, loads python*.dll from that directory, and executes embedded marshalled Python bytecode. No suspicious imports in the parent process; threat behaviour manifests in spawned Python/miner child processes.

Detection Signatures

  • MITRE ATT&CK
    • T1059.003 (Windows Command Shell) — possible batch/powershell launcher in embedded payload; not confirmed statically
    • T1059.006 (Python) — execution via embedded Python interpreter
    • T1074.001 (Data Staged: Local Data Staging) — extraction to temp directory
    • T1105 (Ingress Tool Transfer) — self-contained payload delivery
    • T1574.002 (DLL Side-Loading) — loading Python DLL from _MEI path
  • Capa: non-functional (missing signatures). No ATT&CK mapping available.

References

  • Artifact ID: c913803e-06c0-4d30-8309-64af3b5daaf0 ^[metadata.json]
  • OpenCTI labels: coinminer, exe, urlhaus ^[metadata.json]
  • PyInstaller bootloader source: https://github.com/pyinstaller/pyinstaller/blob/develop/bootloader/src/pyi_main.c
  • Related wiki: coinminer

Provenance

  • file.txtfile command (PE32 executable)
  • strings.txt — strings (1795 lines, truncated output)
  • rabin2-info.txt — radare2 rabin2 -I (binary metadata)
  • pefile.txtpefile Python module (sections, imports, resources)
  • binwalk.txtbinwalk (embedded artifacts / zlib blocks)
  • exiftool.json — ExifTool PE metadata
  • floss.txt — flare-floss (tool argument error, no decoded output)
  • capa.txt — flare-capa (signature path error, no output)
  • triage.json — triage tier assignment
  • metadata.json — artifact metadata from OpenCTI
  • R2 decompilation — radare2 via MCP (pdg at entry0, main, fcn.00402520, fcn.00401bc0)