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.rdataor.data. - Decoder pattern:
buf[i] = ~(buf[i] ^ key[i % len])or equivalent. - Often paired with
strlento 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(mutext1)5076fdc3(mutext2)dc2936ea(mutext4)c3b1b4e4(mutext5)04134145(mutext13)49740d89(mutext7) — this analysisb221a625(mutext12)cbc59001(mutext11)
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.rdatasections. 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.rdatabuffer 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 —
t7sibling analysis