| /* |
| * Copyright (C) 2006 Sensory Networks, Inc. |
| * Written by aCaB <acab@clamav.net> |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| * 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. |
| */ |
| |
| |
| /* |
| ** 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" |
| #include "suecrypt.h" |
| |
| #define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
| #define EC16(x) le16_to_host(x) |
| |
| 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) { |
| 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++) { |
| if(!CLI_ISCONTAINED(sections[j].rva, sections[j].rsz, va, sz)) continue; |
| hunk=file+sections[j].rva-va+sections[j].raw; |
| 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); |
| hunk+=0x18+(cli_readint32(hunk+0x14)&0xffff); /* size of PE + size of OPT */ |
| memset(hunk+0x28*sects, 0, 0x28); |
| |
| return file; |
| } |