typeanalysisfamilyunattributedconfidencemediumcreated2026-07-29updated2026-07-29pemalware-familyloaderanti-vmanti-debugevasioncode-injectionc2obfuscation
SHA-256: 136b57507a3cfe1fc39cf6973869dca7e871e91d63f283c77380fc33298d6d51

unattributed: 136b5750 — MSVC 14.12 PE32 with PEB-walking, XOR-NOT string crypto, and CPUID anti-VM

Executive Summary

A 150 KB PE32 GUI binary compiled with MSVC 14.12 (VS 2017 15.5+) in September 2022. Labelled by OpenCTI as dropped-by-phorpiex, but static traits differ sharply from known Phorpiex downloaders: no masquerade-name list, no ip-api.com gating, and a heavier anti-analysis / reflective-loader stack. All threat APIs are resolved at runtime via PEB-walking; strings are encrypted with a custom XOR-NOT scheme using a hard-coded alphabet array. The binary carries anti-VM (CPUID hypervisor-bit checks + RDTSC timing), an LCG PRNG, and network C2 logic that builds HTTP POST payloads with encrypted body data. Static-only analysis (CAPE skipped).

What It Is

Field Value
SHA-256 136b57507a3cfe1fc39cf6973869dca7e871e91d63f283c77380fc33298d6d51
Size 149,504 bytes (150 KB)
Type PE32 executable (GUI) Intel 80386, 6 sections ^[file.txt]
Compiler MSVC 14.12 (LinkerVersion 14.12) — Visual Studio 2017 15.5 or newer ^[pefile.txt:18] ^[exiftool.json:18]
Timestamp 0x631A9665 — Fri Sep 9 01:27:01 2022 UTC ^[pefile.txt:34]
Debug POGO (IMAGE_DEBUG_TYPE_POGO, size 0xF4) ^[pefile.txt:313]
ASLR / DEP Enabled (DYNAMIC_BASE, NX_COMPAT) ^[pefile.txt:68]
Canary Enabled (canary: true) ^[rabin2-info.txt:6]
Signed Unsigned ^[rabin2-info.txt:27]
Overlay None ^[rabin2-info.txt:23]
Static imports Minimal surface: GDI32 (6), USER32 (11), KERNEL32 (8) — all GUI housekeeping ^[pefile.txt:249]
YARA Generic PE only; no family-specific hits ^[yara.txt]

Static import table is a facade. The binary resolves ~30+ threat APIs at runtime via PEB-walking through ntdll → kernel32 → wininet, caching results in a pseudo-import table at 0x425xxx in the .data section.

How It Works

1. Entry Point & Runtime Loader (0x417034)

The entry-point stub at 0x1946F (RVA) delegates to fcn.00417034, which acts as the runtime orchestrator:

  • Loads module "C" (i.e., kernel32) via PEB-walking by pushing 'C' (0x43) to slot 0x4256c4 and invoking the walker. ^[r2:fcn.00417034]
  • Creates two worker threads:
    • Thread A at 0x407468 — file-system enumeration (* wildcard, recursive). ^[r2:fcn.00417034]
    • Thread B at 0x40782c — network / C2 communication (WinInet-style handle allocation, HTTP POST construction). ^[r2:fcn.00417034]
  • Checks a series of boolean gates in .data (0x42512f, 0x425128, 0x425127, 0x425125, 0x425131, 0x425132, 0x425126) to decide whether to spawn additional threads (0x408f68, 0x407e58, 0x409628, 0x40c064) or skip them. ^[r2:fcn.00417034]
  • Calls a reflective loader / memory mapper at 0x406668 which performs VirtualAlloc-style allocation (via indirect slot 0x4254e4), maps sections, and writes through slots 0x42552c / 0x425544. ^[r2:fcn.00417034]

2. PEB-Walking API Resolution

No imports for VirtualAlloc, CreateThread, InternetOpen, CryptAcquireContext, etc. The binary walks the InMemoryOrderModuleList from the PEB (fs:[0x30]), iterates export tables, and resolves APIs by hash or name. Resolved pointers are cached in .data slots:

