typeanalysisfamilycoinminerconfidencemediummalware-familycryptominerpepython-pyinstallercompiler
SHA-256: da02fd0723caacead4f056ddcb30995785e52f60dbd5c5c00828de5b54a0aad9

coinminer: da02fd07 — 5.82 MB plain-zlib PyInstaller sibling, thirty-ninth block cluster

Executive Summary

PyInstaller single-file PE32 (5.82 MB) built with MSVC 14.0 on 2018-09-04 14:43:33 UTC. The outer binary is the standard C bootloader stub (~319 KB); the actual payload is a 5.32 MB zlib-compressed overlay (91.4% of file) containing 39 distinct zlib streams. No AES encryption layer is present — unlike the majority of this cluster, there is no pyimod00_crypto_key module and no weak QWERTY-derived key 1qazxsw23edcvfrN. No mining-specific strings are recoverable from the outer binary or overlay. Static-only analysis; CAPE skipped due to no Windows guest. Treated as a probable coinminer sibling by build fingerprint, but inner payload identity is unconfirmed.

What It Is

Field Value
SHA-256 da02fd0723caacead4f056ddcb30995785e52f60dbd5c5c00828de5b54a0aad9
Size 5,823,801 bytes (5.82 MB) ^[file.txt]
Type PE32 executable (GUI) Intel 80386, 6 sections ^[file.txt]
Compiler MSVC 14.0 (Visual Studio 2015) ^[exiftool.json] ^[rabin2-info.txt]
Timestamp 2018-09-04 14:43:33 UTC ^[pefile.txt] ^[rabin2-info.txt]
Linker 14.0 / 14.16 ( MajorLinkerVersion=0xE, Minor=0x0 ) ^[pefile.txt]
Build path hint _MEIPASS2, pyi-runtime-tmpdir, PyInstaller: pyi_win32_utils_to_utf8 failed ^[strings.txt:115] ^[strings.txt:235] ^[strings.txt:243]
Family coinminer (pipeline label; medium confidence)

The binary is a standard PyInstaller v3.x single-file executable for Python 2.7. The PE header is minimal: six sections (.text, .rdata, .data, .gfids, .rsrc, .reloc), no export table, no security directory, no COM descriptor, no delay imports. ^[pefile.txt] Import surface is thin: KERNEL32.dll (heap/CRT/process APIs), USER32.dll (MessageBoxA/W), and WS2_32.dll (ntohl by ordinal). ^[pefile.txt] The .rsrc section contains seven RT_ICON entries (~66 KB total) with no VS_VERSIONINFO or manifest. ^[pefile.txt]

How It Works

Bootloader stub

On execution, the PyInstaller C stub:

  1. Resolves its own path via GetModuleFileNameW. ^[strings.txt:118]
  2. Creates a temporary directory (default %TEMP%/_MEIxxxxxx) controlled by _MEIPASS2 or pyi-runtime-tmpdir environment variables. ^[strings.txt:115] ^[strings.txt:235]
  3. Extracts the embedded CArchive from the file overlay into the temp directory.
  4. Loads python27.dll (or equivalent) and bootstraps the Python runtime.
  5. Executes the embedded __main__.py script. ^[strings.txt:105]

The stub contains standard PyInstaller error strings: Cannot open self %s or archive %s, Error allocating decompression buffer, Archive path exceeds PATH_MAX, Failed to execute script %s. ^[strings.txt:116] ^[strings.txt:78] ^[strings.txt:95] ^[strings.txt:111]

Overlay analysis

The PE proper ends at raw offset 0x3CE00 (≈ 248 KB). Everything after is the PyInstaller CArchive overlay:

  • Overlay size: 5,574,457 bytes (5.32 MB, 91.4% of total file) ^[binwalk.txt]
  • Zlib streams: 39 distinct zlib-compressed blocks detected by binwalk ^[binwalk.txt]
  • AES encryption: Absent. No pyimod00_crypto_key module name, no 1qazxsw23edcvfrN key string, no crypto_key reference anywhere in the binary. ^[strings.txt] (verified by full-text search)
  • Python runtime: No python27.dll or python3x.dll string found in the outer binary; the runtime DLL is likely one of the zlib-compressed entries inside the overlay. ^[strings.txt]

Payload content (inferred)

