libclamav/suecrypt.c
3fcb62ca
 /*
632be7ba
  *  Copyright (C) 2006 Sensory Networks, Inc.
  *             Written by aCaB <acab@clamav.net>
3fcb62ca
  *  This program is free software; you can redistribute it and/or modify
632be7ba
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
3fcb62ca
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
 
632be7ba
 
3fcb62ca
 /*
 ** suecrypt.c
 **
 ** 05/08/2k6 - Quick RCE, started coding.
 ** 06/08/2k6 - There were large drops of black rain.
 ** 07/08/2k6 - Found more versions, back to reversing.
 ** 11/08/2k6 - Generic and special cases handler. Release. 
 **
 */
 
 /*
 ** Unpacks and rebuilds suecrypt(*)
 **
 ** Not sure at all what this stuff is, couldn't find any reference to it
 ** Seems to be popular in dialers, can't say more except...
 ** Christoph asked for it and that's enough :)
 **
 ** (*) some versions or maybe only some samples
 */
 
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #include <sys/types.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <stdlib.h>
 #include <string.h>
 
 #include "cltypes.h"
 #include "others.h"
 #include "pe.h"
9be6aaaa
 #include "suecrypt.h"
3fcb62ca
 
 #define EC32(x) le32_to_host(x) /* Convert little endian to host */
 #define EC16(x) le16_to_host(x)
 
57866af1
 char *sudecrypt(int desc, size_t fsize, struct cli_exe_section *sections, uint16_t sects, char *buff, uint32_t bkey, uint32_t pkey, uint32_t e_lfanew) {
3fcb62ca
   char *file, *hunk;
   uint32_t va,sz,key;
   int i, j;
 
   cli_dbgmsg("in suecrypt\n");
 
   if (!(file=cli_calloc(fsize, 1))) return 0;
   lseek(desc, 0, SEEK_SET);
   if((size_t) cli_readn(desc, file, fsize) != fsize) {
     cli_dbgmsg("SUE: Can't read %d bytes\n", fsize);
     free(file);
     return 0;
   }
 
   va=(bkey>>16)|(bkey<<16);
   key=((sz=cli_readint32(buff+0x3e))^va);
   if (!key || key==0x208 || key==0x3bc) key=((sz=cli_readint32(buff+0x46))^va); /* FIXME: black magic */
 
   if (key!=pkey) {
     cli_dbgmsg("SUE: Key seems not (entirely) encrypted\n\tpossible key: 0%08x\n\tcrypted key:  0%08x\n\tplain key:    0%08x\n", pkey, key, sz);
     va=0;
     for (i=0; i<4; i++) {
       va=(va<<8)|0xff;
       if (((key&va)|(sz&(~va)))==pkey) {
 	key=pkey;
 	break;
       }
     }
     if (i==4) cli_dbgmsg("SUE: let's roll the dice...\n");
   }
   cli_dbgmsg("SUE: Decrypting with 0%08x\n", key);
 
   i=0;
   while(1) {
     if (!CLI_ISCONTAINED(buff-0x74, 0xbe, buff-0x58+i*8, 8)) {
       free(file);
       return 0;
     }
     va=(cli_readint32(buff-0x58+i*8)^bkey);
     sz=(cli_readint32(buff-0x58+4+i*8)^bkey);
     if (!va) break;
     cli_dbgmsg("SUE: Hunk #%d RVA:%x size:%d\n", i, va, sz);
     for (j=0; j<sects; j++) {
57866af1
       if(!CLI_ISCONTAINED(sections[j].rva, sections[j].rsz, va, sz)) continue;
       hunk=file+sections[j].rva-va+sections[j].raw;
3fcb62ca
       while(sz>=4) {
 	cli_writeint32(hunk, cli_readint32(hunk)^key);
 	hunk+=4;
 	sz-=4;
       }
       break;
     }
     if (j==sects) {
       cli_dbgmsg("SUE: Hunk out of file or cross sections\n");
       free(file);
       return 0;
     }
     i++;
   }
   va=(cli_readint32(buff-0x74)^bkey);
   cli_dbgmsg("SUE: found OEP: @%x\n", va);
 
   hunk=file+e_lfanew;
   hunk[6]=sects&0xff;
   hunk[7]=sects>>8;
   cli_writeint32(hunk+0x28, va);
3eba7cb1
   hunk+=0x18+(cli_readint32(hunk+0x14)&0xffff); /* size of PE + size of OPT */
   memset(hunk+0x28*sects, 0, 0x28);
3fcb62ca
 
   return file;
 }