libclamav/rebuildpe.c
85dd8460
 /*
2023340a
  *  Copyright (C) 2007-2008 Sourcefire, Inc.
  *
  *  Authors: Alberto Wu
85dd8460
  *
  *  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.
85dd8460
  *
  *  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
48b7b4a7
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
85dd8460
  */
 
 /*
 ** rebuildpe.c
 ** 
 ** 28/07/2k4 - Moved out of petitep.c
5eb34fac
 ** 08/08/2k4 - Fixed typo for sects characteristics
85dd8460
 **
 */
 
 /*
 ** Rebuilds a fully parsable / *not runnable* PE file including
 ** a fake MZ header, a piece of informational 16bit code,
 ** lookalike PE & Optional headers, an array of structures and
 ** of course the real content.
 ** Sections characteristics will have all the bits set.
 */
 
68fb8dd1
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
85dd8460
 #include <string.h>
 
 #include "rebuildpe.h"
 #include "others.h"
 
75282b5c
 #define EC32(x) le32_to_host(x) /* Convert little endian to host */
 #define EC16(x) le16_to_host(x) /* Convert little endian to host */
57866af1
 #define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o))
 #define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o))
 
68fb8dd1
 
85dd8460
 struct IMAGE_PE_HEADER {
     uint32_t Signature;
     /* FILE HEADER */
     uint16_t    Machine;
     uint16_t    NumberOfSections;
     uint32_t   TimeDateStamp;
     uint32_t   PointerToSymbolTable;
     uint32_t   NumberOfSymbols;
     uint16_t    SizeOfOptionalHeader;
     uint16_t    Characteristics;
     /* OPTIONAL HEADER */
     uint16_t    Magic;
     uint8_t    MajorLinkerVersion;
     uint8_t    MinorLinkerVersion;
     uint32_t   SizeOfCode;
     uint32_t   SizeOfInitializedData;
     uint32_t   SizeOfUninitializedData;
     uint32_t   AddressOfEntryPoint;
     uint32_t   BaseOfCode;
     uint32_t   BaseOfData;
     /* NT additional fields. */
     uint32_t   ImageBase;
     uint32_t   SectionAlignment;
     uint32_t   FileAlignment;
     uint16_t    MajorOperatingSystemVersion;
     uint16_t    MinorOperatingSystemVersion;
     uint16_t    MajorImageVersion;
     uint16_t    MinorImageVersion;
     uint16_t    MajorSubsystemVersion;
     uint16_t    MinorSubsystemVersion;
     uint32_t   Win32VersionValue;
     uint32_t   SizeOfImage;
     uint32_t   SizeOfHeaders;
     uint32_t   CheckSum;
     uint16_t    Subsystem;
     uint16_t    DllCharacteristics;
     uint32_t   SizeOfStackReserve;
     uint32_t   SizeOfStackCommit;
     uint32_t   SizeOfHeapReserve;
     uint32_t   SizeOfHeapCommit;
     uint32_t   LoaderFlags;
     uint32_t   NumberOfRvaAndSizes;
     /* IMAGE_DATA_DIRECTORY follows.... */
 };
 
 #define HEADERS "\
 \x4D\x5A\x90\x00\x02\x00\x00\x00\x04\x00\x0F\x00\xFF\xFF\x00\x00\
 \xB0\x00\x00\x00\x00\x00\x00\x00\x40\x00\x1A\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00\
 \x0E\x1F\xB4\x09\xBA\x0D\x00\xCD\x21\xB4\x4C\xCD\x21\x54\x68\x69\
 \x73\x20\x66\x69\x6C\x65\x20\x77\x61\x73\x20\x63\x72\x65\x61\x74\
 \x65\x64\x20\x62\x79\x20\x43\x6C\x61\x6D\x41\x56\x20\x66\x6F\x72\
 \x20\x69\x6E\x74\x65\x72\x6E\x61\x6C\x20\x75\x73\x65\x20\x61\x6E\
 \x64\x20\x73\x68\x6F\x75\x6C\x64\x20\x6E\x6F\x74\x20\x62\x65\x20\
 \x72\x75\x6E\x2E\x0D\x0A\x43\x6C\x61\x6D\x41\x56\x20\x2D\x20\x41\
 \x20\x47\x50\x4C\x20\x76\x69\x72\x75\x73\x20\x73\x63\x61\x6E\x6E\
 \x65\x72\x20\x2D\x20\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\
 \x63\x6C\x61\x6D\x61\x76\x2E\x6E\x65\x74\x0D\x0A\x24\x00\x00\x00\
 \x50\x45\x00\x00\x4C\x01\xFF\xFF\x43\x4C\x41\x4D\x00\x00\x00\x00\
 \x00\x00\x00\x00\xE0\x00\x83\x8F\x0B\x01\x00\x00\x00\x10\x00\x00\
 \x00\x10\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x00\x10\x00\x00\
 \x00\x10\x00\x00\xFF\xFF\xFF\xFF\x00\x10\x00\x00\x00\x02\x00\x00\
 \x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x0A\x00\x00\x00\x00\x00\
 \x00\x10\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\
 \x00\x00\x10\x00\x00\x10\x00\x00\x00\x00\x10\x00\x00\x10\x00\x00\
 \x00\x00\x00\x00\x10\x00\x00\x00\
 "
 