No plaintext mining indicators (stratum, xmrig, pool, monero, wallet, miner) are present in the outer binary or recoverable from the overlay without decompression. ^[strings.txt] The sample is structurally identical to the confirmed PyInstaller coinminer cluster (same MSVC 14.0 build timestamp, same bootloader version, same zlib overlay pattern). The most parsimonious attribution is that the inner payload is a Python-based miner or downloader, but this is inference — the actual payload is concealed inside 39 zlib blocks.

Compared to AES-encrypted siblings (e.g., 359fcf01, 058ab625, f7abdaf8), this sample drops the encryption layer entirely. The builder appears to have toggled AES on/off while keeping the same PyInstaller version and build pipeline.

Decompiled Behavior

Ghidra was not run for this sample; static analysis relied on radare2 and tool outputs. Radare2 analysis (level 3) recovered 930 functions. The entry point entry0 at 0x004079d3 delegates to main at 0x00401000, which implements the standard PyInstaller C bootloader flow: archive open → TOC read → zlib decompress → temp directory write → Python DLL load → script execution. ^[r2:entry0] ^[r2:main]

Notable functions (radare2 symbol names recovered from string xrefs):

  • Py_Initialize / Py_Finalize / PyRun_SimpleString — Python runtime bootstrap ^[strings.txt:145] ^[strings.txt:141] ^[strings.txt:181]
  • PyMarshal_ReadObjectFromString — loads compiled .pyc from the CArchive ^[strings.txt:198]
  • PyImport_ExecCodeModule — executes the unmarshalled code object ^[strings.txt:165]
  • CreateProcessW — spawns the extracted payload process ^[strings.txt:239]

No anti-debug, anti-VM, or sandbox-evasion logic is present in the bootloader stub. The stub is the stock PyInstaller runtime with no modifications.

C2 Infrastructure

No C2 indicators recoverable statically. The payload is a 5.32 MB zlib-compressed overlay; network indicators (Stratum pool URLs, wallet addresses, HTTP downloaders) would only be visible after full extraction and decompression of the inner Python payload. OpenCTI label is coinminer/exe/urlhaus with no additional IOCs. ^[triage.json]

Interesting Tidbits

  • No AES layer — This is the largest plain-zlib sibling in the cluster (5.82 MB). Most siblings in the 2–6 MB range use AES-256-CBC with the weak key 1qazxsw23edcvfrN derived from the top-left QWERTY row. This sample omits encryption entirely, making the overlay directly decompressible with standard zlib. ^[/intel/analyses/359fcf01a54b89eabcbfcecd734e2af60b6bfa19ffd7fcdd87b1e4ed15db599c.html]
  • Python 2.7 era — The bootloader strings reference PyString_FromString and PyString_FromFormat, which are Python 2.x APIs removed in Python 3. This confirms the build target is Python 2.7. ^[strings.txt:183] ^[strings.txt:185]
  • MSVC 14.0 CRT bloat — The .rdata section contains full Visual C++ 2015 CRT error strings, vtable descriptors, and C++ exception handling metadata. ^[strings.txt:358] ^[strings.txt:300-354]
  • WS2_32 import — Only ntohl is imported by ordinal from WS2_32.dll. This is a minimal networking stub; the actual socket code lives in the Python overlay (likely via socket or urllib modules). ^[pefile.txt]
  • No signing — Security directory is zeroed. signed: false in rabin2. ^[pefile.txt] ^[rabin2-info.txt]

How To Mess With It (Homelab Replication)

Toolchain: Visual Studio 2015 (MSVC 14.0), Python 2.7.18, PyInstaller 3.x

Steps:

  1. Install Python 2.7.18 on a Windows research VM.
  2. pip install pyinstaller==3.6
  3. Write a trivial Python script (e.g., prints _MEIPASS and sleeps):
    import sys, os, time
    print("_MEIPASS:", getattr(sys, '_MEIPASS', os.getcwd()))
    time.sleep(30)
    
  4. Build: pyinstaller --onefile test.py
  5. Verify with binwalk -e dist/test.exe — should show zlib streams in the overlay.
  6. Compare capa fingerprint (if capa signatures are installed) to cluster siblings.

What you'll learn: PyInstaller single-file PE structure, CArchive overlay layout, and how the bootloader delegates to the Python runtime. The --onefile flag is the key toggle that produces this overlay pattern.

Deployable Signatures

YARA rule

