|| Author: SPTH/rRlf || Back to articles ||
*************************************************************
*************************************************************
************ ***********
************ Hashes for Encryption ***********
************ by Second Part To Hell/[rRlf] ***********
************ ***********
*************************************************************
*************************************************************
Index:
******
0) Intro Words
1) The Idea
2) The Practice
a) Simple MD5 encryption
b) Multible-byte MD5 encryption
c) Multibe-byte MD5/SHA1 encryption
d) The final attempt
3) Outro Words
0) Intro Words
A hash function (or hash algorithm) is a way of creating a small digital
"fingerprint" from any kind of data. You can neighter find the original
fingerprinted string nor create a new string with the same checksum
(without a great effort). Beside of rainbow-lists, bruteforce is the only
way to find out what the checksum stands for. Bruteforce uses more time,
the longer the fingerprinted data is. If hash functions will be used in
viruses for encryption, antivirus programms would have to use a bruteforce
attack to find the real virus code. As bruteforce requires much time, and
less scanning time is essential for antivirus-programs, hash-encryption
might be a useful weapon against antivirus programs.
1) The Idea
A typical cryptographic one-way function, such as MD5 or SHA1, is not
one-to-one and makes an effective hash function. How can this be used for
encryption? I wrote bruteforce requires more time the longer the string
is. Now imagine: Create checksums of 1-3 bytes of your virus. Then write a
bruteforce function which finds the real content, combine the content to
the full code and execute it. This bruteforce search should need some
seconds for finding the real content, because emulators will also need the
same time - and the longer an emulator will use, the worse it is for the
antivirus program. Imagine an antivirus program that need 15 - 30 seconds
for scanning one file - whereas the time is no problem for the virus.
2) The Practice
In my examples I've used PHP, because it has an existing MD5/SHA1 function
so it is easy to understand the examples. When I've thought about this
technique I've thought about real binary viruses (assembler would be good,
as you can write very fast bruteforce engines with it).
a) Simple MD5 encryption
In this example I show you how to primitively use this technique. The
code simple uses a bruteforce function to find the strings of the
checksums and prints it to the browser. The checksums are always one
single byte, encrypted with MD5; which means that bruteforce will only
need 2^8 trials per each checksum.
- - - - - - - - - - - - - [ Simple MD5 encryption ] - - - - - - - - - - - - -
<?php
$code=array('c1d9f50f86825a1a2302ec2449c17196', // H
'e1671797c52e15f763380b45e841ec32', // e
'2db95e8e1a9267b7a1188556b2013b33', // l
'2db95e8e1a9267b7a1188556b2013b33', // l
'd95679752134a2d9eb61dbd7b91c4bcc', // o
'7215ee9c7d9dc229d2921a40e899ec5f', // <space>
'5206560a306a2e085a437fd258eb57ce', // V
'02129bb861061d1a052c592e2dc6b383', // X
'e1671797c52e15f763380b45e841ec32', // e
'4b43b0aee35624cd95b910189b3dc231', // r
'03c7c0ace395d80182db07ae2c30f034', // s
'9033e0e305f247c0c3c80d0c7848c8b3'); // !
$i=0; $j=0; $z='';
while ($code[$j])
{
do
{
$i++;
} while (md5(chr($i))!=$code[$j]);
$z.=chr($i);
$j++;
}
echo $z;
?>
- - - - - - - - - - - - - [ Simple MD5 encryption ] - - - - - - - - - - - - -
b) Multible-byte MD5 encryption
This improved version can handle an unlimited number of bytes (well,
limited by time - the checksums are 1 or 2 bytes, because more needs
too much time for the slow PHP interpreter and 30 seconds limit of my
webserver). It uses MD5 again. At this example, the bruteforce engine
needs 2^16 trials to find the correct string. You could increase it to
2^24 (3 bytes) or even 2^32 if you have a damn fast webserver and much
time, but I think 2^24 is realistic.
- - - - - - - - - - - [ Multible-byte MD5 encryption ] - - - - - - - - - - - -
<?php
$code=array('a64cf5823262686e1a28b2245be34ce0', // He
'5b54c0a045f179bcbbbc9abcb8b5cd4c', // ll
'd95679752134a2d9eb61dbd7b91c4bcc', // o
'380f40674dcc13ab964f970e5c5750bb', // <space>V
'02129bb861061d1a052c592e2dc6b383', // X
'818f9c45cfa30eeff277ef38bcbe9910', // er
'530490af3588a14fb123af08e8bf4b95'); // s!
$j=0; $z='';
while ($code[$j])
{
$k=''; $i=0; $r=1;
do
{
while(++$i>255)
{
if ($k=='')
{
$k=chr(0); $i=0;
}
elseif (ord($k{strlen($k)-$r})==255)
{
$k{strlen($k)-$r}=chr(0);
if (strlen($k)-$r) { $r++; }
else { $k=chr(0).$k; $i=0; }
}
else
{
$k{strlen($k)-$r}=chr(ord($k{strlen($k)-$r})+1);
$i=0;
}
}
} while (md5($k.chr($i))!=$code[$j]);
$z.=$k.chr($i);
$j++;
}
echo $z;
?>
- - - - - - - - - - - [ Multible-byte MD5 encryption ] - - - - - - - - - - - -
c) Multibe-byte MD5/SHA1 encryption
The next improvement is to add another checksum, which doubles the
amount of trials needed for finding the encrypt string. There is just
one line that has changed - the while-condition. There is a significant
difference between MD5 and SHA1: MD5 builds 32-byte checksums, SHA1
creates 40-byte checksums.To not manifest which hash algorithm has been
used,the checksum has to be reduced to 32 byte. This is no problem for
the bruteforce, as it can compare the reduced 32 byte. An bruteforce
emulator needs about 2^17 trials per checksum now to decrypt it.
- - - - - - - - - - [ Multibe-byte MD5/SHA1 encryption ] - - - - - - - - - - -
<?php
$code=array('a64cf5823262686e1a28b2245be34ce0', // 'He' MD5
'110c8a30c16070bf2813480d9492a1a1', // 'll' SHA1
'd95679752134a2d9eb61dbd7b91c4bcc', // 'o' MD5
'4a980110005e2e6de062cd0dfd73db7e', // ' V' SHA1
'c032adc1ff629c9b66f22749ad667e6b', // 'X' SHA1
'818f9c45cfa30eeff277ef38bcbe9910', // 'er' MD5
'6393a74e8dceffcbc8e77e7a54e1b813'); // 's!' SHA1
$j=0; $z='';
while ($code[$j])
{
$k=''; $i=0; $r=1;
do
{
while(++$i>255)
{
if ($k=='')
{
$k=chr(0); $i=0;
}
elseif (ord($k{strlen($k)-$r})==255)
{
$k{strlen($k)-$r}=chr(0);
if (strlen($k)-$r) { $r++; }
else { $k=chr(0).$k; $i=0; }
}
else
{
$k{strlen($k)-$r}=chr(ord($k{strlen($k)-$r})+1);
$i=0;
}
}
} while (md5($k.chr($i))!=$code[$j] && substr(sha1($k.chr($i)),0,32)!=$code[$j]);
$z.=$k.chr($i);
$j++;
}
echo $z;
?>
- - - - - - - - - - [ Multibe-byte MD5/SHA1 encryption ] - - - - - - - - - - -
d) The final attempt
As we know that the checksum does not contain more that two or three
bytes, we could also include garbage into the checksums. We have to
include a counter to the bruteforce function, and count all trials. If
the counter reaches a point where no code has been found, it stopps the
searching, and continues with the next checksum. Furthermore I've
included a function which creates new checksums and writes it to the
browser. The encryption function takes one or two bytes of the string,
creates MD5 or SHA1 checksums and randomly includes garbage checksums.
In a real malware, which uses that technique, the encryption function
is inside the encrypted code - of course - together with the spreading
routines.
- - - - - - - - - - - - - - [ The final attempt ] - - - - - - - - - - - - - -
<?php
$code=array('a64cf5823262686e1a28b2245be34ce0', // 'He' MD5
'110c8a30c16070bf2813480d9492a1a1', // 'll' SHA1
'd95679752134a2d9eb61dbd7b91c4bcc', // 'o' MD5
'62686dec2c331fbdc2e2e260b39f8ef6', // GARBAGE
'4a980110005e2e6de062cd0dfd73db7e', // ' V' SHA1
'c032adc1ff629c9b66f22749ad667e6b', // 'X' SHA1
'a853cc79167c18e737532c32a3401b68', // GARBAGE
'818f9c45cfa30eeff277ef38bcbe9910', // 'er' MD5
'6393a74e8dceffcbc8e77e7a54e1b813'); // 's!' SHA1
$j=0; $z='';
while ($code[$j])
{
$k=''; $i=0; $r=1; $c=0;
do
{
while(++$i>255)
{
if ($k=='')
{
$k=chr(0); $i=0;
}
elseif (ord($k{strlen($k)-$r})==255)
{
$k{strlen($k)-$r}=chr(0);
if (strlen($k)-$r) { $r++; }
else { $k=chr(0).$k; $i=0; }
}
else
{
$k{strlen($k)-$r}=chr(ord($k{strlen($k)-$r})+1);
$i=0;
}
}
} while (md5($k.chr($i))!=$code[$j] && substr(sha1($k.chr($i)),0,32)!=$code[$j] && ++$c<65535);
if ($c<65535) { $z.=$k.chr($i); }
$j++;
}
echo $z.'<br><br>';
echo "Now let's see some other possible variants:<br>";
srand((double)microtime()*1000000);
$nz='';
while (strlen($z)>0)
{
$t=0;
$y=substr($z,0,rand(1,2));
if (!rand(0,3)) { $nz=$nz.'<br>'.md5(chr(rand(0,255)).chr(rand(0,255)).chr(rand(0,255))); }
if (strlen($z)==1) { $y.=$z{1}; }
if (rand(0,1))
{
$nz=$nz.'<br>'.md5($y);
}
else
{
$nz=$nz.'<br>'.substr(sha1($y),0,32);
}
if (!rand(0,3)) { $nz=$nz.'<br>'.substr(sha1(chr(rand(0,255)).chr(rand(0,255)).chr(rand(0,255))),0,32); }
$z=substr($z,strlen($y));
}
echo $nz;
?>
- - - - - - - - - - - - - - [ The final attempt ] - - - - - - - - - - - - - -
5) Outro words
In my opinion, emulators are not fast enough to detect a virus using hash
encrypted malware. If the virus is static,of course, this technique is not
very useful, because the checksums of all possible variants of the the
first n bytes can be used as scan-string; but if the virusbody morphs
itself a little bit, this technique could make antivirus researchers a
very hard life. I want to mention again, that I think this idea is very
useful for assembler-viruses, because assembler is very fast, and they are
binary (255 possibilities per byte, not just [A-Z&&a-z&&0-9].
Thanks for reading - I'm checking out now - Over!
- - - - - - - - - - - - - - -
Second Part To Hell/[rRlf]
www.spth.de.vu
spth@priest.com
written in September 2006
...surrealistic viruswriter...
- - - - - - - - - - - - - - -