PhotoRec: avoid potential integer overflow while parsing exe files

This commit is contained in:
Christophe Grenier 2019-08-05 16:25:06 +02:00
parent 94fa96ce3f
commit 0ae3da4161

View file

@ -37,7 +37,6 @@
#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);
static void file_rename_pe_exe(file_recovery_t *file_recovery);
const file_hint_t file_hint_exe= {
@ -51,122 +50,119 @@ const file_hint_t file_hint_exe= {
static const unsigned char exe_header[2] = {'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)
{
const struct dos_image_file_hdr *dos_hdr=(const struct dos_image_file_hdr*)buffer;
const struct pe_image_file_hdr *pe_hdr;
if(memcmp(buffer,exe_header,sizeof(exe_header))!=0)
return 0;
pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
if(le32(dos_hdr->e_lfanew)>0 &&
le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
(le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr))
{
/* NE Win16 */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
return 1;
}
if(le32(dos_hdr->e_lfanew)>0 &&
le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
(le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
{
/* Windows PE */
if(le16(pe_hdr->Characteristics) & 0x2000)
{
/* Dynamic Link Library */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="dll";
}
else if(le16(pe_hdr->Characteristics) & 0x02)
const struct pe_image_file_hdr *pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
{
/* NE Win16 */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
return 1;
}
else
if((le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
{
#ifdef DEBUG_EXE
log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
#endif
return 0;
}
file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
#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)
/* Windows PE */
if(le16(pe_hdr->Characteristics) & 0x2000)
{
log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
/* Dynamic Link Library */
reset_file_recovery(file_recovery_new);
file_recovery_new->extension="dll";
}
else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
else if(le16(pe_hdr->Characteristics) & 0x02)
{
const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
reset_file_recovery(file_recovery_new);
file_recovery_new->extension=file_hint_exe.extension;
}
else
{
#ifdef DEBUG_EXE
log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
#endif
return 0;
}
file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
#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)));
}
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+1) <= buffer+buffer_size;
i++,pe_image_section++)
{
if(le32(pe_image_section->SizeOfRawData)>0)
if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
{
#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);
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
if(le32(pe_image_section->SizeOfRawData)%32==0)
{
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+1) <= buffer+buffer_size;
i++,pe_image_section++)
{
if(le32(pe_image_section->SizeOfRawData)>0)
{
if(sum < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
#ifdef DEBUG_EXE
log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
(unsigned long)le32(pe_image_section->PointerToRawData),
(unsigned long)(tmp-1));
#endif
if(le32(pe_image_section->SizeOfRawData)%32==0)
{
if(sum < tmp)
sum=tmp;
}
}
if(le16(pe_image_section->NumberOfRelocations)>0)
{
const uint64_t tmp=(uint64_t)le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
#ifdef DEBUG_EXE
log_debug("relocations 0x%lx-0x%lx\n",
(unsigned long)le32(pe_image_section->PointerToRelocations),
(unsigned long)(tmp-1));
#endif
if(sum < tmp)
sum = tmp;
}
}
if(le16(pe_image_section->NumberOfRelocations)>0)
if(le32(pe_hdr->NumberOfSymbols)>0)
{
const uint64_t tmp=(uint64_t)le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*(uint64_t)le32(pe_hdr->NumberOfSymbols);
#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*le16(pe_image_section->NumberOfRelocations)-1);
log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
(long unsigned)(tmp-1));
#endif
if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations))
sum = le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
if(le32(pe_hdr->NumberOfSymbols)<0x10000)
{
if(sum < tmp)
sum = tmp;
}
}
/* It's not perfect, EXE overlay are not recovered */
file_recovery_new->calculated_file_size=sum;
}
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;
file_recovery_new->file_rename=&file_rename_pe_exe;
return 1;
}
file_recovery_new->data_check=&data_check_size;
file_recovery_new->file_check=&file_check_size;
file_recovery_new->file_rename=&file_rename_pe_exe;
return 1;
}
if(le16(dos_hdr->bytes_in_last_block) <= 512 &&
le16(dos_hdr->blocks_in_file) > 0 &&
@ -520,3 +516,8 @@ static void file_rename_pe_exe(file_recovery_t *file_recovery)
}
fclose(file);
}
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);
}