rule PyInstaller_Coinminer_Sep2018_Cluster
{
    meta:
        description = "PyInstaller single-file PE32 from Sep 2018 MSVC 14.0 coinminer cluster"
        author = "PacketPursuit"
        date = "2026-08-04"
        sha256 = "da02fd0723caacead4f056ddcb30995785e52f60dbd5c5c00828de5b54a0aad9"
    strings:
        $pyi1 = "Cannot open self %s or archive %s" ascii
        $pyi2 = "Failed to execute script %s" ascii
        $pyi3 = "pyi-runtime-tmpdir" ascii
        $pyi4 = "_MEIPASS2" ascii
        $pyi5 = "PyInstaller: pyi_win32_utils_to_utf8 failed." ascii
        $msvc_ts = { 15 9A 8E 5B }  // TimeDateStamp 0x5B8E9A15 = Sep 4 2018 14:43:33 UTC
    condition:
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3C)) == 0x4550 and
        filesize > 1MB and filesize < 10MB and
        3 of ($pyi*) and
        $msvc_ts
}

Behavioral hunt query (Sigma-like)

title: PyInstaller Coinminer Extraction and Execution
logsource:
  product: windows
  category: process_creation
detection:
  selection:
    CommandLine|contains:
      - '_MEI'
      - 'pyi-runtime-tmpdir'
    ParentImage|endswith:
      - '.exe'
  temp_path:
    CommandLine|contains:
      - '\Temp\_MEI'
  condition: selection and temp_path

IOC list

Indicator Value Note
SHA-256 da02fd0723caacead4f056ddcb30995785e52f60dbd5c5c00828de5b54a0aad9 Sample hash
Build timestamp 0x5B8E9A15 (2018-09-04 14:43:33 UTC) Cluster fingerprint
Temp path pattern %TEMP%\_MEIxxxxxx PyInstaller extraction directory
Environment variable _MEIPASS2 Controls extraction path
Overlay signature 39+ zlib streams, no AES layer Plain-zlib variant

Behavioral fingerprint

This binary is a PyInstaller single-file executable built with MSVC 14.0 in September 2018. On launch it creates a _MEI-prefixed temporary directory under %TEMP%, extracts a Python 2.7 runtime and embedded script from a large zlib-compressed file overlay (typically 1–6 MB, >85% of file size), then loads python27.dll and executes the extracted __main__.py. No registry persistence or elevation is attempted by the bootloader itself; persistence behavior, if any, is implemented in the inner Python payload. The overlay contains 30–60 zlib-compressed blocks. Some siblings encrypt the overlay with AES-256-CBC using the weak key 1qazxsw23edcvfrN; this specific sample omits encryption.

Detection Signatures

Capability ATT&CK ID Evidence
Python script execution T1059.006 PyInstaller bootloader extracts and runs embedded Python bytecode ^[strings.txt:105] ^[strings.txt:165]
Data deobfuscation T1027 Zlib-compressed overlay (39 streams) ^[binwalk.txt]
File and directory discovery T1083 FindFirstFileExW, GetFileAttributesExW ^[pefile.txt]
Process creation T1106 CreateProcessW ^[pefile.txt]

References

  • Artifact ID: 14668ecc-aeef-4c0a-acad-fd280314f8d5 ^[triage.json]
  • OpenCTI labels: coinminer, exe, urlhaus ^[triage.json]
  • coinminer — Entity page for the family cluster
  • pyinstaller-bootloader — Concept page for PyInstaller PE structure
  • python-packed-payload — Concept page for Python-packed malware
  • Sibling analysis: 801fbba1 (first confirmed sibling) ^[/intel/analyses/801fbba19b4d4828191e87e7311480deaf81e84482dab70adf38d61afd01c1fa.html]
  • Sibling analysis: 1fed143e (plain-zlib sibling, 4.14 MB) ^[/intel/analyses/1fed143e0f95ce0e7e6070d89745c74b6a086df0387a2e091720be20a27774b4.html]

Provenance

  • file.txt — file(1) output
  • exiftool.json — ExifTool 12.76 PE metadata
  • pefile.txt — pefile.py full PE dump
  • strings.txt — strings -a -n 6 (10,640 lines)
  • floss.txt — FireEye flare-floss (failed due to CLI argument error)
  • capa.txt — Mandiant capa (failed: default signature path missing)
  • binwalk.txt — binwalk -e embedded artifact scan (39 zlib streams)
  • rabin2-info.txt — radare2 rabin2 -I header summary
  • triage.json — OpenCTI-derived labels and artifact metadata
  • dynamic-analysis.md — CAPE skipped (no Windows guest)
  • Radare2 analysis: level 3, 930 functions recovered, entry0 at 0x004079d3