/*
File: file_exe.c
Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
This software is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
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 the Free Software Foundation, Inc., 51
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <stdio.h>
#include "types.h"
#include "common.h"
#include "filegen.h"
#include "pe.h"
#include "log.h"
static void register_header_check_exe(file_stat_t *file_stat);
static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
const file_hint_t file_hint_exe= {
.extension="exe",
.description="MS Windows executable",
.min_header_distance=0,
.max_filesize=PHOTOREC_MAX_FILE_SIZE,
.recover=1,
.header_check=&header_check_exe,
.register_header_check=®ister_header_check_exe
};
static const unsigned char exe_header[] = {'M','Z'};
static void register_header_check_exe(file_stat_t *file_stat)
{
register_header_check(0, exe_header,sizeof(exe_header), &header_check_exe, file_stat);
}
static int header_check_exe(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
if(memcmp(buffer,exe_header,sizeof(exe_header))==0)
{
const struct pe_image_file_hdr *pe_hdr;
uint32_t e_lfanew=buffer[0x3c]+ (buffer[0x3c+1]<<8) +
(buffer[0x3c+2]<<16) + (buffer[0x3c+3]<<24); /* address of new exe header */
if(e_lfanew==0 || e_lfanew>buffer_size-sizeof(struct pe_image_file_hdr))
{
#ifdef DEBUG_EXE
log_debug("EXE rejected, not PE (e_lfanew)\n");
#endif
return 0;
}
pe_hdr=(const struct pe_image_file_hdr *)(buffer+e_lfanew);
if(le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE)
{
#ifdef DEBUG_EXE
log_debug("EXE rejected, not PE (missing signature)\n");
#endif
return 0;
}
if(le16(pe_hdr->Characteristics) & 0x2000)
{
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="dll";
}
else if(le16(pe_hdr->Characteristics) & 0x01)
{
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
}
else
{
#ifdef DEBUG_EXE
log_debug("EXE rejected, bad characteristics\n");
#endif
return 0;
}
#ifdef DEBUG_EXE
{
const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
(((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
{
log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
}
else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
(((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
}
log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
(long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
}
#endif
{
unsigned int i;
uint64_t sum=0;
const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
for(i=0;i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_image_section < buffer+buffer_size;i++,pe_image_section++)
{
if(le32(pe_image_section->SizeOfRawData)>0)
{
#ifdef DEBUG_EXE
log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
(unsigned long)le32(pe_image_section->PointerToRawData),
(unsigned long)le32(pe_image_section->PointerToRawData)+le32(pe_image_section->SizeOfRawData)-1);
#endif
if(le32(pe_image_section->SizeOfRawData)%32==0)
{
if(sum < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
}
}
if(le32(pe_image_section->NumberOfRelocations)>0)
{
#ifdef DEBUG_EXE
log_debug("relocations 0x%lx-0x%lx\n",
(unsigned long)le32(pe_image_section->PointerToRelocations),
(unsigned long)le32(pe_image_section->PointerToRelocations)+1*le32(pe_image_section->NumberOfRelocations)-1);
#endif
if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le32(pe_image_section->NumberOfRelocations))
sum = le32(pe_image_section->PointerToRelocations)+ 1*le32(pe_image_section->NumberOfRelocations);
}
}
if(le32(pe_hdr->NumberOfSymbols)>0)
{
#ifdef DEBUG_EXE
log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
(long unsigned)(le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))-1);
#endif
if(le32(pe_hdr->NumberOfSymbols)<0x10000)
{
if(sum < le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))
sum = le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols);
}
}
/* It's not perfect, EXE overlay are not recovered */
file_recovery_new->calculated_file_size=sum;
}
file_recovery_new->data_check=&data_check_size;
file_recovery_new->file_check=&file_check_size;
return 1;
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1