57866af1
 int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file)
85dd8460
 {
4490fd97
   uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200);
85dd8460
   char *pefile=NULL, *curpe;
   struct IMAGE_PE_HEADER *fakepe;
4490fd97
   int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000));
85dd8460
 
4490fd97
   if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200);
 
   if(sects+gotghost > 96)
57866af1
     return 0;
52b5464e
 
85dd8460
   for (i=0; i < sects; i++)
57866af1
     datasize+=PESALIGN(sections[i].rsz, 0x200);
 
52b5464e
   if(datasize > CLI_MAX_ALLOCATION)
57866af1
     return 0;
52b5464e
 
57866af1
   if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) {
85dd8460
     memcpy(pefile, HEADERS, 0x148);
 
4490fd97
     datasize = PESALIGN(rawbase, 0x1000);
57866af1
 
85dd8460
     fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0);
4490fd97
     fakepe->NumberOfSections = EC16(sects+gotghost);
68fb8dd1
     fakepe->AddressOfEntryPoint = EC32(ep);
     fakepe->ImageBase = EC32(base);
4490fd97
     fakepe->SizeOfHeaders = EC32(rawbase);
85dd8460
     memset(pefile+0x148, 0, 0x80);
68fb8dd1
     cli_writeint32(pefile+0x148+0x10, ResRva);
     cli_writeint32(pefile+0x148+0x14, ResSize);
85dd8460
     curpe = pefile+0x148+0x80;
 
4490fd97
     if (gotghost) {
       snprintf(curpe, 8, "empty");
       cli_writeint32(curpe+8, sections[0].rva-datasize); /* vsize */
       cli_writeint32(curpe+12, datasize); /* rva */
       cli_writeint32(curpe+0x24, 0xffffffff);
       curpe+=40;
       datasize+=PESALIGN(sections[0].rva-datasize, 0x1000);
     }
 
85dd8460
     for (i=0; i < sects; i++) {
       snprintf(curpe, 8, ".clam%.2d", i+1);
       cli_writeint32(curpe+8, sections[i].vsz);
       cli_writeint32(curpe+12, sections[i].rva);
       cli_writeint32(curpe+16, sections[i].rsz);
57866af1
       cli_writeint32(curpe+20, rawbase);
4490fd97
       /* already zeroed
85dd8460
       cli_writeint32(curpe+24, 0);
       cli_writeint32(curpe+28, 0);
       cli_writeint32(curpe+32, 0);
4490fd97
       */
5eb34fac
       cli_writeint32(curpe+0x24, 0xffffffff);
57866af1
       memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz);
       rawbase+=PESALIGN(sections[i].rsz, 0x200);
85dd8460
       curpe+=40;
57866af1
       datasize+=PESALIGN(sections[i].vsz, 0x1000);
85dd8460
     }
57866af1
     fakepe->SizeOfImage = EC32(datasize);
   } else {
     return 0;
85dd8460
   }
 
57866af1
   i = (cli_writen(file, pefile, rawbase)!=-1);
   free(pefile);
   return i;
85dd8460
 }