1 /*
2
3 File: file_exe.c
4
5 Copyright (C) 1998-2005,2007 Christophe GRENIER <grenier@cgsecurity.org>
6
7 This software is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write the Free Software Foundation, Inc., 51
19 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #ifdef HAVE_STRING_H
27 #include <string.h>
28 #endif
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #include <stdio.h>
33 #include "types.h"
34 #include "common.h"
35 #include "filegen.h"
36 #include "pe.h"
37 #include "log.h"
38
39 static void register_header_check_exe(file_stat_t *file_stat);
40 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);
41 static void file_rename_pe_exe(file_recovery_t *file_recovery);
42
43 const file_hint_t file_hint_exe= {
44 .extension="exe",
45 .description="MS Windows executable",
46 .max_filesize=PHOTOREC_MAX_FILE_SIZE,
47 .recover=1,
48 .enable_by_default=1,
49 .register_header_check=®ister_header_check_exe
50 };
51
52 static const unsigned char exe_header[2] = {'M','Z'};
53
register_header_check_exe(file_stat_t * file_stat)54 static void register_header_check_exe(file_stat_t *file_stat)
55 {
56 register_header_check(0, exe_header,sizeof(exe_header), &header_check_exe, file_stat);
57 }
58
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)59 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)
60 {
61 const struct dos_image_file_hdr *dos_hdr=(const struct dos_image_file_hdr*)buffer;
62 const struct pe_image_file_hdr *pe_hdr;
63 if(memcmp(buffer,exe_header,sizeof(exe_header))!=0)
64 return 0;
65 pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
66 if(le32(dos_hdr->e_lfanew)>0 &&
67 le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
68 (le32(pe_hdr->Magic) & 0xffff) == IMAGE_WIN16_SIGNATURE)
69 {
70 /* NE Win16 */
71 reset_file_recovery(file_recovery_new);
72 file_recovery_new->extension=file_hint_exe.extension;
73 return 1;
74 }
75 if(le32(dos_hdr->e_lfanew)>0 &&
76 le32(dos_hdr->e_lfanew) <= buffer_size-sizeof(struct pe_image_file_hdr) &&
77 (le32(pe_hdr->Magic) & 0xffff) == IMAGE_NT_SIGNATURE)
78 {
79 /* Windows PE */
80 if(le16(pe_hdr->Characteristics) & 0x2000)
81 {
82 /* Dynamic Link Library */
83 reset_file_recovery(file_recovery_new);
84 file_recovery_new->extension="dll";
85 }
86 else if(le16(pe_hdr->Characteristics) & 0x02)
87 {
88 reset_file_recovery(file_recovery_new);
89 file_recovery_new->extension=file_hint_exe.extension;
90 }
91 else
92 {
93 #ifdef DEBUG_EXE
94 log_warning("EXE rejected, bad characteristics %02x\n", le16(pe_hdr->Characteristics));
95 #endif
96 return 0;
97 }
98 file_recovery_new->time=le32(pe_hdr->TimeDateStamp);
99 #ifdef DEBUG_EXE
100 {
101 const struct pe_image_optional_hdr32 *pe_image_optional32=(const struct pe_image_optional_hdr32 *)
102 (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
103 if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR_MAGIC)
104 {
105 log_debug("SizeOfCode %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfCode));
106 log_debug("SizeOfImage %lx\n", (long unsigned)le32(pe_image_optional32->SizeOfImage));
107 }
108 else if(le16(pe_image_optional32->Magic)==IMAGE_NT_OPTIONAL_HDR64_MAGIC)
109 {
110 const struct pe_image_optional_hdr64 *pe_image_optional64=(const struct pe_image_optional_hdr64 *)
111 (((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr)));
112 }
113 log_debug("PE image opt 0x%lx-0x%lx\n", (long unsigned)sizeof(struct pe_image_file_hdr),
114 (long unsigned)(sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader) - 1));
115 }
116 #endif
117 {
118 unsigned int i;
119 uint64_t sum=0;
120 const struct pe_image_section_hdr *pe_image_section=(const struct pe_image_section_hdr*)
121 ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
122 for(i=0;
123 i<le16(pe_hdr->NumberOfSections) &&
124 (const unsigned char*)(pe_image_section+1) <= buffer+buffer_size;
125 i++,pe_image_section++)
126 {
127 if(le32(pe_image_section->SizeOfRawData)>0)
128 {
129 #ifdef DEBUG_EXE
130 log_debug("%s 0x%lx-0x%lx\n", pe_image_section->Name,
131 (unsigned long)le32(pe_image_section->PointerToRawData),
132 (unsigned long)le32(pe_image_section->PointerToRawData)+le32(pe_image_section->SizeOfRawData)-1);
133 #endif
134 if(le32(pe_image_section->SizeOfRawData)%32==0)
135 {
136 if(sum < le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData))
137 sum=le32(pe_image_section->PointerToRawData) + le32(pe_image_section->SizeOfRawData);
138 }
139 }
140 if(le16(pe_image_section->NumberOfRelocations)>0)
141 {
142 #ifdef DEBUG_EXE
143 log_debug("relocations 0x%lx-0x%lx\n",
144 (unsigned long)le32(pe_image_section->PointerToRelocations),
145 (unsigned long)le32(pe_image_section->PointerToRelocations)+1*le16(pe_image_section->NumberOfRelocations)-1);
146 #endif
147 if(sum < le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations))
148 sum = le32(pe_image_section->PointerToRelocations)+ 1*le16(pe_image_section->NumberOfRelocations);
149 }
150 }
151 if(le32(pe_hdr->NumberOfSymbols)>0)
152 {
153 #ifdef DEBUG_EXE
154 log_debug("Symboles 0x%lx-0x%lx\n", (long unsigned)le32(pe_hdr->PointerToSymbolTable),
155 (long unsigned)(le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))-1);
156 #endif
157 if(le32(pe_hdr->NumberOfSymbols)<0x10000)
158 {
159 if(sum < le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols))
160 sum = le32(pe_hdr->PointerToSymbolTable)+ IMAGE_SIZEOF_SYMBOL*le32(pe_hdr->NumberOfSymbols);
161 }
162 }
163 /* It's not perfect, EXE overlay are not recovered */
164 file_recovery_new->calculated_file_size=sum;
165 }
166 file_recovery_new->data_check=&data_check_size;
167 file_recovery_new->file_check=&file_check_size;
168 file_recovery_new->file_rename=&file_rename_pe_exe;
169 return 1;
170 }
171 if(le16(dos_hdr->bytes_in_last_block) <= 512 &&
172 le16(dos_hdr->blocks_in_file) > 0 &&
173 le16(dos_hdr->min_extra_paragraphs) <= le16(dos_hdr->max_extra_paragraphs)
174 )
175 {
176 /* MSDOS EXE */
177 uint64_t coff_offset=le16(dos_hdr->blocks_in_file)*512;
178 if(le16(dos_hdr->bytes_in_last_block))
179 coff_offset-=512-le16(dos_hdr->bytes_in_last_block);
180
181 if(coff_offset < buffer_size-1 &&
182 buffer[coff_offset]==0x4c && buffer[coff_offset+1]==0x01)
183 { /* COFF_I386MAGIC */
184 reset_file_recovery(file_recovery_new);
185 file_recovery_new->extension=file_hint_exe.extension;
186 return 1;
187 }
188 #ifdef DEBUG_EXE
189 {
190 unsigned int i;
191 const struct exe_reloc *exe_reloc;
192 log_info("Maybe a DOS EXE\n");
193 log_info("blocks %llu\n", (long long unsigned)coff_offset);
194 log_info("data start %llx\n", (long long unsigned)16*le16(dos_hdr->header_paragraphs));
195 log_info("reloc %u\n", le16(dos_hdr->num_relocs));
196 for(i=0, exe_reloc=(const struct exe_reloc *)(buffer+le16(dos_hdr->reloc_table_offset));
197 i < le16(dos_hdr->num_relocs) &&
198 le16(dos_hdr->reloc_table_offset)+ (i+1)*sizeof(struct exe_reloc) < buffer_size;
199 i++, exe_reloc++)
200 {
201 log_info("offset %x, segment %x\n",
202 le16(exe_reloc->offset), le16(exe_reloc->segment));
203 }
204 }
205 #endif
206 }
207 return 0;
208 }
209
210 struct rsrc_entries_s
211 {
212 uint32_t Type;
213 uint32_t Pos;
214 } __attribute__ ((gcc_struct, __packed__));
215
216 struct PE_index
217 {
218 uint16_t len;
219 uint16_t val_len;
220 uint16_t type;
221 } __attribute__ ((gcc_struct, __packed__));
222
223 static char vs_version_info[32]={
224 'V', 0x0, 'S', 0x0, '_', 0x0, 'V', 0x0, 'E', 0x0, 'R', 0x0, 'S', 0x0, 'I', 0x0,
225 'O', 0x0, 'N', 0x0, '_', 0x0, 'I', 0x0, 'N', 0x0, 'F', 0x0, 'O', 0x0, 0x0, 0x0
226 };
227
228 static char StringFileInfo[30]={
229 'S', 0x0, 't', 0x0, 'r', 0x0, 'i', 0x0, 'n', 0x0, 'g', 0x0, 'F', 0x0, 'i', 0x0,
230 'l', 0x0, 'e', 0x0, 'I', 0x0, 'n', 0x0, 'f', 0x0, 'o', 0x0, 0x0, 0x0
231 };
232
233 static char OriginalFilename[34]={
234 'O', 0x0, 'r', 0x0, 'i', 0x0, 'g', 0x0, 'i', 0x0, 'n', 0x0, 'a', 0x0, 'l', 0x0,
235 'F', 0x0, 'i', 0x0, 'l', 0x0, 'e', 0x0, 'n', 0x0, 'a', 0x0, 'm', 0x0, 'e', 0x0,
236 0x0, 0x0
237 };
238
239 static char InternalName[24]={
240 'I', 0x0, 'n', 0x0, 't', 0x0, 'e', 0x0, 'r', 0x0, 'n', 0x0, 'a', 0x0, 'l', 0x0,
241 'N', 0x0, 'a', 0x0, 'm', 0x0, 'e', 0x0
242 };
243
ReadUnicodeStr(const char * buffer,unsigned int pos,const unsigned int len)244 static unsigned int ReadUnicodeStr(const char *buffer, unsigned int pos, const unsigned int len)
245 {
246 for(; pos+2<len && (buffer[pos]!='\0' || buffer[pos+1]!='\0'); pos+=2)
247 {
248 #ifdef DEBUG_EXE
249 log_info("%c", buffer[pos]);
250 #endif
251 }
252 pos+=2;
253 if((pos & 0x03)!=0)
254 pos+=2;
255 return pos;
256 }
257
PEVersion_aux(file_recovery_t * file_recovery,const char * buffer,const unsigned int end,const char * needle,const unsigned int needle_len,const int force_ext)258 static int PEVersion_aux(file_recovery_t *file_recovery, const char*buffer, const unsigned int end, const char *needle, const unsigned int needle_len, const int force_ext)
259 {
260 unsigned int pos=0;
261 while(1)
262 {
263 const struct PE_index *PE_index;
264 pos=(pos + 3) & 0xfffffffc; /* align on a 4-byte boundary */
265 if(pos + 6 > end)
266 {
267 return -1;
268 }
269 PE_index=(const struct PE_index*)&buffer[pos];
270 if(le16(PE_index->len)==0 && le16(PE_index->val_len)==0)
271 {
272 return -1;
273 }
274 {
275 const char *stringName=&buffer[pos+6];
276 if(pos + 6 + sizeof(vs_version_info) < end &&
277 memcmp(stringName, vs_version_info, sizeof(vs_version_info))==0)
278 {
279 pos+=6+sizeof(vs_version_info);
280 if((pos & 0x03)!=0)
281 pos+=2;
282 pos+=le16(PE_index->val_len);
283 }
284 else if(pos + 6 + sizeof(StringFileInfo) < end &&
285 memcmp(stringName, StringFileInfo, sizeof(StringFileInfo))==0 &&
286 le16(PE_index->val_len)==0)
287 {
288 unsigned int i;
289 unsigned int pt=pos+6+sizeof(StringFileInfo);
290 pos+=le16(PE_index->len);
291 for(i=0; pt + 6 < pos; i++)
292 {
293 if(i==0)
294 {
295 pt=ReadUnicodeStr(buffer, pt+6, pos);
296 }
297 else
298 {
299 int do_rename=0;
300 PE_index=(const struct PE_index*)&buffer[pt];
301 if(pt+6+needle_len < end &&
302 memcmp(&buffer[pt+6], needle, needle_len)==0)
303 {
304 do_rename=1;
305 }
306 pt=ReadUnicodeStr(buffer, pt+6, pos);
307 if(le16(PE_index->val_len)>0)
308 {
309 if(do_rename)
310 {
311 file_rename_unicode(file_recovery, buffer, end, pt, NULL, force_ext);
312 return 0;
313 }
314 #ifdef DEBUG_EXE
315 log_info(": ");
316 #endif
317 pt=ReadUnicodeStr(buffer, pt, pos);
318 }
319 }
320 #ifdef DEBUG_EXE
321 log_info("\n");
322 #endif
323 }
324 }
325 else
326 {
327 pos+=le16(PE_index->len)+le16(PE_index->val_len);
328 }
329 }
330 }
331 }
332
PEVersion(FILE * file,const unsigned int offset,const unsigned int length,file_recovery_t * file_recovery)333 static void PEVersion(FILE *file, const unsigned int offset, const unsigned int length, file_recovery_t *file_recovery)
334 {
335 char *buffer;
336 if(length==0 || length > 1024*1024)
337 return;
338 if(fseek(file, offset, SEEK_SET)<0)
339 return ;
340 buffer=(char*)MALLOC(length);
341 if(fread(buffer, length, 1, file) != 1)
342 {
343 free(buffer);
344 return ;
345 }
346 if(PEVersion_aux(file_recovery, buffer, length, OriginalFilename, sizeof(OriginalFilename), 0)==0)
347 {
348 free(buffer);
349 return;
350 }
351 PEVersion_aux(file_recovery, buffer, length, InternalName, sizeof(InternalName), 1);
352 free(buffer);
353 }
354
file_exe_ressource(FILE * file,const unsigned int base,const unsigned int dir_start,const unsigned int size,const unsigned int rsrcType,const unsigned int level,const struct pe_image_section_hdr * pe_sections,unsigned int nbr_sections,file_recovery_t * file_recovery)355 static void file_exe_ressource(FILE *file, const unsigned int base, const unsigned int dir_start, const unsigned int size, const unsigned int rsrcType, const unsigned int level, const struct pe_image_section_hdr *pe_sections, unsigned int nbr_sections, file_recovery_t *file_recovery)
356 {
357 struct rsrc_entries_s *rsrc_entries;
358 struct rsrc_entries_s *rsrc_entry;
359 unsigned char buffer[16];
360 int buffer_size;
361 unsigned int nameEntries;
362 unsigned idEntries;
363 unsigned int count;
364 unsigned int i;
365 #ifdef DEBUG_EXE
366 log_info("file_exe_ressource(file, %u, %u, %u, %u)\n", base, dir_start, size, level);
367 #endif
368 if(level > 2)
369 return ;
370 if(fseek(file, base + dir_start, SEEK_SET)<0)
371 return ;
372 buffer_size=fread(buffer, 1, sizeof(buffer), file);
373 if(buffer_size<16)
374 return ;
375 nameEntries = buffer[12]+(buffer[13]<<8);
376 idEntries = buffer[14]+(buffer[15]<<8);
377 count = nameEntries + idEntries;
378 if(count==0 || count > 1024)
379 return ;
380 rsrc_entries=(struct rsrc_entries_s *)MALLOC(count * sizeof(struct rsrc_entries_s));
381 if(fread(rsrc_entries, sizeof(struct rsrc_entries_s), count, file) != count)
382 {
383 free(rsrc_entries);
384 return ;
385 }
386 for(i=0, rsrc_entry=rsrc_entries; i<count; i++, rsrc_entry++)
387 {
388 const unsigned int rsrcType_new=(level==0?le32(rsrc_entry->Type):rsrcType);
389 #ifdef DEBUG_EXE
390 log_info("ressource %u, %x, offset %u\n",
391 rsrcType_new,
392 le32(rsrc_entry->Pos),
393 base + (le32(rsrc_entry->Pos) & 0x7fffffff));
394 #endif
395 /* Only intersted by version resources */
396 if(rsrcType_new==16)
397 {
398 if((le32(rsrc_entry->Pos) & 0x80000000)!=0)
399 {
400 file_exe_ressource(file,
401 base,
402 le32(rsrc_entry->Pos) & 0x7fffffff,
403 size,
404 (level==0?le32(rsrc_entry->Type):rsrcType),
405 level + 1,
406 pe_sections, nbr_sections, file_recovery);
407 }
408 if(level==2)
409 {
410 unsigned int off;
411 unsigned int len;
412 if(fseek(file, base + (le32(rsrc_entry->Pos) & 0x7fffffff), SEEK_SET)<0)
413 {
414 free(rsrc_entries);
415 return ;
416 }
417 buffer_size=fread(buffer, 1, sizeof(buffer), file);
418 if(buffer_size<16)
419 {
420 free(rsrc_entries);
421 return ;
422 }
423 off=buffer[0]+ (buffer[1]<<8) + (buffer[2]<<16) + (buffer[3]<<24);
424 len=buffer[4]+ (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
425 {
426 const struct pe_image_section_hdr *pe_section;
427 for(i=0, pe_section=pe_sections; i<nbr_sections; i++,pe_section++)
428 {
429 if(le32(pe_section->VirtualAddress) <= off
430 && off < le32(pe_section->VirtualAddress) + le32(pe_section->SizeOfRawData))
431 {
432 PEVersion(file, off - le32(pe_section->VirtualAddress) + base, len, file_recovery);
433 free(rsrc_entries);
434 return ;
435 }
436 }
437 }
438 free(rsrc_entries);
439 return ;
440 }
441 }
442 }
443 free(rsrc_entries);
444 }
445
file_rename_pe_exe(file_recovery_t * file_recovery)446 static void file_rename_pe_exe(file_recovery_t *file_recovery)
447 {
448 unsigned char buffer[4096];
449 FILE *file;
450 int buffer_size;
451 const struct dos_image_file_hdr *dos_hdr=(const struct dos_image_file_hdr*)buffer;
452 const struct pe_image_file_hdr *pe_hdr;
453 if((file=fopen(file_recovery->filename, "rb"))==NULL)
454 return;
455 buffer_size=fread(buffer, 1, sizeof(buffer), file);
456 if(buffer_size < (int)sizeof(struct dos_image_file_hdr))
457 {
458 fclose(file);
459 return ;
460 }
461 if(memcmp(buffer,exe_header,sizeof(exe_header))!=0)
462 {
463 fclose(file);
464 return ;
465 }
466 if((unsigned int)buffer_size < le32(dos_hdr->e_lfanew)+sizeof(struct pe_image_file_hdr))
467 {
468 fclose(file);
469 return ;
470 }
471 pe_hdr=(const struct pe_image_file_hdr *)(buffer+le32(dos_hdr->e_lfanew));
472 if(le32(dos_hdr->e_lfanew)==0 ||
473 le32(dos_hdr->e_lfanew) > buffer_size-sizeof(struct pe_image_file_hdr) ||
474 le32(pe_hdr->Magic) != IMAGE_NT_SIGNATURE)
475 {
476 fclose(file);
477 return ;
478 }
479 {
480 unsigned int i;
481 const struct pe_image_section_hdr *pe_sections;
482 const struct pe_image_section_hdr *pe_section;
483 unsigned int nbr_sections;
484 pe_sections=(const struct pe_image_section_hdr*)
485 ((const unsigned char*)pe_hdr + sizeof(struct pe_image_file_hdr) + le16(pe_hdr->SizeOfOptionalHeader));
486 for(i=0, pe_section=pe_sections;
487 i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_section < buffer+buffer_size;
488 i++, pe_section++)
489 {
490 #ifdef DEBUG_EXE
491 if(le32(pe_section->SizeOfRawData)>0)
492 {
493 log_info("%s 0x%lx-0x%lx\n", pe_section->Name,
494 (unsigned long)le32(pe_section->VirtualAddress),
495 (unsigned long)le32(pe_section->VirtualAddress)+le32(pe_section->VirtualSize)-1);
496 }
497 #endif
498 }
499 nbr_sections=i;
500 for(i=0, pe_section=pe_sections;
501 i<le16(pe_hdr->NumberOfSections) && (const unsigned char*)pe_section < buffer+buffer_size;
502 i++, pe_section++)
503 {
504 if(le32(pe_section->SizeOfRawData)>0)
505 {
506 if(memcmp((const char*)pe_section->Name, ".rsrc", 6)==0)
507 {
508 file_exe_ressource(file,
509 le32(pe_section->PointerToRawData),
510 0,
511 le32(pe_section->SizeOfRawData),
512 0,
513 0,
514 pe_sections, nbr_sections, file_recovery);
515 fclose(file);
516 return;
517 }
518 }
519 }
520 }
521 fclose(file);
522 }
523