|| 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... - - - - - - - - - - - - - - -