Slot VA Likely API Class Evidence
0x4256c4 PEB-walk / module resolver Called with 'C' (0x43) to load kernel32 ^[r2:fcn.00417034]
0x42551c CreateThread Used to spawn threads with entry-point addresses ^[r2:fcn.00417034]
0x425480 VirtualAlloc / memory allocation Called with size arguments before loader execution ^[r2:fcn.00417034]
0x4254d0 CloseHandle / WaitForSingleObject Used on thread handles after creation ^[r2:fcn.00417034]
0x425548 WaitForSingleObject Called with 0xffffffffffffffff (INFINITE) timeout ^[r2:fcn.00417034]
0x4255c0 LoadLibraryA / GetModuleHandleA Loads modules by encrypted name ^[r2:fcn.00406ae8]
0x4255c4 GetProcAddress Resolves APIs after module load ^[r2:fcn.00406ae8]
0x425470 InternetOpen / InternetConnect / HttpOpenRequest Network init; called with XOR-decrypted host/port values ^[r2:fcn.00406ae8]
0x425464 CryptStringToBinary / string helper Used during payload encoding ^[r2:fcn.0040cfcc]
0x4254e4 VirtualAlloc Allocates RWX or RW memory for reflective mapping ^[r2:fcn.00417034]
0x42552c WriteProcessMemory / memcpy Writes decrypted payload into allocated memory ^[r2:fcn.00417034]
0x425544 VirtualProtect Changes memory protection after write ^[r2:fcn.00417034]
0x4254cc ResumeThread / CreateRemoteThread Resumes suspended thread after injection ^[r2:fcn.00417034]
0x425590 GetTickCount / Sleep Timing / anti-emulation ^[r2:fcn.00417034]
0x425744 CryptAcquireContextW / BCryptOpenAlgorithmProvider Crypto init ^[r2:fcn.0040782c]
0x425758 CryptImportKey / BCryptImportKey Key import for payload decryption ^[r2:fcn.0040782c]
0x4257a0 CryptSetKeyParam Sets key parameters (mode, IV) ^[r2:fcn.0040782c]
0x4257a4 CryptEncrypt / CryptDecrypt Payload encryption / decryption ^[r2:fcn.0040782c]
0x425760 CryptGenRandom / RtlGenRandom Generates random data for C2 payload ^[r2:fcn.0040782c]
0x425814 HttpOpenRequestW / HttpSendRequestW HTTP POST to C2 ^[r2:fcn.0040cfcc]
0x42565c OpenProcess Used for process injection targeting ^[r2:fcn.0040782c]
0x42543c lstrlenA String length helper ^[r2:fcn.0040792c]
0x425444 lstrcpyA String copy helper ^[r2:fcn.0040792c]
0x425440 lstrcmpA String comparison helper ^[r2:fcn.0040792c]

Slot values are stored XOR-encrypted with key 0x10035fff and decrypted at first use. ^[r2:fcn.00401240]

3. String Encryption — XOR-NOT Alphabet Cipher

The binary decrypts strings with a two-step routine at 0x401240:

void decrypt_dwords(uint32_t *buf, int count) {
    for (int i = 0; i < count; i++) {
        buf[i] ^= 0x10035fff;
        buf[i] = ~buf[i];
    }
}

^[r2:fcn.00401240]

At 0x40d4b0, the malware builds a 62-character alphabet table by decrypting a 16-DWORD array:

Encrypted: 0xabbfe241 0xa7bbe645 0xa3b7ea49 ... 0xeffc9938
Decrypted: "ABCD" "EFGH" "IJKL" ... "0123" "4567" "89"

This yields the ordered alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789. ^[r2:fcn.0040d4b0]

The malware then uses this alphabet as a lookup table to construct host names, URLs, and User-Agent strings character-by-character via the LCG PRNG (see below). This is a custom base-62 string encoder.

At 0x40cfcc, a second encrypted array decodes to "POST" (wide-character fragments 0x4f0050, 0x540053, 0x0000), confirming HTTP POST as the C2 verb. ^[r2:fcn.0040cfcc]

4. Anti-Analysis & Anti-VM (0x4010bc)

