The SuperFectExec malware comes in a two-stage encoded state, along with a piece of PHP that decodes the first encoding.
This documents that first stage encoding.
for ($o = 0, $e = '&\'()*+,-.:]^_`{|+:*+,+ ... *|(,\'|*:,\'', $d = ''; @ord($e[$o]); $o++) {
if ($o < 16) {
$h[$e[$o]] = $o;
} else {
$d .= @chr(($h[$e[$o]] << 4) + $h[$e[++$o]]);
}
}
The first 16 bytes of ciphertext
are indexes into an array $h[]
,
which gets set to values 0x00 - 0x0f.
Each byte of the rest of the ciphertext will have a value of one of the indexes into $h[]. Use bytes of ciphertext to index $h[] to get the cleartext nibbles, then shift the high nibble and add it to the low nibble.
I implemented an encoder to match the decoder included in SuperFetchExec, to ensure that I understood the encoding.
<?php
// Encode cleartext to superfetchexec-encoded cipertext.
// Need 16 bytes as transposed ciphertext of the
// 2, 4-bit nibbles of a cleartext byte.
$printable_encoding = $argv[1];
$filename = $argv[2];
$cleartext = file_get_contents($filename);
// First 16 bytes of $cipertext are the values of
// encoded nibbles
$ciphertext = $printable_encoding;
$length = strlen($cleartext);
for ($i = 0; $i < $length; ++$i) {
// $cleartext[$i], a byte, gets encoded
// as 2 ciphertext bytes.
$high = 0x0f & (ord($cleartext[$i]) >> 4);
$low = 0x0f & ord($cleartext[$i]);
$ciphertext .= $printable_encoding[$high];
$ciphertext .= $printable_encoding[$low];
}
print $ciphertext;
The block of encoded text (PHP variable $e
above) has the printable
characters used to decode the rest of the block of encoded text as
a sort of prolog.
This has the advantage of not needing a separate key, which is what the second stage of SuperFetchExec uses.
It also has the advantage of allowing different printable encodings so that no easy-to-spot string can be used as a signature for malware detection.
It has the disadvantage of just being a transposition cipher, where pairs of ciphertext bytes represent single cleartext bytes. If you didn't have the SuperFetchExe source code, presumably you could do some frequency counts on bigrams of the ciphertext and figure out the cleartext.