typetechniqueconfidencehighcreated2026-09-02updated2026-09-02obfuscationanti-staticmsvcmalware-family

XOR + NOT String Decryption

A lightweight anti-static string obfuscation technique observed in MSVC 9.0 PE32 malware (Phorpiex campaign). Strings are encoded at build time by XOR-ing each byte with a repeating 4-byte key, then applying a bitwise NOT. The decoder is a simple loop that reverses both operations.

Detection / Fingerprint

  • Look for a short hardcoded key (typically 4 bytes, e.g. Tmlr) in .rdata or .data.
  • Decoder pattern: buf[i] = ~(buf[i] ^ key[i % len]) or equivalent.
  • Often paired with strlen to determine loop bounds.
  • Commonly found in MSVC 9.0/MSVCR90 binaries with thin IATs.

Implementation Patterns Observed

Phorpiex variant (49740d89):

  • Key: Tmlr (4 bytes, hardcoded at 0x4041c0).
  • Decoder function at 0x401030.
  • Outer loop iterates over the input string using strlen.
  • Inner loop XORs with key byte, then applies bitwise NOT (~).
  • Result is written back in-place to the caller-supplied buffer.

Siblings sharing this exact key:

  • 67ae1ba4 (mutex t1)
  • 5076fdc3 (mutex t2)
  • dc2936ea (mutex t4)
  • c3b1b4e4 (mutex t5)
  • 04134145 (mutex t13)
  • 49740d89 (mutex t7) — this analysis
  • b221a625 (mutex t12)
  • cbc59001 (mutex t11)

Reproduce on Your Own VMs

#include <stdio.h>
#include <string.h>

// Encode a string at build time
void encode(char* buf, size_t len, const char* key) {
    for (size_t i = 0; i < len; i++) {
        buf[i] = ~(buf[i] ^ key[i % strlen(key)]);
    }
}

// Decode at runtime (same operation — XOR+NOT is its own inverse)
void decode(char* buf, size_t len, const char* key) {
    for (size_t i = 0; i < len; i++) {
        buf[i] = ~(buf[i] ^ key[i % strlen(key)]);
    }
}

int main() {
    const char* key = "Tmlr";
    char msg[] = "Hello, world!";
    
    printf("Original:  %s\n", msg);
    encode(msg, strlen(msg), key);
    printf("Encoded:   ");
    for (size_t i = 0; i < strlen(msg); i++) printf("%02x ", (unsigned char)msg[i]);
    printf("\n");
    decode(msg, strlen(msg), key);
    printf("Decoded:   %s\n", msg);
    return 0;
}

Compile with MSVC 9.0 or any C compiler. The encoded bytes will appear as high-entropy noise in the binary; the key and decoder loop are the detection targets.

Defensive Countermeasures

  • String signature: Hunt for the 4-byte key (Tmlr) in PE .rdata sections. Key reuse across campaign siblings is common.
  • Behavioral: The decoder is typically called early in main() before network operations. A memory-write-then-read on a .rdata buffer is anomalous.
  • Emulation: Run the decoder in a sandbox to recover plaintext strings (SMTP commands, BTC wallets, C2 URLs).

Pages Where Observed

  • phorpiex — Phorpiex campaign entity
  • /intel/analyses/49740d891262803c8b246275ac6a80bb64ee2c3fb76953b3f365f5b236105031.html — t7 sibling analysis