| /* |
| * Copyright (C) 2004 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. |
| */ |
| |
| /* |
| ** rebuildpe.c |
| ** |
| ** 28/07/2k4 - Moved out of petitep.c |
| ** 08/08/2k4 - Fixed typo for sects characteristics |
| ** |
| */ |
| |
| /* |
| ** 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. |
| */ |
| |
| #if HAVE_CONFIG_H |
| #include "clamav-config.h" |
| #endif |
| |
| #include <string.h> |
| |
| #include "rebuildpe.h" |
| #include "others.h" |
| |
| #define EC32(x) le32_to_host(x) /* Convert little endian to host */ |
| #define EC16(x) le16_to_host(x) /* Convert little endian to host */ |
| #define PEALIGN(o,a) (((a))?(((o)/(a))*(a)):(o)) |
| #define PESALIGN(o,a) (((a))?(((o)/(a)+((o)%(a)!=0))*(a)):(o)) |
| |
| |
| 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\ |
| " |
| |
| 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) |
| { |
| uint32_t datasize=0, rawbase=PESALIGN(0x148+0x80+0x28*sects, 0x200); |
| char *pefile=NULL, *curpe; |
| struct IMAGE_PE_HEADER *fakepe; |
| int i, gotghost=(sections[0].rva > PESALIGN(rawbase, 0x1000)); |
| |
| if (gotghost) rawbase=PESALIGN(0x148+0x80+0x28*(sects+1), 0x200); |
| |
| if(sects+gotghost > 96) |
| return 0; |
| |
| for (i=0; i < sects; i++) |
| datasize+=PESALIGN(sections[i].rsz, 0x200); |
| |
| if(datasize > CLI_MAX_ALLOCATION) |
| return 0; |
| |
| if((pefile = (char *) cli_calloc(rawbase+datasize, 1))) { |
| memcpy(pefile, HEADERS, 0x148); |
| |
| datasize = PESALIGN(rawbase, 0x1000); |
| |
| fakepe = (struct IMAGE_PE_HEADER *)(pefile+0xd0); |
| fakepe->NumberOfSections = EC16(sects+gotghost); |
| fakepe->AddressOfEntryPoint = EC32(ep); |
| fakepe->ImageBase = EC32(base); |
| fakepe->SizeOfHeaders = EC32(rawbase); |
| memset(pefile+0x148, 0, 0x80); |
| cli_writeint32(pefile+0x148+0x10, ResRva); |
| cli_writeint32(pefile+0x148+0x14, ResSize); |
| curpe = pefile+0x148+0x80; |
| |
| 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); |
| } |
| |
| 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); |
| cli_writeint32(curpe+20, rawbase); |
| /* already zeroed |
| cli_writeint32(curpe+24, 0); |
| cli_writeint32(curpe+28, 0); |
| cli_writeint32(curpe+32, 0); |
| */ |
| cli_writeint32(curpe+0x24, 0xffffffff); |
| memcpy(pefile+rawbase, buffer+sections[i].raw, sections[i].rsz); |
| rawbase+=PESALIGN(sections[i].rsz, 0x200); |
| curpe+=40; |
| datasize+=PESALIGN(sections[i].vsz, 0x1000); |
| } |
| fakepe->SizeOfImage = EC32(datasize); |
| } else { |
| return 0; |
| } |
| |
| i = (cli_writen(file, pefile, rawbase)!=-1); |
| free(pefile); |
| return i; |
| } |