1 /**
2  * Alex Eubanks, June 2012 - endeavor at rainbowsandpwnies.com
3  * The structures used for this code come from
4  * https://github.com/endeav0r/Rainbows-And-Pwnies-Tools .
5  *
6  * Originally (C) 2011 Alex Eubanks.
7  * Released into the public domain on June 7, 2012.
8  *
9  * The names and values used in XML may seem large/redundant, but they
10  * mirror those found in the PE specification given by Microsoft.
11  *
12  * For a description of the meanings of the field names below, please see
13  * "Microsoft PE and COFF Specification,"
14  * http://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
15 
16  * Revision history:
17  * 2015-april   bda - Removed requirement that pe_NumberOfRvaAndSizes, hardcoded
18                       to 16, be defined, since some data was found where it was
19                       0, resulting in failure to extract valid dll filenames.
20  * 2015-april   bda - added PE carving.
21  */
22 
23 
24 #include "config.h"
25 #include "be13_api/utils.h"  // needs config.h
26 #include "be13_api/scanner_params.h"
27 
28 /**
29  * XML_SPEC
30  PE
31  FileHeader
32  @Machine =>   "IMAGE_FILE_MACHINE_AMD64"
33  | "IMAGE_FILE_MACHINE_ARM"
34  | "IMAGE_FILE_MACHINE_ARMV7"
35  | "IMAGE_FILE_MACHINE_I386"
36  | "IMAGE_FILE_MACHINE_IA64"
37  @NumberOfSections     => %d
38  @TimeDateStamp        => %d
39  @TimeDateStampISO     => %s
40  @PointToSymbolTable   => %d
41  @NumberOfSymbols      => %d
42  @SizeOfOptionalHeader => %d
43  Characteristics
44  IMAGE_FILE_RELOCS_STRIPPED  // these tags are present if
45  ...                         // bits were set in
46  IMAGE_FILE_BYTES_REVERSE_HI // Characteristics
47  OptionalHeaderStandard // Same name and attributes for both PE
48  *                      // and PE+ to simplify parser writing
49  @Magic => "PE32" | "PE32+"
50  @MajorLinkerVersion    => %d
51  @MinorLinkerVersion    => %d
52  @SizeOfCode            => %d
53  @SizeOfInitializedData => %d
54  @AddressOfEntryPoint   => 0x%x
55  @BaseOfCode            => 0x%x
56  OptionalHeaderWindows // Same name and attributes for both PE
57  *                     // and PE+ to simplify parser writing
58  @ImageBase        => 0x%x
59  @SectionAlignment => %d
60  @FileAlignment    => %d
61  @MajorOperatingSystemVersion => %d
62  @MinorOperatingSystemVersion => %d
63  @MajorImageVersion     => %d
64  @MinorImageVersion     => %d
65  @MajorSubsystemVersion => %d
66  @MinorSubsystemVersion => %d
67  @Win32VersionValue     => %d
68  @SizeOfImage           => %d
69  @SizeOfHeaders         => %d
70  @CheckSum              => 0x%x
71  @Subsystem =>    IMAGE_SUBSYSTEM_UNKNOWN
72  ..
73  IMAGE_SUBSYSTEM_XBOX
74  @SizeOfStackReserve  => %d
75  @SizeOfStackCommit   => %d
76  @SizeOfHeapReserve   => %d
77  @SizeOfHeadCommit    => %d
78  @LoaderFlags         => %d // reserved, should always be
79  *                          // zero
80  @NumberOfRvaAndSizes => %d
81  DllCharacteristics
82  IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE // tags present
83  ..                                     // if bits set
84  IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE
85  sections
86  SectionHeader
87  @Name                 => %s
88  @VirtualSize          => %d
89  @VirtualAddress       => %d
90  @SizeOfRawData        => %d
91  @PointerToRawData     => %d
92  @PointerToRelocations => %d
93  @PointerToLinenumbers => %d
94  @NumberOfRelocations  => %d
95  @NumberOfLinenumbers  => %d
96  Characteristics
97  IMAGE_SCN_TYPE_REG  // tags present if bits set
98  ..
99  IMAGE_SCN_MEM_WRITE
100  dlls
101  dll => %s
102  // <dlls><dll>msvcrt.dll</dll><dll>ntdll.dll</dll></dlls>
103  */
104 
105 
106 
107 #define PE_SIGNATURE         "PE\0\0"
108 #define PE_SIGNATURE_SIZE    4
109 
110 enum E {
111     PE_FILE_OFFSET = 0x3c,
112 };
113 
114 #ifndef IMAGE_FILE_MACHINE_AM33
115 #define IMAGE_FILE_MACHINE_UNKNOWN   0x0
116 #define IMAGE_FILE_MACHINE_AM33      0x1d3
117 #define IMAGE_FILE_MACHINE_ALPHA     0x184
118 #define IMAGE_FILE_MACHINE_AMD64     0x8664
119 #define IMAGE_FILE_MACHINE_ARM       0x1c0
120 #define IMAGE_FILE_MACHINE_ARMV7     0x1c4
121 #define IMAGE_FILE_MACHINE_ALPHA64   0x284
122 #define IMAGE_FILE_MACHINE_I386      0x14c
123 #define IMAGE_FILE_MACHINE_IA64      0x200
124 #define IMAGE_FILE_MACHINE_M68K      0x268
125 #define IMAGE_FILE_MACHINE_MIPS16    0x266
126 #define IMAGE_FILE_MACHINE_MIPSFPU   0x366
127 #define IMAGE_FILE_MACHINE_MIPSFPU16 0x466
128 #define IMAGE_FILE_MACHINE_POWERPC   0x1f0
129 #define IMAGE_FILE_MACHINE_R3000     0x162
130 #define IMAGE_FILE_MACHINE_R4000     0x166
131 #define IMAGE_FILE_MACHINE_R10000    0x168
132 #define IMAGE_FILE_MACHINE_SH3       0x1a2
133 #define IMAGE_FILE_MACHINE_SH4       0x1a6
134 #define IMAGE_FILE_MACHINE_THUMB     0x1c2
135 #endif
136 
137 #define IMAGE_FILE_RELOCS_STRIPPED         0x0001
138 #define IMAGE_FILE_EXECUTABLE_IMAGE        0x0002
139 #define IMAGE_FILE_LINE_NUMS_STRIPPED      0x0004
140 #define IMAGE_FILE_LOCAL_SYMS_STRIPPED     0x0008
141 #define IMAGE_FILE_AGRESSIVE_WS_TRIM       0x0010
142 #define IMAGE_FILE_LARGE_ADDRESS_AWARE     0x0020
143 #define IMAGE_FILE_16BIT_MACHINE           0x0040
144 #define IMAGE_FILE_BYTES_REVERSED_LO       0x0080
145 #define IMAGE_FILE_32BIT_MACHINE           0x0100
146 #define IMAGE_FILE_DEBUG_STRIPPED          0x0200
147 #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
148 #define IMAGE_FILE_SYSTEM                  0x1000
149 #define IMAGE_FILE_DLL                     0x2000
150 #define IMAGE_FILE_UP_SYSTEM_ONLY          0x4000
151 #define IMAGE_FILE_BYTES_REVERSE_HI        0x8000
152 
153 #define IMAGE_SUBSYSTEM_UNKNOWN                 0
154 #define IMAGE_SUBSYSTEM_NATIVE                  1
155 #define IMAGE_SUBSYSTEM_WINDOWS_GUI             2
156 #define IMAGE_SUBSYSTEM_WINDOWS_CUI             3
157 #define IMAGE_SUBSYSTEM_POSIX_CUI               7
158 #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI          9
159 #define IMAGE_SUBSYSTEM_EFI_APPLICATION         10
160 #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
161 #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER      12
162 #define IMAGE_SUBSYSTEM_EFI_ROM                 13
163 #define IMAGE_SUBSYSTEM_XBOX                    14
164 
165 #define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE          0x0040
166 #define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY       0x0080
167 #define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT             0x0100
168 #define IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION          0x0200
169 #define IMAGE_DLL_CHARACTERISTICS_NO_SEH                0x0400
170 #define IMAGE_DLL_CHARACTERISTICS_NO_BIND               0x0800
171 #define IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER            0x2000
172 #define IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
173 
174 #define IMAGE_SCN_TYPE_REG               0x00000000
175 #define IMAGE_SCN_TYPE_DSECT             0x00000001
176 #define IMAGE_SCN_TYPE_NOLOAD            0x00000002
177 #define IMAGE_SCN_TYPE_GROUP             0x00000004
178 #define IMAGE_SCN_TYPE_NO_PAD            0x00000008
179 #define IMAGE_SCN_TYPE_COPY              0x00000010
180 #define IMAGE_SCN_CNT_CODE               0x00000020
181 #define IMAGE_SCN_CNT_INITIALIZED_DATA   0x00000040
182 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
183 #define IMAGE_SCN_LNK_OTHER              0x00000100
184 #define IMAGE_SCN_LNK_INFO               0x00000200
185 #define IMAGE_SCN_TYPE_OVER              0x00000400
186 #define IMAGE_SCN_LNK_REMOVE             0x00000800
187 #define IMAGE_SCN_LNK_COMDAT             0x00001000
188 #define IMAGE_SCN_MEM_FARDATA            0x00008000
189 #define IMAGE_SCN_MEM_PURGEABLE          0x00020000
190 #define IMAGE_SCN_MEM_16BIT              0x00020000
191 #define IMAGE_SCN_MEM_LOCKED             0x00040000
192 #define IMAGE_SCN_MEM_PRELOAD            0x00080000
193 #define IMAGE_SCN_ALIGN_1BYTES           0x00100000
194 #define IMAGE_SCN_ALIGN_2BYTES           0x00200000
195 #define IMAGE_SCN_ALIGN_4BYTES           0x00300000
196 #define IMAGE_SCN_ALIGN_8BYTES           0x00400000
197 #define IMAGE_SCN_ALIGN_16BYTES          0x00500000
198 #define IMAGE_SCN_ALIGN_32BYTES          0x00600000
199 #define IMAGE_SCN_ALIGN_64BYTES          0x00700000
200 #define IMAGE_SCN_ALIGN_128BYTES         0x00800000
201 #define IMAGE_SCN_ALIGN_256BYTES         0x00900000
202 #define IMAGE_SCN_ALIGN_512BYTES         0x00A00000
203 #define IMAGE_SCN_ALIGN_1024BYTES        0x00B00000
204 #define IMAGE_SCN_ALIGN_2048BYTES        0x00C00000
205 #define IMAGE_SCN_ALIGN_4096BYTES        0x00D00000
206 #define IMAGE_SCN_ALIGN_8192BYTES        0x00E00000
207 #define IMAGE_SCN_LNK_NRELOC_OVFL        0x01000000
208 #define IMAGE_SCN_MEM_DISCARDABLE        0x02000000
209 #define IMAGE_SCN_MEM_NOT_CACHED         0x04000000
210 #define IMAGE_SCN_MEM_NOT_PAGED          0x08000000
211 #define IMAGE_SCN_MEM_SHARED             0x10000000
212 #define IMAGE_SCN_MEM_EXECUTE            0x20000000
213 #define IMAGE_SCN_MEM_READ               0x40000000
214 #define IMAGE_SCN_MEM_WRITE              0x80000000
215 
216 #define IMAGE_FILE_TYPE_PE32     0x10b
217 #define IMAGE_FILE_TYPE_PE32PLUS 0x20b
218 
219 #define PE_SECTION_RESERVED_FLAGS 0x00000417
220 
221 /* For information on __attribute__((packed)), see:
222  * http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Type-Attributes.html
223  */
224 
225 // tunable parameter
226 
227 typedef struct _Pe_Fileheader {
228     uint16_t Machine              __attribute__((packed));
229     uint16_t NumberOfSections     __attribute__((packed));
230     uint32_t TimeDateStamp        __attribute__((packed));
231     uint32_t PointerToSymbolTable __attribute__((packed));
232     uint32_t NumberOfSymbols      __attribute__((packed));
233     uint16_t SizeOfOptionalHeader __attribute__((packed));
234     uint16_t Characteristics      __attribute__((packed));
235 } __attribute__((packed)) Pe_FileHeader;
236 
237 typedef struct _Pe_OptionalHeaderStandard {
238     uint16_t Magic;                   // 2
239     uint8_t  MajorLinkerVersion;      // 3
240     uint8_t  MinorLinkerVersion;      // 4
241     uint32_t SizeOfCode;              // 8
242     uint32_t SizeOfInitializedData;   // 12
243     uint32_t SizeOfUninitializedData; // 16
244     uint32_t AddressOfEntryPoint;     // 20
245     uint32_t BaseOfCode;              // 24
246     uint32_t BaseOfData;              // 28
247 } __attribute__((packed)) Pe_OptionalHeaderStandard;
248 
249 typedef struct _Pe_OptionalHeaderStandardPlus {
250     uint16_t Magic;                   // 2
251     uint8_t  MajorLinkerVersion;      // 3
252     uint8_t  MinorLinkerVersion;      // 4
253     uint32_t SizeOfCode;              // 8
254     uint32_t SizeOfInitializedData;   // 12
255     uint32_t SizeOfUninitializedData; // 16
256     uint32_t AddressOfEntryPoint;     // 20
257     uint32_t BaseOfCode;              // 24
258 } __attribute__((packed)) Pe_OptionalHeaderStandardPlus;
259 
260 typedef struct _Pe_OptionalHeaderWindows {
261     uint32_t ImageBase;                   // 32
262     uint32_t SectionAlignment;            // 36
263     uint32_t FileAlignment;               // 40
264     uint16_t MajorOperatingSystemVersion; // 42
265     uint16_t MinorOperatingSystemVersion; // 44
266     uint16_t MajorImageVersion;           // 46
267     uint16_t MinorImageVersion;           // 48
268     uint16_t MajorSubsystemVersion;       // 50
269     uint16_t MinorSubsystemVersion;       // 52
270     uint32_t Win32VersionValue;           // 56
271     uint32_t SizeOfImage;                 // 60
272     uint32_t SizeOfHeaders;               // 64
273     uint32_t CheckSum;                    // 68
274     uint16_t Subsystem;                   // 70
275     uint16_t DllCharacteristics;          // 72
276     uint32_t SizeOfStackReserve;          // 76
277     uint32_t SizeOfStackCommit;           // 80
278     uint32_t SizeOfHeapReserve;           // 84
279     uint32_t SizeOfHeapCommit;            // 88
280     uint32_t LoaderFlags;                 // 92
281     uint32_t NumberOfRvaAndSizes;         // 96
282 } __attribute__((packed)) Pe_OptionalHeaderWindows;
283 
284 typedef struct _Pe_OptionalHeaderWindowsPlus {
285     uint64_t ImageBase;                   // 32
286     uint32_t SectionAlignment;            // 36
287     uint32_t FileAlignment;               // 40
288     uint16_t MajorOperatingSystemVersion; // 42
289     uint16_t MinorOperatingSystemVersion; // 44
290     uint16_t MajorImageVersion;           // 46
291     uint16_t MinorImageVersion;           // 48
292     uint16_t MajorSubsystemVersion;       // 50
293     uint16_t MinorSubsystemVersion;       // 52
294     uint32_t Win32VersionValue;           // 56
295     uint32_t SizeOfImage;                 // 60
296     uint32_t SizeOfHeaders;               // 64
297     uint32_t CheckSum;                    // 68
298     uint16_t Subsystem;                   // 70
299     uint16_t DllCharacteristics;          // 72
300     uint64_t SizeOfStackReserve;          // 80
301     uint64_t SizeOfStackCommit;           // 88
302     uint64_t SizeOfHeapReserve;           // 96
303     uint64_t SizeOfHeapCommit;            // 104
304     uint32_t LoaderFlags;                 // 108
305     uint32_t NumberOfRvaAndSizes;         // 112
306 } __attribute__((packed)) Pe_OptionalHeaderWindowsPlus;
307 
308 typedef struct _Pe_SectionHeader {
309     char Name[8];                  // 8
310     uint32_t VirtualSize;          // 12
311     uint32_t VirtualAddress;       // 16
312     uint32_t SizeOfRawData;        // 20
313     uint32_t PointerToRawData;     // 24
314     uint32_t PointerToRelocations; // 28
315     uint32_t PointerToLinenumbers; // 32
316     uint16_t NumberOfRelocations;  // 34
317     uint16_t NumberOfLinenumbers;  // 36
318     uint32_t Characteristics;      // 40
319 } __attribute__((packed)) Pe_SectionHeader;
320 
321 typedef struct _Pe_ImportDirectoryTable {
322     uint32_t ImportLookupTableRVA;
323     uint32_t TimeDateStamp;
324     uint32_t ForwarderChain;
325     uint32_t NameRVA;
326     uint32_t ImportAddressTableRVA;
327 } Pe_ImportDirectoryTable;
328 
operator <<(std::ostream & os,const Pe_ImportDirectoryTable & idt)329 std::ostream & operator << (std::ostream &os,const Pe_ImportDirectoryTable &idt){
330     os << " ImportLookupTableRVA=" << idt.ImportLookupTableRVA
331        << " TimeDateStamp=" << idt.TimeDateStamp
332        << " ForwarderChain=" << idt.ForwarderChain
333        << " NameRVA=" << idt.NameRVA
334        << " ImportAddressTableRVA=" << idt.ImportAddressTableRVA;
335     return os;
336 };
337 
338 typedef struct _Pe_DataDirectory {
339     uint32_t VirtualAddress;
340     uint32_t Size;
341 } Pe_DataDirectory;
342 
343 
344 /** Machinery to turn bitfields into XML */
345 #define FLAGNAME(STR) {STR,#STR}
346 struct  flagnames_t {
347     uint32_t flag;
348     const char *name;
349 };
350 
decode_flags(std::stringstream & xml,const std::string & sectionName,const struct flagnames_t flagnames[],const uint32_t flags)351 static void decode_flags (std::stringstream &xml,
352                           const std::string &sectionName,
353                           const struct flagnames_t flagnames[],
354                           const uint32_t flags)
355 {
356     xml << "<" << sectionName << ">";
357     for (size_t i = 0; flagnames[i].name; i++) {
358         if (flags & flagnames[i].flag) xml << "<" << flagnames[i].name << " />";
359     }
360     xml << "</" << sectionName << ">";
361 }
362 
363 // this is going to return a string because it returns empty string if
364 // the value was not found
match_switch_case(const struct flagnames_t flagnames[],const uint32_t needle)365 static std::string match_switch_case (const struct flagnames_t flagnames[],
366                                  const uint32_t needle)
367 {
368     int i;
369     for (i = 0; flagnames[i].flag; i++) {
370         if (needle == flagnames[i].flag) return flagnames[i].name;
371     }
372     return "";
373 }
374 
375 // Breaks out PE Section Characteristics into xml. This number of these
376 // make section header parsing code ugly, so we break it out
377 
378 struct flagnames_t pe_section_characteristic_names[] = {
379     FLAGNAME(IMAGE_SCN_TYPE_REG),
380     FLAGNAME(IMAGE_SCN_TYPE_DSECT),
381     FLAGNAME(IMAGE_SCN_TYPE_NOLOAD),
382     FLAGNAME(IMAGE_SCN_TYPE_GROUP),
383     FLAGNAME(IMAGE_SCN_TYPE_NO_PAD),
384     FLAGNAME(IMAGE_SCN_TYPE_COPY),
385     FLAGNAME(IMAGE_SCN_CNT_CODE),
386     FLAGNAME(IMAGE_SCN_CNT_INITIALIZED_DATA),
387     FLAGNAME(IMAGE_SCN_CNT_UNINITIALIZED_DATA),
388     FLAGNAME(IMAGE_SCN_LNK_OTHER),
389     FLAGNAME(IMAGE_SCN_LNK_INFO),
390     FLAGNAME(IMAGE_SCN_TYPE_OVER),
391     FLAGNAME(IMAGE_SCN_LNK_REMOVE),
392     FLAGNAME(IMAGE_SCN_LNK_COMDAT),
393     FLAGNAME(IMAGE_SCN_MEM_FARDATA),
394     FLAGNAME(IMAGE_SCN_MEM_PURGEABLE),
395     FLAGNAME(IMAGE_SCN_MEM_16BIT),
396     FLAGNAME(IMAGE_SCN_MEM_LOCKED),
397     FLAGNAME(IMAGE_SCN_MEM_PRELOAD),
398     FLAGNAME(IMAGE_SCN_ALIGN_1BYTES),
399     FLAGNAME(IMAGE_SCN_ALIGN_2BYTES),
400     FLAGNAME(IMAGE_SCN_ALIGN_4BYTES),
401     FLAGNAME(IMAGE_SCN_ALIGN_8BYTES),
402     FLAGNAME(IMAGE_SCN_ALIGN_16BYTES),
403     FLAGNAME(IMAGE_SCN_ALIGN_32BYTES),
404     FLAGNAME(IMAGE_SCN_ALIGN_64BYTES),
405     FLAGNAME(IMAGE_SCN_ALIGN_128BYTES),
406     FLAGNAME(IMAGE_SCN_ALIGN_256BYTES),
407     FLAGNAME(IMAGE_SCN_ALIGN_512BYTES),
408     FLAGNAME(IMAGE_SCN_ALIGN_1024BYTES),
409     FLAGNAME(IMAGE_SCN_ALIGN_2048BYTES),
410     FLAGNAME(IMAGE_SCN_ALIGN_4096BYTES),
411     FLAGNAME(IMAGE_SCN_ALIGN_8192BYTES),
412     FLAGNAME(IMAGE_SCN_LNK_NRELOC_OVFL),
413     FLAGNAME(IMAGE_SCN_MEM_DISCARDABLE),
414     FLAGNAME(IMAGE_SCN_MEM_NOT_CACHED),
415     FLAGNAME(IMAGE_SCN_MEM_NOT_PAGED),
416     FLAGNAME(IMAGE_SCN_MEM_SHARED),
417     FLAGNAME(IMAGE_SCN_MEM_EXECUTE),
418     FLAGNAME(IMAGE_SCN_MEM_READ),
419     FLAGNAME(IMAGE_SCN_MEM_WRITE),
420     {0,0}
421 };
422 
423 struct flagnames_t pe_fileheader_characteristic_names[] = {
424     FLAGNAME(IMAGE_FILE_RELOCS_STRIPPED),
425     FLAGNAME(IMAGE_FILE_EXECUTABLE_IMAGE),
426     FLAGNAME(IMAGE_FILE_LINE_NUMS_STRIPPED),
427     FLAGNAME(IMAGE_FILE_LOCAL_SYMS_STRIPPED),
428     FLAGNAME(IMAGE_FILE_AGRESSIVE_WS_TRIM), // misspelling in spec!
429     FLAGNAME(IMAGE_FILE_LARGE_ADDRESS_AWARE),
430     FLAGNAME(IMAGE_FILE_16BIT_MACHINE),
431     FLAGNAME(IMAGE_FILE_BYTES_REVERSED_LO),
432     FLAGNAME(IMAGE_FILE_32BIT_MACHINE),
433     FLAGNAME(IMAGE_FILE_DEBUG_STRIPPED),
434     FLAGNAME(IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP),
435     FLAGNAME(IMAGE_FILE_SYSTEM),
436     FLAGNAME(IMAGE_FILE_DLL),
437     FLAGNAME(IMAGE_FILE_UP_SYSTEM_ONLY),
438     FLAGNAME(IMAGE_FILE_BYTES_REVERSE_HI),
439     {0,0}
440 };
441 
442 struct flagnames_t pe_optionalwindowsheader_dllcharacteristic[] = {
443     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE),
444     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY),
445     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_NX_COMPAT),
446     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION),
447     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_NO_SEH),
448     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_NO_BIND),
449     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER),
450     FLAGNAME(IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
451     {0,0}
452 };
453 
454 // There are more options available in the defines above, but we only
455 // check the values we expect to find in windows executables
456 struct flagnames_t pe_fileheader_machine[] = {
457     FLAGNAME(IMAGE_FILE_MACHINE_AMD64),
458     FLAGNAME(IMAGE_FILE_MACHINE_ARM),
459     FLAGNAME(IMAGE_FILE_MACHINE_ARMV7),
460     FLAGNAME(IMAGE_FILE_MACHINE_I386),
461     FLAGNAME(IMAGE_FILE_MACHINE_IA64),
462     {0,0}
463 };
464 
465 struct flagnames_t pe_optionalwindowsheader_subsystem[] = {
466     FLAGNAME(IMAGE_SUBSYSTEM_UNKNOWN),
467     FLAGNAME(IMAGE_SUBSYSTEM_NATIVE),
468     FLAGNAME(IMAGE_SUBSYSTEM_WINDOWS_GUI),
469     FLAGNAME(IMAGE_SUBSYSTEM_WINDOWS_CUI),
470     FLAGNAME(IMAGE_SUBSYSTEM_POSIX_CUI),
471     FLAGNAME(IMAGE_SUBSYSTEM_WINDOWS_CE_GUI),
472     FLAGNAME(IMAGE_SUBSYSTEM_EFI_APPLICATION),
473     FLAGNAME(IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER),
474     FLAGNAME(IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER),
475     FLAGNAME(IMAGE_SUBSYSTEM_EFI_ROM),
476     FLAGNAME(IMAGE_SUBSYSTEM_XBOX),
477     {0,0}
478 };
479 
480 // Takes a pointer to data which matches PE_SIGNATURE at PE_FILE_OFFSET
481 // Returns an empty string if this is not a PE, or a bunch of XML
482 // describing the PE if it is
483 
valid_dll_name(const std::string & dllname)484 static bool valid_dll_name(const std::string &dllname)
485 {
486     if (!validASCIIName(dllname)) return false;
487     if (dllname.size()<5) return false; /* DLL names have at least a character, a period and an extension */
488     if (dllname.at(dllname.size()-4)!='.') return false; // check for the '.'
489     return true;			// looks valid
490 }
491 
valid_section_name(const std::string & sectionName)492 static bool valid_section_name(const std::string &sectionName)
493 {
494     if(!validASCIIName(sectionName)) return false;
495     if(sectionName.size()<1) return false;
496     return true;
497 }
498 
scan_winpe_verify(const sbuf_t & sbuf)499 static std::string scan_winpe_verify (const sbuf_t &sbuf)
500 {
501     //const uint8_t * data = sbuf.buf;
502     size_t size          = sbuf.bufsize;
503 
504     size_t ohs_offset                          = 0;    // OptionalHeaderStandard
505     size_t ohw_offset                          = 0;    // OptionalHeaderWindows
506     //uint32_t     header_offset;
507     int          section_i;
508     std::stringstream xml;
509     //int dlli;
510 
511     // set Pe_FileHeader to correct address
512     uint32_t header_offset = sbuf.get32u(PE_FILE_OFFSET);
513 
514     // we adjust header_offset to account for PE_SIGNATURE_SIZE, and use
515     // header_offset throughout the code to insure we don't have
516     // out-of-bounds errors
517     header_offset += PE_SIGNATURE_SIZE;
518 
519     /******************************************
520      * BEGIN HEADER                            *
521      ******************************************/
522     if (header_offset + sizeof(Pe_FileHeader) > size)
523         return "";
524 
525     xml << "<PE><FileHeader";
526 
527     uint16_t pe_Machine              = sbuf.get16u(header_offset);
528     uint16_t pe_NumberOfSections     = sbuf.get16u(header_offset + 2);
529     uint32_t pe_TimeDateStamp        = sbuf.get32u(header_offset + 4);
530     std::string pe_TimeDateStampISO  = unixTimeToISODate(pe_TimeDateStamp);
531     uint32_t pe_PointerToSymbolTable = sbuf.get32u(header_offset + 8);
532     uint32_t pe_NumberOfSymbols      = sbuf.get32u(header_offset + 12);
533     uint16_t pe_SizeOfOptionalHeader = sbuf.get16u(header_offset + 16);
534     uint16_t pe_Characteristics      = sbuf.get16u(header_offset + 18);
535 
536     // 2^11.75 confidence, 2^20.25 to go
537     std::string Machine = match_switch_case(pe_fileheader_machine, pe_Machine);
538     if (Machine == "") return "";
539 
540     // A PE with (0|>256) sections? Doubtful
541     if ((pe_NumberOfSections == 0) || (pe_NumberOfSections > 256)) return "";
542 
543     if (    ((pe_NumberOfSymbols == 0) && (pe_PointerToSymbolTable != 0))
544 	    || (pe_NumberOfSymbols > 1000000)) return "";
545 
546     if (pe_SizeOfOptionalHeader & 0x1) return "";
547 
548     xml << " Machine=\""              << Machine                  << "\"";
549     xml << " NumberOfSections=\""     << pe_NumberOfSections     << "\"";
550     xml << " TimeDateStamp=\""        << pe_TimeDateStamp        << "\"";
551     xml << " TimeDateStampISO=\""     << pe_TimeDateStampISO     << "\"";
552     xml << " PointerToSymbolTable=\"" << pe_PointerToSymbolTable << "\"";
553     xml << " NumberOfSymbols=\""      << pe_NumberOfSymbols      << "\"";
554     xml << " SizeOfOptionalHeader=\"" << pe_SizeOfOptionalHeader << "\"";
555     xml << ">";             // close FileHeader
556 
557     decode_flags(xml,
558                  "Characteristics",
559                  pe_fileheader_characteristic_names,
560                  pe_Characteristics);
561 
562     xml << "</FileHeader>";
563 
564 
565     /******************************************
566      * BEGIN OPTIONAL HEADER STANDARD          *
567      ******************************************/
568 
569     // we assume an optional header exists
570     uint16_t pe_Magic;
571 
572     xml << "<OptionalHeaderStandard";
573 
574     // if we're going to segfault on this dereference, we don't have
575     // enough information to confirm this PE. return false
576     // Note: sizeof(*ohs) == sizeof(*ohsp) + 4
577     if (header_offset + sizeof(Pe_FileHeader)
578         + sizeof(Pe_OptionalHeaderStandard) > size)
579         return "";
580     ohs_offset = header_offset + sizeof(Pe_FileHeader);
581 
582     pe_Magic = sbuf.get16u(ohs_offset);
583     uint8_t  pe_MajorLinkerVersion;
584     uint8_t  pe_MinorLinkerVersion;
585     uint32_t pe_SizeOfCode;
586     uint32_t pe_SizeOfInitializedData;
587     uint32_t pe_SizeOfUninitializedData;
588     uint32_t pe_AddressOfEntryPoint;
589     uint32_t pe_BaseOfCode;
590     switch (pe_Magic) {
591     case IMAGE_FILE_TYPE_PE32 :
592         pe_MajorLinkerVersion      = sbuf.get8u(ohs_offset + 2);
593         pe_MinorLinkerVersion      = sbuf.get8u(ohs_offset + 3);
594         pe_SizeOfCode              = sbuf.get32u(ohs_offset + 4);
595         pe_SizeOfInitializedData   = sbuf.get32u(ohs_offset + 8);
596         pe_SizeOfUninitializedData = sbuf.get32u(ohs_offset + 12);
597         pe_AddressOfEntryPoint     = sbuf.get32u(ohs_offset + 16);
598         pe_BaseOfCode              = sbuf.get32u(ohs_offset + 20);
599         // this field isn't used to make OptionalHeaderStandard and
600         // OptionalHeaderStandardPlus consistent (this field isn't in Plus header)
601         //uint32_t pe_BaseOfData              = sbuf.get32u(ohs_offset + 24);
602 
603         // check for values resembling sanity
604         if (pe_BaseOfCode          > 0x10000000) return "";
605         if (pe_AddressOfEntryPoint > 0x10000000) return "";
606 
607         xml << " Magic=\"PE32\"";
608         xml << " MajorLinkerVersion=\""      << ((int) pe_MajorLinkerVersion) << "\"";
609         xml << " MinorLinkerVersion=\""      << ((int) pe_MinorLinkerVersion) << "\"";
610         xml << " SizeOfCode=\""              << pe_SizeOfCode                 << "\"";
611         xml << " SizeOfInitializedData=\""   << pe_SizeOfInitializedData      << "\"";
612         xml << " SizeOfUninitializedData=\"" << pe_SizeOfUninitializedData    << "\"";
613         xml << " AddressOfEntryPoint=\"0x"   << std::hex << pe_AddressOfEntryPoint << "\"";
614         xml << " BaseOfCode=\"0x"            << std::hex << pe_BaseOfCode          << "\"";
615 
616         break;
617 
618     case IMAGE_FILE_TYPE_PE32PLUS :
619         pe_MajorLinkerVersion      = sbuf.get8u(ohs_offset + 2);
620         pe_MinorLinkerVersion      = sbuf.get8u(ohs_offset + 3);
621         pe_SizeOfCode              = sbuf.get32u(ohs_offset + 4);
622         pe_SizeOfInitializedData   = sbuf.get32u(ohs_offset + 8);
623         pe_SizeOfUninitializedData = sbuf.get32u(ohs_offset + 12);
624         pe_AddressOfEntryPoint     = sbuf.get32u(ohs_offset + 16);
625         pe_BaseOfCode              = sbuf.get32u(ohs_offset + 20);
626 
627         if (pe_BaseOfCode          > 0x10000000) return "";
628         if (pe_AddressOfEntryPoint > 0x10000000) return "";
629 
630         xml << " Magic=\"PE32+\"";
631         xml << " MajorLinkerVersion=\""      << ((int) pe_MajorLinkerVersion) << "\"";
632         xml << " MinorLinkerVersion=\""      << ((int) pe_MinorLinkerVersion) << "\"";
633         xml << " SizeOfCode=\""              << pe_SizeOfCode                 << "\"";
634         xml << " SizeOfInitializedData=\""   << pe_SizeOfInitializedData      << "\"";
635         xml << " SizeOfUninitializedData=\"" << pe_SizeOfUninitializedData    << "\"";
636         xml << " AddressOfEntryPoint=\"0x"   << std::hex << pe_AddressOfEntryPoint << "\"";
637         xml << " BaseOfCode=\"0x"            << std::hex << pe_BaseOfCode          << "\"";
638 
639         break;
640 
641     default :
642         return "";
643     }
644 
645     xml << " />";
646 
647 
648     /******************************************
649      * BEGIN OPTIONAL HEADER WINDOWS           *
650      ******************************************/
651     // If the SizeOfOptionalHeader is large enough to support the
652     // optional windows header,then we will pull out windows header
653     // information.
654     // At this point, our confidence level should be very high that this
655     // is a PE, and we are only pulling information for XML
656     uint32_t pe_SectionAlignment = 0;
657     uint32_t pe_FileAlignment = 0;
658     uint16_t pe_MajorOperatingSystemVersion = 0;
659     uint16_t pe_MinorOperatingSystemVersion = 0;
660     uint16_t pe_MajorImageVersion = 0;
661     uint16_t pe_MinorImageVersion = 0;
662     uint16_t pe_MajorSubsystemVersion = 0;
663     uint16_t pe_MinorSubsystemVersion = 0;
664     uint32_t pe_Win32VersionValue = 0;
665     uint32_t pe_SizeOfImage = 0;
666     uint32_t pe_SizeOfHeaders = 0;
667     uint32_t pe_CheckSum = 0;
668     uint16_t pe_Subsystem = 0;
669     uint16_t pe_DllCharacteristics = 0;
670     uint32_t pe_LoaderFlags = 0;
671     uint32_t pe_NumberOfRvaAndSizes = 0;
672 
673     uint64_t pe_ImageBase = 0;
674     uint64_t pe_SizeOfStackReserve = 0;
675     uint64_t pe_SizeOfStackCommit = 0;
676     uint64_t pe_SizeOfHeapReserve = 0;
677     uint64_t pe_SizeOfHeapCommit = 0;
678 
679     std::string Subsystem = "";
680     bool ohw_xml = true;
681 
682     if (    (pe_Magic == IMAGE_FILE_TYPE_PE32)
683 	    && (pe_SizeOfOptionalHeader > sizeof(Pe_OptionalHeaderStandard) +
684 		sizeof(Pe_OptionalHeaderWindows))
685 	    // do we have enough buffer space for this?
686 	    && (header_offset
687 		+ sizeof(Pe_FileHeader)
688 		+ sizeof(Pe_OptionalHeaderStandard)
689 		+ sizeof(Pe_OptionalHeaderWindows) <= size)) {
690 
691         ohw_offset = ohs_offset + sizeof(Pe_OptionalHeaderStandard);
692 
693         pe_ImageBase                   = sbuf.get32u(ohw_offset);
694         pe_SectionAlignment            = sbuf.get32u(ohw_offset + 4);
695         pe_FileAlignment               = sbuf.get32u(ohw_offset + 8);
696         pe_MajorOperatingSystemVersion = sbuf.get16u(ohw_offset + 12);
697         pe_MinorOperatingSystemVersion = sbuf.get16u(ohw_offset + 14);
698         pe_MajorImageVersion           = sbuf.get16u(ohw_offset + 16);
699         pe_MinorImageVersion           = sbuf.get16u(ohw_offset + 18);
700         pe_MajorSubsystemVersion       = sbuf.get16u(ohw_offset + 20);
701         pe_MinorSubsystemVersion       = sbuf.get16u(ohw_offset + 22);
702         pe_Win32VersionValue           = sbuf.get32u(ohw_offset + 24);
703         pe_SizeOfImage                 = sbuf.get32u(ohw_offset + 28);
704         pe_SizeOfHeaders               = sbuf.get32u(ohw_offset + 32);
705         pe_CheckSum                    = sbuf.get32u(ohw_offset + 36);
706         pe_Subsystem                   = sbuf.get16u(ohw_offset + 40);
707         pe_DllCharacteristics          = sbuf.get16u(ohw_offset + 42);
708         pe_SizeOfStackReserve          = sbuf.get32u(ohw_offset + 44);
709         pe_SizeOfStackCommit           = sbuf.get32u(ohw_offset + 48);
710         pe_SizeOfHeapReserve           = sbuf.get32u(ohw_offset + 52);
711         pe_SizeOfHeapCommit            = sbuf.get32u(ohw_offset + 56);
712         pe_LoaderFlags                 = sbuf.get32u(ohw_offset + 60);
713         pe_NumberOfRvaAndSizes         = sbuf.get32u(ohw_offset + 64);
714 
715         Subsystem = match_switch_case(pe_optionalwindowsheader_subsystem, pe_Subsystem);
716     }
717     else if (    (pe_Magic == IMAGE_FILE_TYPE_PE32PLUS)
718 		 && (pe_SizeOfOptionalHeader > sizeof(Pe_OptionalHeaderStandardPlus) +
719 		     sizeof(Pe_OptionalHeaderWindowsPlus))
720 		 // do we have enough buffer space for this?
721 		 && (header_offset
722 		     + sizeof(Pe_FileHeader)
723 		     + sizeof(Pe_OptionalHeaderStandardPlus)
724 		     + sizeof(Pe_OptionalHeaderWindowsPlus) <= size)) {
725 
726         ohw_offset = ohs_offset + sizeof(Pe_OptionalHeaderStandardPlus);
727 
728         pe_ImageBase                   = sbuf.get64u(ohw_offset);
729         pe_SectionAlignment            = sbuf.get32u(ohw_offset + 8);
730         pe_FileAlignment               = sbuf.get32u(ohw_offset + 12);
731         pe_MajorOperatingSystemVersion = sbuf.get16u(ohw_offset + 16);
732         pe_MinorOperatingSystemVersion = sbuf.get16u(ohw_offset + 18);
733         pe_MajorImageVersion           = sbuf.get16u(ohw_offset + 20);
734         pe_MinorImageVersion           = sbuf.get16u(ohw_offset + 22);
735         pe_MajorSubsystemVersion       = sbuf.get16u(ohw_offset + 24);
736         pe_MinorSubsystemVersion       = sbuf.get16u(ohw_offset + 26);
737         pe_Win32VersionValue           = sbuf.get32u(ohw_offset + 30);
738         pe_SizeOfImage                 = sbuf.get32u(ohw_offset + 32);
739         pe_SizeOfHeaders               = sbuf.get32u(ohw_offset + 36);
740         pe_CheckSum                    = sbuf.get32u(ohw_offset + 40);
741         pe_Subsystem                   = sbuf.get16u(ohw_offset + 44);
742         pe_DllCharacteristics          = sbuf.get16u(ohw_offset + 46);
743         pe_SizeOfStackReserve          = sbuf.get64u(ohw_offset + 48);
744         pe_SizeOfStackCommit           = sbuf.get32u(ohw_offset + 52);
745         pe_SizeOfHeapReserve           = sbuf.get32u(ohw_offset + 56);
746         pe_SizeOfHeapCommit            = sbuf.get32u(ohw_offset + 60);
747         pe_LoaderFlags                 = sbuf.get32u(ohw_offset + 64);
748         pe_NumberOfRvaAndSizes         = sbuf.get32u(ohw_offset + 68);
749 
750         Subsystem = match_switch_case(pe_optionalwindowsheader_subsystem, pe_Subsystem);
751     }
752     else ohw_xml = false;
753 
754     if (ohw_xml) {
755         xml << "<OptionalHeaderWindows";
756         xml << " ImageBase=\"0x"                 << std::hex << pe_ImageBase       << "\"";
757         xml << " SectionAlignment=\""            << pe_SectionAlignment            << "\"";
758         xml << " FileAlignment=\""               << pe_FileAlignment               << "\"";
759         xml << " MajorOperatingSystemVersion=\"" << pe_MajorOperatingSystemVersion << "\"";
760         xml << " MinorOperatingSystemVersion=\"" << pe_MinorOperatingSystemVersion << "\"";
761         xml << " MajorImageVersion=\""           << pe_MajorImageVersion           << "\"";
762         xml << " MinorImageVersion=\""           << pe_MinorImageVersion           << "\"";
763         xml << " MajorSubsystemVersion=\""       << pe_MajorSubsystemVersion       << "\"";
764         xml << " MinorSubsystemVersion=\""       << pe_MinorSubsystemVersion       << "\"";
765         xml << " Win32VersionValue=\""           << pe_Win32VersionValue           << "\"";
766         xml << " SizeOfImage=\""                 << pe_SizeOfImage                 << "\"";
767         xml << " SizeOfHeaders=\""               << pe_SizeOfHeaders               << "\"";
768         xml << " CheckSum=\"0x"                  << std::hex << pe_CheckSum        << "\"";
769         xml << " SubSystem=\""                   << Subsystem                      << "\"";
770         xml << " SizeOfStackReserve=\""          << pe_SizeOfStackReserve          << "\"";
771         xml << " SizeOfStackCommit=\""           << pe_SizeOfStackCommit           << "\"";
772         xml << " SizeOfHeapReserve=\""           << pe_SizeOfHeapReserve           << "\"";
773         xml << " SizeOfHeapCommit=\""            << pe_SizeOfHeapCommit            << "\"";
774         xml << " LoaderFlags=\""                 << pe_LoaderFlags                 << "\"";
775         xml << " NumberOfRvaAndSizes=\""         << pe_NumberOfRvaAndSizes         << "\">";
776 
777         /* Note: This field name is DllCharacteristics in the Microsoft
778          * spec, not Characteristics.  We have chosen to preserve
779          * Microsoft's inconsistency in the XML.
780          */
781         decode_flags(xml,
782                      "DllCharacteristics",
783                      pe_optionalwindowsheader_dllcharacteristic,
784                      pe_DllCharacteristics);
785         xml << "</OptionalHeaderWindows>";
786     }
787 
788 
789     // Before we loop through sections, we're going to locate the
790     // virtual address of the idata directory. If we load a valid
791     // section that holds the idata, we'll save the address of the idata
792     // so we can load DLL names later
793 
794     // find the .idata DataDirectory
795     const Pe_DataDirectory  * idd  = NULL; // idata Data Directory
796     if ((pe_Magic == IMAGE_FILE_TYPE_PE32) && (ohw_offset)) {
797 	idd = sbuf.get_struct_ptr<Pe_DataDirectory>(header_offset
798 						    + sizeof(Pe_FileHeader)
799 						    + sizeof(Pe_OptionalHeaderStandard)
800 						    + sizeof(Pe_OptionalHeaderWindows)
801 						    + sizeof(Pe_DataDirectory));
802     }
803     if ((pe_Magic == IMAGE_FILE_TYPE_PE32PLUS) && (ohw_offset)) {
804 	idd = sbuf.get_struct_ptr<Pe_DataDirectory>(header_offset
805 						    + sizeof(Pe_FileHeader)
806 						    + sizeof(Pe_OptionalHeaderStandardPlus)
807 						    + sizeof(Pe_OptionalHeaderWindowsPlus)
808 						    + sizeof(Pe_DataDirectory));
809     }
810 
811     // Section Header for Imports (shi):
812     // if this not NULL once we're done processing sections,
813     // it points to the Section Header of the section which
814     // holds the import table data
815     const Pe_SectionHeader * shi  = NULL;
816     xml << "<Sections>";
817     for (section_i = 0; section_i < pe_NumberOfSections; section_i++) {
818 
819 	const Pe_SectionHeader * sh =
820 	    sbuf.get_struct_ptr<Pe_SectionHeader>(header_offset
821 						  + sizeof(Pe_FileHeader)
822 						  + pe_SizeOfOptionalHeader
823 						  + sizeof(Pe_SectionHeader) * section_i);
824 	if(sh==0) break; // no more!
825 
826         // the following flags are reserved for future use and should
827         // not be set. If we get something invalid, we've probably gone
828         // into garbage, so just give up on the sections.
829         if (sh->Characteristics & PE_SECTION_RESERVED_FLAGS) break;
830 
831         if (sh->VirtualSize & 0x80000000) break;
832 
833         // this allows for sections up to 256mb in size, more than
834         // generous
835         if (sh->SizeOfRawData & 0xe0000000) break;
836 
837 
838         // section names do not have to be null-terminated,
839         // so termiante it.
840         char section_name[9];
841         strncpy(section_name, sh->Name, sizeof(section_name));
842         section_name[8] = '\0';
843 
844 	if(!valid_section_name(section_name)){
845 	    shi = 0;			// don't get the shi
846 	    goto end_of_sections;
847 	}
848 
849         xml << "<SectionHeader";
850         xml << " Name=\""                 << section_name << "\"";
851         xml << " VirtualSize=\""          << sh->VirtualSize << "\"";
852         xml << " VirtualAddress=\""       << sh->VirtualAddress << "\"";
853         xml << " SizeOfRawData=\""        << sh->SizeOfRawData << "\"";
854         xml << " PointerToRawData=\""     << sh->PointerToRawData << "\"";
855         xml << " PointerToRelocations=\"" << sh->PointerToRelocations << "\"";
856         xml << " PointerToLinenumbers=\"" << sh->PointerToLinenumbers << "\"";
857         xml << " >";
858 
859         decode_flags(xml,"Characteristics",pe_section_characteristic_names,sh->Characteristics);
860 
861         xml << "</SectionHeader>";
862 
863         // check if import data resides in this section
864         if (idd) {
865             if (    (idd->VirtualAddress >= sh->VirtualAddress)
866 		    && (idd->VirtualAddress < sh->VirtualAddress
867 			+ sh->SizeOfRawData)) {
868                 shi = sh;
869             }
870         }
871     }
872  end_of_sections:;
873     xml << "</Sections>";
874 
875     // get DLL names
876     if (shi) {
877         // find offset into PE where the Import Data Table resides
878 	xml << "<dlls>";
879         for (int idt_i = 0;  ; idt_i++) {
880 	    const Pe_ImportDirectoryTable * idt  = sbuf.get_struct_ptr<Pe_ImportDirectoryTable>(shi->PointerToRawData + (  idd->VirtualAddress - shi->VirtualAddress) + sizeof(Pe_ImportDirectoryTable)*idt_i);
881 	    if(idt==0) break;
882 
883             // The Import Data Table is terminated by a null entry
884             if (idt->ImportLookupTableRVA == 0 && idt->TimeDateStamp==0 && idt->ForwarderChain==0 && idt->NameRVA==0 && idt->ImportAddressTableRVA==0){
885 		break;
886 	    }
887 
888             // We are given the RVA of a string which contains the
889             // name of the DLL. We're going to loop through sections,
890             // attempt to find a section which is loaded into this
891             // RVA, and then extract the name from it
892             for (int si = 0; si < pe_NumberOfSections; si++) {
893                 // is this section header out-of-bounds
894                 if (header_offset + sizeof(Pe_FileHeader)
895                     + pe_SizeOfOptionalHeader
896                     + sizeof(Pe_SectionHeader) * (si + 1) > size)
897                     break;
898 
899                 const Pe_SectionHeader *sht =
900 		    sbuf.get_struct_ptr<Pe_SectionHeader>(header_offset
901 							  + sizeof(Pe_FileHeader)
902 							  + pe_SizeOfOptionalHeader
903 							  + sizeof(Pe_SectionHeader) * si);
904 
905                 // find target section
906                 if (    (sht->VirtualAddress < idt->NameRVA)
907 			&& (sht->VirtualAddress + sht->SizeOfRawData > idt->NameRVA)) {
908 
909                     // can we actually get the string out of this section
910                     // max allowable string size is 32 chars
911 		    if (sht->PointerToRawData
912 			+ (idt->NameRVA - sht->VirtualAddress)
913 			+ 32 >= size)
914 			break;
915 
916 		    // place dll name in a buffer string and add the xml
917 		    // Note --- currently this copies then verifies; it would be better
918 		    // to verify while copying...
919 
920 		    // find length of dllname, <= 32 characters
921 		    // p. 90 of the pecoff specification (v8) assures that
922 		    // names contain ASCII strings and are null-terminated.
923 		    int dllname_length = 32;
924 		    for (int dlli = 0; dlli < 32; dlli++) {
925 			if (sbuf[sht->PointerToRawData + (idt->NameRVA - sht->VirtualAddress) + dlli] == 0) {
926 			    dllname_length = dlli;
927 			    break;
928 			}
929 		    }
930 		    std::string dllname = sbuf.substr(sht->PointerToRawData + (idt->NameRVA - sht->VirtualAddress), dllname_length);
931 
932 		    // according to spec, these names are ASCII. perform
933 		    // a sanity check, as this data is deep in the file
934 		    // and may not be part of a contiguous PE
935 		    if(!valid_dll_name(dllname)) goto end_of_dlls;
936 		    xml << "<dll>" << dllname << "</dll>";
937                 }
938             }
939         }
940     end_of_dlls:;
941 	xml << "</dlls>";
942     }
943     xml << "</PE>";
944     return xml.str();
945 }
946 
947 // the data that ends the furthest out is the carve size
get_carve_size(const sbuf_t & sbuf)948 static size_t get_carve_size (const sbuf_t& sbuf)
949 {
950     // heaser offset
951     const uint32_t header_offset = sbuf.get32u(PE_FILE_OFFSET) + PE_SIGNATURE_SIZE;
952 
953     // OptionalHeaderStandard offset
954     const size_t ohs_offset = header_offset + sizeof(Pe_FileHeader);
955 
956     // image file type
957     const uint16_t pe_Magic = sbuf.get16u(ohs_offset);
958 
959     // check end of signature as potential carve size
960     // point to the certificate table containing the digital signature,
961     // IMAGE_DIRECTORY_ENTRY_SECURITY, index 4
962     const Pe_DataDirectory* ctd;
963     if (pe_Magic == IMAGE_FILE_TYPE_PE32) {
964 	ctd = sbuf.get_struct_ptr<Pe_DataDirectory>(header_offset
965 						    + sizeof(Pe_FileHeader)
966 						    + sizeof(Pe_OptionalHeaderStandard)
967 						    + sizeof(Pe_OptionalHeaderWindows)
968 						    + sizeof(Pe_DataDirectory)*4);
969     } else if (pe_Magic == IMAGE_FILE_TYPE_PE32PLUS) {
970 	ctd = sbuf.get_struct_ptr<Pe_DataDirectory>(header_offset
971 						    + sizeof(Pe_FileHeader)
972 						    + sizeof(Pe_OptionalHeaderStandardPlus)
973 						    + sizeof(Pe_OptionalHeaderWindowsPlus)
974 						    + sizeof(Pe_DataDirectory)*4);
975     } else {
976         // corrupt magic number so do not carve
977         return 0;
978     }
979 
980     size_t carve_size = 0;
981     if (ctd != NULL && ctd->VirtualAddress < 1024*1024*1024 && ctd->Size < 1024*1024) {
982         // consider end of signature, which can be 0, as potential carve size
983         carve_size = ctd->VirtualAddress + ctd->Size;
984     }
985 
986     // consider each section size as potential carve size
987     const uint16_t pe_NumberOfSections = sbuf.get16u(header_offset + 2);
988     const uint16_t pe_SizeOfOptionalHeader = sbuf.get16u(header_offset + 16);
989     for (int section_i = 0; section_i < pe_NumberOfSections; section_i++) {
990 
991 	const Pe_SectionHeader * sh =
992 	    sbuf.get_struct_ptr<Pe_SectionHeader>(header_offset
993 						  + sizeof(Pe_FileHeader)
994 						  + pe_SizeOfOptionalHeader
995 						  + sizeof(Pe_SectionHeader) * section_i);
996 	if(sh==0) break; // end of sbuf
997 
998         if (sh->PointerToRawData + sh->SizeOfRawData > carve_size) {
999             carve_size = sh->PointerToRawData + sh->SizeOfRawData;
1000         }
1001     }
1002 
1003     // the carve size must not be totally unreasonable
1004     if (carve_size > 1024*1024*1024) { // 1GiB
1005         return 0;
1006     }
1007 
1008     return carve_size;
1009 }
1010 
1011 extern "C"
scan_winpe(scanner_params & sp)1012 void scan_winpe (scanner_params &sp)
1013 {
1014     sp.check_version();
1015     std::string xml;
1016 
1017     if (sp.phase == scanner_params::PHASE_INIT){
1018         sp.info->set_name("winpe" );
1019         sp.info->description     = "Scan for Windows PE headers";
1020         sp.info->scanner_version = "1.1.0";
1021         struct feature_recorder_def::flags_t carve_flag;
1022         carve_flag.carve = true;
1023         sp.info->feature_defs.push_back( feature_recorder_def("winpe"));
1024         sp.info->feature_defs.push_back( feature_recorder_def("winpe_carved", carve_flag));
1025         return;
1026     }
1027 
1028     if(sp.phase == scanner_params::PHASE_SCAN){    // phase 1
1029 	feature_recorder &f = sp.named_feature_recorder("winpe");
1030         const sbuf_t &sbuf = *(sp.sbuf);
1031 
1032 	/*
1033 	 * Portable Executables start with a MS-DOS stub. The actual PE
1034 	 * begins at an offset of 0x3c (PE_FILE_OFFSET) bytes. The signature
1035 	 * is "PE\0\0"
1036 	 */
1037 	// we are going to make sure we have at least enough room for a
1038 	// complete MS-Dos Stub, Signature and PE header, and an optional
1039 	// header and/or at least one section
1040 
1041 
1042 	/* Return if the buffer is impossibly small to contain a PE header */
1043 	if ((sbuf.bufsize < PE_SIGNATURE_SIZE + sizeof(Pe_FileHeader) + 40) ||
1044 	    (sbuf.bufsize < PE_FILE_OFFSET+4)){
1045 	    return;
1046 	}
1047 
1048 	/* Loop through the sbuf, go to the offset, and see if there is a PE signature */
1049 	for (size_t pos = 0; pos < sbuf.pagesize; pos++) {
1050 	    size_t bytes_left = sbuf.bufsize - pos;
1051 	    if(bytes_left < PE_FILE_OFFSET+4) break; // ran out of space
1052 
1053 	    // offset to the header is at 0x3c
1054 	    const uint32_t pe_header_offset = sbuf.get32u(pos+PE_FILE_OFFSET);
1055 	    if (pe_header_offset + 4 > bytes_left) continue; // points to region outside the sbuf
1056 
1057 	    // check for magic number. If found, analyze
1058 	    if (    (sbuf[pos+pe_header_offset    ] == PE_SIGNATURE[0])
1059 		    && (sbuf[pos+pe_header_offset + 1] == PE_SIGNATURE[1])
1060 		    && (sbuf[pos+pe_header_offset + 2] == PE_SIGNATURE[2])
1061 		    && (sbuf[pos+pe_header_offset + 3] == PE_SIGNATURE[3])) {
1062 
1063 		sbuf_t data = sbuf.slice(pos);
1064 
1065 		xml = scan_winpe_verify(data);
1066 		if (xml != "") {
1067 		    // If we have 4096 bytes, generate hash of first 4K
1068                     sbuf_t first4k = data.slice(0, 4096);
1069 		    f.write(data.pos0, first4k.hash(), xml);
1070 
1071                     size_t carve_size = get_carve_size(data);
1072                     feature_recorder &f_carved = sp.named_feature_recorder("winpe_carved");
1073                     f_carved.carve(data.slice(0, carve_size), ".winpe");
1074 		}
1075 	    }
1076 	}
1077     }
1078 }
1079