A dedicated gate function performs three checks:

  1. CPUID leaf 1, ECX bit 31 (0x80000000) — hypervisor present bit. If set, the binary alters code paths. ^[r2:fcn.004010bc]
  2. CPUID leaf 7, EBX bit 18 (0x40000) — additional hypervisor feature flag. ^[r2:fcn.004010bc]
  3. RDTSC differential timing — reads rdtsc, applies ror / rol 0xd (13-bit rotate), and compares deltas. Triggers if execution is slower than expected (emulation / instrumentation). ^[r2:fcn.004010bc]

No debugger-specific API calls (IsDebuggerPresent, CheckRemoteDebuggerPresent) are imported statically; detection is entirely CPU-feature based.

5. PRNG (0x40110c)

Linear congruential generator used for:

  • Sleep jitter (anti-emulation)
  • Character selection from the alphabet table (string building)
  • Randomized C2 URL / filename generation
uint32_t lcg() {
    seed = (seed * 0x19660d + 0x3c6ef35f) & 0x7ffffff;
    return seed;
}

^[r2:fcn.0040110c]

6. Network / C2 Behavior (0x40cfcc, 0x40782c)

  • 0x40cfcc allocates a buffer, decrypts the POST verb, and builds an HTTP request body with encrypted payload data. It calls 0x425814 (HttpSendRequest) to transmit. ^[r2:fcn.0040cfcc]
  • 0x40782c performs network initialization (likely InternetOpen / InternetConnect), creates request handles, and reads responses. The function allocates multiple handles and closes them on error paths. ^[r2:fcn.0040782c]
  • The request User-Agent and target URL are constructed at runtime from the alphabet table + PRNG; no hard-coded domains survive in the binary.

7. File-System Enumeration (0x407468, 0x40766c)

  • 0x407468 enumerates drives / directories with "*" wildcard, using 0x425564 (likely FindFirstFile / FindNextFile) and checks result codes (2 = ERROR_FILE_NOT_FOUND, 3 = ERROR_PATH_NOT_FOUND). ^[r2:fcn.00407468]
  • 0x40766c walks recursively, caching file paths for exfiltration or payload staging. Uses indirect API calls at 0x42543c (lstrlen), 0x425444 (lstrcpy), 0x425440 (lstrcmp). ^[r2:fcn.0040766c]

Decompiled Behavior

Address Role Key Observations
0x4010bc Anti-debug/VM gate CPUID hypervisor bits + RDTSC rotate-13 timing ^[r2:fcn.004010bc]
0x4011c4 String helper ASCII case-conversion ('A'–'Z' bounds, OR 0x20) ^[r2:fcn.004011c4]
0x40110c LCG PRNG Multiplier 0x19660d, increment 0x3c6ef35f, mask 0x7ffffff ^[r2:fcn.0040110c]
0x401240 Decrypt stub XOR 0x10035fff then NOT; called 147 times ^[r2:fcn.00401240]
0x406668 Reflective mapper VirtualAlloc, section mapping, 0x42552c/0x425544 writes ^[r2:fcn.00406668]
0x406ae8 Network init Decrypts host/port values, calls 0x425470 (WinInet) ^[r2:fcn.00406ae8]
0x407468 File enumerator FindFirstFile style enumeration with wildcard "*" ^[r2:fcn.00407468]
0x40766c Directory traversal Recursive walk with indirect string APIs ^[r2:fcn.0040766c]
0x40782c C2 comms InternetOpen, handle allocation, HTTP POST body assembly ^[r2:fcn.0040782c]
0x409bb0 Init stub Sets flag gates (0x425129, 0x42512e), calls 0x425580 (likely TlsSetValue or init) ^[r2:fcn.00409bb0]
0x40b734 Alloc wrapper Wrapper around 0x4068c0 (heap alloc with size rounding) ^[r2:fcn.0040b734]
0x40cfcc HTTP POST builder Decrypts "POST", assembles encrypted body, calls 0x425814 ^[r2:fcn.0040cfcc]
0x40d4b0 Alphabet builder Decrypts 16-DWORD array into A-Z a-z 0-9 lookup table ^[r2:fcn.0040d4b0]
0x417034 Main orchestrator PEB-walk, thread creation, flag-gated execution flow ^[r2:fcn.00417034]

C2 Infrastructure

