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 §ionName,
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 §ionName)
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