No hard-coded C2 endpoints survive in the binary. The C2 domain, path, and User-Agent are generated at runtime via:

  1. LCG PRNG (0x40110c) producing indices into the alphabet table.
  2. Character-by-character assembly into a wide-character buffer.
  3. HTTP POST verb decrypted from 0x40cfcc ("POST" wide).
  4. Payload body encrypted (likely via CryptEncrypt at slot 0x4257a4) before transmission.

Static inference only — no CAPE detonation available. The presence of HttpOpenRequest/HttpSendRequest patterns, CryptEncrypt, and the POST verb assembly confirms outbound C2 capability, but exact domains are runtime-resolved.

Interesting Tidbits

  • POGO optimization: The binary carries IMAGE_DEBUG_TYPE_POGO (Profile Guided Optimization) metadata, typical of MSVC release builds tuned for hot-path performance. This is unusual for commodity malware and suggests a builder that compiles with full optimization. ^[pefile.txt:313]
  • Canary + ASLR + DEP: All modern mitigations are enabled, yet the binary manually allocates RWX memory (VirtualAlloc → WriteProcessMemory → VirtualProtect). The reflective loader bypasses DEP by design. ^[rabin2-info.txt]
  • Alphabet cipher novelty: The base-62 alphabet table construction via encrypted DWORD arrays is not a standard obfuscation pattern. It evades string-scanning tools because no C2 strings exist in the binary — only the alphabet and the PRNG seed. ^[r2:fcn.0040d4b0]
  • OpenCTI label dropped-by-phorpiex: This sample was dropped by Phorpiex infrastructure, but the binary itself is not a Phorpiex downloader. It is a second-stage payload with its own toolchain (MSVC 14.12 vs. the Delphi/VCL or MinGW builders seen in Phorpiex droppers). Attribution to a specific family is pending. ^[metadata.json]
  • GUI subsystem: Declares Windows GUI but shows no window-creation logic in the decompiled entry path. The USER32/GDI32 imports are likely decoys or minimal scaffolding for the subsystem requirement. ^[file.txt]

How To Mess With It (Homelab Replication)

  1. Toolchain: Install Visual Studio 2017 15.5+ (MSVC 14.12) or VS 2019/2022 with v141 toolset.
  2. Compile a stub that:
    • Walks PEB InMemoryOrderModuleList.
    • Computes export hashes (e.g., DJB2 or CRC32) for VirtualAlloc, CreateThread, InternetOpenA.
    • Stores encrypted pointers in a .data slot array.
    • Uses cpuid leaf 1 / leaf 7 checks for VM gating.
    • Implements the LCG seed = (seed * 0x19660d + 0x3c6ef35f) & 0x7ffffff.
  3. String obfuscation: Embed the alphabet as XOR-NOT encrypted DWORDs. Build C2 URLs at runtime by indexing the alphabet with PRNG output.
  4. Verification: Run capa <reproducer.exe> — should match the same anti-analysis and runtime-resolution capabilities seen in this sample's (failed) capa run.

Deployable Signatures

YARA Rule

rule unattributed_136b5750_pe32_xor_not_loader
{
    meta:
        description = "PE32 MSVC 14.12 reflective loader with XOR-NOT string crypto and PEB-walking API resolution"
        author = "PacketPursuit"
        date = "2026-07-29"
        sha256 = "136b57507a3cfe1fc39cf6973869dca7e871e91d63f283c77380fc33298d6d51"
    strings:
        $xor_not_key = { 3D FF 5F 03 10 }           // cmp eax, 0x10035fff
        $xor_not_op = { 81 31 FF 5F 03 10 }         // xor dword ptr [ecx], 0x10035fff
        $lcg_mul = { 0D 66 19 00 00 }               // 0x19660d
        $lcg_inc = { 35 3C EF C6 03 }               // 0x3c6ef35f
        $lcg_mask = { 25 FF FF FF 07 }              // and eax, 0x7ffffff
        $alphabet_1 = { 41 BB BF EA }               // encrypted "ABCD"
        $alphabet_2 = { 45 E6 BB A7 }               // encrypted "EFGH"
        $alphabet_3 = { 49 EA B7 A3 }               // encrypted "IJKL"
        $post_wide = { 50 A0 B3 EF 53 A0 A8 EF 00 A0 FC EF }  // encrypted "POST" wide fragments
    condition:
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3C) + 0x18) == 0x10B and   // PE32
        3 of ($xor_not_*) and
        2 of ($lcg_*) and
        2 of ($alphabet_*) and
        $post_wide
}

Behavioral Fingerprint

This binary loads with a minimal import table (GDI32, USER32, KERNEL32 GUI functions only). Within the first 5 seconds of execution, it walks the PEB InMemoryOrderModuleList to resolve VirtualAlloc, CreateThread, InternetOpen, and cryptographic APIs by hash. It allocates RWX memory, copies a decrypted payload into it, and spawns a file-system enumeration thread (FindFirstFile with "*" wildcard) alongside a network thread that assembles an HTTP POST request. The POST body is encrypted with a session key imported via CryptImportKey. C2 domain and User-Agent are generated at runtime using a seeded LCG PRNG and a base-62 alphabet table. If executed inside a VM, CPUID leaf 1 ECX[31] or leaf 7 EBX[18] hypervisor bits cause altered code paths or early termination.

IOCs

Indicator Value Notes
SHA-256 136b57507a3cfe1fc39cf6973869dca7e871e91d63f283c77380fc33298d6d51 Primary
SHA-1 5d12d573caddd78d39ef56deaf9afe44636ae19b .text section only
MD5 (full) 991090a0e1f6d5368522abda010b3fba .data section
Compilation Sep 9 2022 01:27:01 UTC Timestamp 0x631A9665
Linker 14.12 VS 2017 15.5+
TLSH C3E37D21F612D0B3C87718F13736B1B2F39E8D2C29A56907DAD80F99BC658236F05997 Entropy-high .data
XOR Key 0x10035fff Used for string + pointer encryption
LCG multiplier 0x19660d PRNG constant
LCG increment 0x3c6ef35f PRNG constant
Anti-VM CPUID leaf 1 ECX[31], leaf 7 EBX[18], RDTSC rotate-13 Static detection targets
Pseudo-import region 0x425000–0x425fff (.data VA) Decrypted at runtime

Detection Signatures

ATT&CK Technique Implementation
T1055 — Process Injection Reflective PE loader: VirtualAlloc → write → VirtualProtect → thread creation ^[r2:fcn.00406668]
T1071.001 — Application Layer Protocol: Web Protocols HTTP POST C2 with encrypted body; WinInet API resolution ^[r2:fcn.0040cfcc]
T1027 — Obfuscated Files or Information XOR-NOT encrypted strings, base-62 alphabet encoding, runtime C2 URL generation ^[r2:fcn.00401240] ^[r2:fcn.0040d4b0]
T1497.001 — Virtualization/Sandbox Evasion: System Checks CPUID hypervisor-bit checks (leaf 1 ECX[31], leaf 7 EBX[18]) ^[r2:fcn.004010bc]
T1497.002 — Virtualization/Sandbox Evasion: User Activity Based RDTSC differential timing gate ^[r2:fcn.004010bc]
T1083 — File and Directory Discovery Recursive "*" enumeration via FindFirstFile / FindNextFile ^[r2:fcn.00407468]
T1573.001 — Encrypted Channel: Symmetric Cryptography CryptEncrypt / CryptDecrypt for C2 payload body ^[r2:fcn.0040782c]
T1105 — Ingress Tool Transfer Downloader / payload retrieval via HTTP POST response handling ^[r2:fcn.0040782c]

References

  • OpenCTI artifact: 6d13c7ca-593e-4afd-9785-c7531b1b038a, labels: dropped-by-phorpiex, exe, malware-bazaar ^[metadata.json]
  • Related wiki pages: unattributed, peb-walking-api-resolution
  • Phorpiex entity page (for dropper linkage, not payload family): phorpiex

Provenance

Analysis produced from static triage inputs (file.txt, pefile.txt, exiftool.json, metadata.json, rabin2-info.txt, yara.txt, ssdeep.txt, tlsh.txt) and radare2 decompilation (analysis level 3) of the binary at <sample 136b57507a3c.bin>. CAPA and floss failed due to missing signature database and incorrect CLI invocation, respectively. CAPE dynamic analysis skipped — no Windows guest available. All behavioral claims are statically inferred and marked accordingly.