]> git.saurik.com Git - apple/ld64.git/blob - unit-tests/test-cases/efi-basic/efi-pecoff-util
ld64-409.12.tar.gz
[apple/ld64.git] / unit-tests / test-cases / efi-basic / efi-pecoff-util
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2013 - 2016 Apple Inc. All rights reserved
4 #
5 # Dump out a PE/COFF, PE/COFF+, or TE file using the EfiPeCoff class
6 #
7 # Read from memory in lldb
8 # T=pecoff.EfiPeCoff(lldb.target, 0x86c7d000)
9 #
10 # Read from a Python file object
11 # T=pecoff.EfiPeCoff(file)
12 #
13 # Read from a Python string
14 # T=pecoff.EfiPeCoff(file.read())
15 #
16
17 import sys
18 import struct
19 import collections
20 import optparse
21 import commands
22 import os
23 import platform
24
25 #----------------------------------------------------------------------
26 # Code that auto imports LLDB
27 #----------------------------------------------------------------------
28 try:
29 # Just try for LLDB in case PYTHONPATH is already correctly setup
30 import lldb
31 except ImportError:
32 lldb_python_dirs = list()
33 # lldb is not in the PYTHONPATH, try some defaults for the current platform
34 platform_system = platform.system()
35 if platform_system == 'Darwin':
36 # On Darwin, try the currently selected Xcode directory
37 xcode_dir = commands.getoutput("xcode-select --print-path")
38 if xcode_dir:
39 lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
40 lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
41 lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
42 success = False
43 for lldb_python_dir in lldb_python_dirs:
44 if os.path.exists(lldb_python_dir):
45 if not (sys.path.__contains__(lldb_python_dir)):
46 sys.path.append(lldb_python_dir)
47 try:
48 import lldb
49 except ImportError:
50 pass
51 else:
52 success = True
53 break
54 if not success:
55 print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
56 sys.exit(1)
57
58 class ReadOnlyFile:
59 '''Abstract reading data from an object:
60 Duck type an lldb.SBTarget, string (output of file.read()), or Python File object.
61 '''
62 def __init__(self, readAbstraction, address = 0):
63 # Python file object
64 self.file = None
65 # offset for FAT binaries.
66 self.offset = None
67
68 # lldb SBTarget
69 self.address = None
70 self.startingAddress = None
71 self.SBTarget = None
72 self.SBError = None
73
74 # Python string (file.read())
75 self.data = None
76 self.dataIndex = 0
77
78 if isinstance(readAbstraction, lldb.SBTarget):
79 # duck type lldb memory reads
80 self.address = address
81 self.startingAddress = address
82 self.SBTarget = readAbstraction
83 self.SBError = lldb.SBError()
84 elif isinstance(readAbstraction, file):
85 # duck type to a Python file
86 self.file = readAbstraction
87 self.offset = address
88 elif isinstance(readAbstraction, str):
89 # string, like the result of reading the file in via Python
90 self.data = readAbstraction
91 self.dataIndex = 0
92 else:
93 raise SyntaxError('Unsupported type for readAbstraction')
94
95 def Read (self, size, offset=None):
96 if offset is not None:
97 self.Seek (offset)
98
99 if self.file:
100 return self.file.read(size)
101
102 if self.address:
103 data = self.SBTarget.process.ReadMemory (self.address, size, self.SBError)
104 self.address += size
105 return bytearray(data)
106
107 if self.data:
108 data = self.data[self.dataIndex:self.dataIndex+size]
109 self.dataIndex += size
110 return data
111
112 def ReadCString (self, offset=None, maxSize=512):
113 if offset:
114 self.Seek (offset)
115
116 if self.file:
117 data = self.file.read(maxSize)
118 str = data.split('\x00')[0]
119 # seek to end of string
120 self.file.seek (-(maxSize - len(str)), os.SEEK_CUR)
121 return data
122
123 if self.address:
124 data = self.SBTarget.process.ReadCStringFromMemory (self.address, maxSize, self.SBError)
125 self.address += len(data)
126 return data
127
128 if self.data:
129 data = self.data[self.dataIndex:self.dataIndex+maxSize]
130 str = data.split('\x00')[0]
131 self.dataIndex += len(str)
132 return str
133
134
135 def Seek (self, offset, whence = os.SEEK_SET):
136 if self.file:
137 return self.file.seek(offset, whence)
138
139 if self.address:
140 if whence == os.SEEK_SET:
141 self.address = self.startingAddress + offset
142 elif whence == os.SEEK_CUR:
143 self.address = self.address + offset
144 elif whence == os.SEEK_END:
145 raise SyntaxError('whence does not support SEEK_END due to memory not having an end')
146 else:
147 raise SyntaxError('illegal whence value')
148
149 if self.data:
150 if whence == os.SEEK_SET:
151 self.dataIndex = offset
152 elif whence == os.SEEK_CUR:
153 self.dataIndex = self.dataIndex + offset
154 elif whence == os.SEEK_END:
155 raise SyntaxError('whence does not support SEEK_END due to memory not having an end')
156 else:
157 raise SyntaxError('illegal whence value')
158
159 def Tell (self):
160 if self.file:
161 return self.file.tell()
162
163 if self.address:
164 return self.address
165
166 if self.data:
167 return self.dataIndex
168
169
170 def __del__(self):
171 if self.file:
172 self.file.close()
173
174 class EfiPeCoff:
175 ''' class to abstract PE/COFF walking'''
176
177 # PE/COFF class definitions
178
179 #
180 # typedef struct {
181 # UINT32 VirtualAddress;
182 # UINT32 Size;
183 # } EFI_IMAGE_DATA_DIRECTORY;
184 #
185 # typedef struct {
186 # UINT16 Signature; ///< The signature for TE format = "VZ".
187 # UINT16 Machine; ///< From the original file header.
188 # UINT8 NumberOfSections; ///< From the original file header.
189 # UINT8 Subsystem; ///< From original optional header.
190 # UINT16 StrippedSize; ///< Number of bytes we removed from the header.
191 # UINT32 AddressOfEntryPoint; ///< Offset to entry point -- from original optional header.
192 # UINT32 BaseOfCode; ///< From original image -- required for ITP debug.
193 # UINT64 ImageBase; ///< From original file header.
194 # EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]; ///< Only base relocation and debug directory.
195 # } EFI_TE_IMAGE_HEADER;
196 #
197
198 EFI_TE_IMAGE_HEADER_fmt = '<HHBBHLLQLLLL'
199 TeHdrLength = struct.calcsize(EFI_TE_IMAGE_HEADER_fmt)
200 EFI_TE_IMAGE_HEADER_tuple = 'Signature Machine NumberOfSections Subsystem StrippedSize AddressOfEntryPoint BaseOfCode ImageBase DataDirVirt_Reloc DataDirSize_Reloc DataDirVirt_Debug DataDirSize_Debug'
201 EFI_TE_IMAGE_HEADER = collections.namedtuple ('EFI_TE_IMAGE_HEADER', EFI_TE_IMAGE_HEADER_tuple)
202
203 EFI_IMAGE_NT_SIGNATURE = 0x00004550
204 #
205 # ///
206 # /// PE images can start with an optional DOS header, so if an image is run
207 # /// under DOS it can print an error message.
208 # ///
209 # typedef struct {
210 # UINT16 e_magic; ///< Magic number.
211 # UINT16 e_cblp; ///< Bytes on last page of file.
212 # UINT16 e_cp; ///< Pages in file.
213 # UINT16 e_crlc; ///< Relocations.
214 # UINT16 e_cparhdr; ///< Size of header in paragraphs.
215 # UINT16 e_minalloc; ///< Minimum extra paragraphs needed.
216 # UINT16 e_maxalloc; ///< Maximum extra paragraphs needed.
217 # UINT16 e_ss; ///< Initial (relative) SS value.
218 # UINT16 e_sp; ///< Initial SP value.
219 # UINT16 e_csum; ///< Checksum.
220 # UINT16 e_ip; ///< Initial IP value.
221 # UINT16 e_cs; ///< Initial (relative) CS value.
222 # UINT16 e_lfarlc; ///< File address of relocation table.
223 # UINT16 e_ovno; ///< Overlay number.
224 # UINT16 e_res[4]; ///< Reserved words.
225 # UINT16 e_oemid; ///< OEM identifier (for e_oeminfo).
226 # UINT16 e_oeminfo; ///< OEM information; e_oemid specific.
227 # UINT16 e_res2[10]; ///< Reserved words.
228 # UINT32 e_lfanew; ///< File address of new exe header.
229 # } EFI_IMAGE_DOS_HEADER;
230 #
231
232 # cheat as 58s is really e_cblp -> e_res2[10]
233 EFI_IMAGE_DOS_HEADER_fmt = '<H58sI'
234 DosHdrLength = struct.calcsize(EFI_IMAGE_DOS_HEADER_fmt)
235 EFI_IMAGE_DOS_HEADER_tuple = 'e_magic e_ignore e_lfanew'
236 EFI_IMAGE_DOS_HEADER = collections.namedtuple ('EFI_IMAGE_DOS_HEADER', EFI_IMAGE_DOS_HEADER_tuple)
237
238 #define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
239 #
240 # ///
241 # /// @attention
242 # /// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and
243 # /// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
244 # /// after NT additional fields.
245 # ///
246 EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
247 #
248 # UINT32 Signature;
249 # typedef struct {
250 # UINT16 Machine;
251 # UINT16 NumberOfSections;
252 # UINT32 TimeDateStamp;
253 # UINT32 PointerToSymbolTable;
254 # UINT32 NumberOfSymbols;
255 # UINT16 SizeOfOptionalHeader;
256 # UINT16 Characteristics;
257 # } EFI_IMAGE_FILE_HEADER;
258 # ///
259 # /// Optional Header Standard Fields for PE32.
260 # ///
261 # typedef struct {
262 # ///
263 # /// Standard fields.
264 # ///
265 # UINT16 Magic;
266 # UINT8 MajorLinkerVersion;
267 # UINT8 MinorLinkerVersion;
268 # UINT32 SizeOfCode;
269 # UINT32 SizeOfInitializedData;
270 # UINT32 SizeOfUninitializedData;
271 # UINT32 AddressOfEntryPoint;
272 # UINT32 BaseOfCode;
273 # UINT32 BaseOfData; ///< PE32 contains this additional field, which is absent in PE32+.
274 # ///
275 # /// Optional Header Windows-Specific Fields.
276 # ///
277 # UINT32 ImageBase;
278 # UINT32 SectionAlignment;
279 # UINT32 FileAlignment;
280 # UINT16 MajorOperatingSystemVersion;
281 # UINT16 MinorOperatingSystemVersion;
282 # UINT16 MajorImageVersion;
283 # UINT16 MinorImageVersion;
284 # UINT16 MajorSubsystemVersion;
285 # UINT16 MinorSubsystemVersion;
286 # UINT32 Win32VersionValue;
287 # UINT32 SizeOfImage;
288 # UINT32 SizeOfHeaders;
289 # UINT32 Checksum;
290 # UINT16 Subsystem;
291 # UINT16 DllCharacteristics;
292 # UINT32 SizeOfStackReserve;
293 # UINT32 SizeOfStackCommit;
294 # UINT32 SizeOfHeapReserve;
295 # UINT32 SizeOfHeapCommit;
296 # UINT32 LoaderFlags;
297 # UINT32 NumberOfRvaAndSizes;
298 # EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
299 # } EFI_IMAGE_OPTIONAL_HEADER32;
300 #
301
302 EFI_IMAGE_DATA_DIRECTORY_tuple = '''
303 DataDirVirt_Export DataDirSize_Export
304 DataDirVirt_Import DataDirSize_Import
305 DataDirVirt_Resource DataDirSize_Resource
306 DataDirVirt_Exception DataDirSize_Exception
307 DataDirVirt_Security DataDirSize_Security
308 DataDirVirt_Reloc DataDirSize_Reloc
309 DataDirVirt_Debug DataDirSize_Debug
310 DataDir7Virt DataDir7Size
311 DataDir8Virt DataDir8Size
312 DataDir9Virt DataDir9Size
313 DataDir10Virt DataDir10Size
314 DataDir11Virt DataDir11Size
315 DataDir12Virt DataDir12Size
316 DataDir13Virt DataDir13Size
317 DataDir14Virt DataDir14Size
318 DataDir15Virt DataDir15Size
319 '''
320
321
322 EFI_IMAGE_OPTIONAL_HEADER32_fmt = '<IHHIIIHHHBBIIIIIIIIIHHHHHHIIIIHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'
323 OptionalHeader32Length = struct.calcsize(EFI_IMAGE_OPTIONAL_HEADER32_fmt)
324 EFI_IMAGE_OPTIONAL_HEADER32_tuple = '''
325 Signature
326 Machine
327 NumberOfSections
328 TimeDateStamp
329 PointerToSymbolTable
330 NumberOfSymbols
331 SizeOfOptionalHeader
332 Characteristics
333 Magic
334 MajorLinkerVersion
335 MinorLinkerVersion
336 SizeOfCode
337 SizeOfInitializedData
338 SizeOfUninitializedData
339 AddressOfEntryPoint
340 BaseOfCode
341 BaseOfData
342 ImageBase
343 SectionAlignment
344 FileAlignment
345 MajorOperatingSystemVersion
346 MinorOperatingSystemVersion
347 MajorImageVersion
348 MinorImageVersion
349 MajorSubsystemVersion
350 MinorSubsystemVersion
351 Win32VersionValue
352 SizeOfImage
353 SizeOfHeaders
354 Checksum
355 Subsystem
356 DllCharacteristics
357 SizeOfStackReserve
358 SizeOfStackCommit
359 SizeOfHeapReserve
360 SizeOfHeapCommit
361 LoaderFlags
362 NumberOfRvaAndSizes
363 ''' + EFI_IMAGE_DATA_DIRECTORY_tuple
364 EFI_IMAGE_OPTIONAL_HEADER32 = collections.namedtuple ('EFI_IMAGE_OPTIONAL_HEADER32', EFI_IMAGE_OPTIONAL_HEADER32_tuple)
365
366
367 #
368 # ///
369 # /// @attention
370 # /// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and
371 # /// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
372 # /// after NT additional fields.
373 # ///
374 EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
375 #
376 # ///
377 # /// Optional Header Standard Fields for PE32+.
378 # ///
379
380
381 # UINT32 Signature;
382 # typedef struct {
383 # UINT16 Machine;
384 # UINT16 NumberOfSections;
385 # UINT32 TimeDateStamp;
386 # UINT32 PointerToSymbolTable;
387 # UINT32 NumberOfSymbols;
388 # UINT16 SizeOfOptionalHeader;
389 # UINT16 Characteristics;
390 # } EFI_IMAGE_FILE_HEADER;
391 # ///
392 # /// COFF File Header (Object and Image).
393 # ///
394 # typedef struct {
395 # ///
396 # /// Standard fields.
397 # ///
398 # UINT16 Magic;
399 # UINT8 MajorLinkerVersion;
400 # UINT8 MinorLinkerVersion;
401 # UINT32 SizeOfCode;
402 # UINT32 SizeOfInitializedData;
403 # UINT32 SizeOfUninitializedData;
404 # UINT32 AddressOfEntryPoint;
405 # UINT32 BaseOfCode;
406 # ///
407 # /// Optional Header Windows-Specific Fields.
408 # ///
409 # UINT64 ImageBase;
410 # UINT32 SectionAlignment;
411 # UINT32 FileAlignment;
412 # UINT16 MajorOperatingSystemVersion;
413 # UINT16 MinorOperatingSystemVersion;
414 # UINT16 MajorImageVersion;
415 # UINT16 MinorImageVersion;
416 # UINT16 MajorSubsystemVersion;
417 # UINT16 MinorSubsystemVersion;
418 # UINT32 Win32VersionValue;
419 # UINT32 SizeOfImage;
420 # UINT32 SizeOfHeaders;
421 # UINT32 Checksum;
422 # UINT16 Subsystem;
423 # UINT16 DllCharacteristics;
424 # UINT64 SizeOfStackReserve;
425 # UINT64 SizeOfStackCommit;
426 # UINT64 SizeOfHeapReserve;
427 # UINT64 SizeOfHeapCommit;
428 # UINT32 LoaderFlags;
429 # UINT32 NumberOfRvaAndSizes;
430 # EFI_IMAGE_DATA_DIRECTORY DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
431 # } EFI_IMAGE_OPTIONAL_HEADER64;
432 #
433
434 EFI_IMAGE_OPTIONAL_HEADER64_fmt = '<IHHIIIHHHBBIIIIIQIIHHHHHHIIIIHHQQQQIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'
435 OptionalHeader64Length = struct.calcsize(EFI_IMAGE_OPTIONAL_HEADER64_fmt)
436 EFI_IMAGE_OPTIONAL_HEADER64_tuple = '''
437 Signature
438 Machine
439 NumberOfSections
440 TimeDateStamp
441 PointerToSymbolTable
442 NumberOfSymbols
443 SizeOfOptionalHeader
444 Characteristics
445 Magic
446 MajorLinkerVersion
447 MinorLinkerVersion
448 SizeOfCode
449 SizeOfInitializedData
450 SizeOfUninitializedData
451 AddressOfEntryPoint
452 BaseOfCode
453 ImageBase
454 SectionAlignment
455 FileAlignment
456 MajorOperatingSystemVersion
457 MinorOperatingSystemVersion
458 MajorImageVersion
459 MinorImageVersion
460 MajorSubsystemVersion
461 MinorSubsystemVersion
462 Win32VersionValue
463 SizeOfImage
464 SizeOfHeaders
465 Checksum
466 Subsystem
467 DllCharacteristics
468 SizeOfStackReserve
469 SizeOfStackCommit
470 SizeOfHeapReserve
471 SizeOfHeapCommit
472 LoaderFlags
473 NumberOfRvaAndSizes
474 ''' + EFI_IMAGE_DATA_DIRECTORY_tuple
475 EFI_IMAGE_OPTIONAL_HEADER64 = collections.namedtuple ('EFI_IMAGE_OPTIONAL_HEADER64', EFI_IMAGE_OPTIONAL_HEADER64_tuple)
476
477 #
478 # #define EFI_IMAGE_SIZEOF_SHORT_NAME 8
479 #
480 # ///
481 # /// Section Table. This table immediately follows the optional header.
482 # ///
483 # typedef struct {
484 # UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
485 # union {
486 # UINT32 PhysicalAddress;
487 # UINT32 VirtualSize;
488 # } Misc;
489 # UINT32 VirtualAddress;
490 # UINT32 SizeOfRawData;
491 # UINT32 PointerToRawData;
492 # UINT32 PointerToRelocations;
493 # UINT32 PointerToLinenumbers;
494 # UINT16 NumberOfRelocations;
495 # UINT16 NumberOfLinenumbers;
496 # UINT32 Characteristics;
497 # } EFI_IMAGE_SECTION_HEADER;
498 #
499
500 EFI_IMAGE_SECTION_HEADER_fmt = '<QIIIIIIHHI'
501 PeCoffSectionLength = struct.calcsize(EFI_IMAGE_SECTION_HEADER_fmt)
502 EFI_IMAGE_SECTION_HEADER_tuple = 'Name VirtualSize VirtualAddress SizeOfRawData PointerToRawData PointerToRelocations PointerToLinenumbers NumberOfRelocations NumberOfLinenumbers Characteristics'
503 EFI_IMAGE_SECTION_HEADER = collections.namedtuple ('EFI_IMAGE_SECTION_HEADER', EFI_IMAGE_SECTION_HEADER_tuple)
504
505 #
506 # ///
507 # /// Debug Directory Format.
508 # ///
509 # typedef struct {
510 # UINT32 Characteristics;
511 # UINT32 TimeDateStamp;
512 # UINT16 MajorVersion;
513 # UINT16 MinorVersion;
514 # UINT32 Type;
515 # UINT32 SizeOfData;
516 # UINT32 RVA; ///< The address of the debug data when loaded, relative to the image base.
517 # UINT32 FileOffset; ///< The file pointer to the debug data.
518 # } EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
519 #
520
521 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_fmt = '<IIHHIIII'
522 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_tuple = 'Characteristics TimeDateStamp MajorVersion MinorVersion Type SizeOfData RVA FileOffset'
523 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY = collections.namedtuple ('EFI_IMAGE_DEBUG_DIRECTORY_ENTRY', EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_tuple)
524
525 ##define CODEVIEW_SIGNATURE_MTOC SIGNATURE_32('M', 'T', 'O', 'C')
526 #typedef struct {
527 # UINT32 Signature; ///< "MTOC".
528 # GUID MachOUuid;
529 # //
530 # // Filename of .DLL (Mach-O with debug info) goes here
531 # //
532 #} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
533
534 #typedef struct {
535 # UINT32 Data1;
536 # UINT16 Data2;
537 # UINT16 Data3;
538 # UINT8 Data4[8];
539 #} GUID;
540
541 EFI_GUID_fmt = '<IHHBBBBBBBB'
542
543 # typedef struct {
544 # UINT32 VirtualAddress;
545 # UINT32 SizeOfBlock;
546 # } EFI_IMAGE_BASE_RELOCATION;
547
548 EFI_IMAGE_BASE_RELOCATION_fmt = '<II'
549 BaseRelocationLength = struct.calcsize(EFI_IMAGE_BASE_RELOCATION_fmt)
550
551 # ///
552 # /// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
553 # ///
554 # typedef struct {
555 # ///
556 # /// The length of the entire certificate,
557 # /// including the length of the header, in bytes.
558 # ///
559 # UINT32 dwLength;
560 # ///
561 # /// The revision level of the WIN_CERTIFICATE
562 # /// structure. The current revision level is 0x0200.
563 # ///
564 # UINT16 wRevision;
565 # ///
566 # /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI
567 # /// certificate types. The UEFI specification reserves the range of
568 # /// certificate type values from 0x0EF0 to 0x0EFF.
569 # ///
570 # UINT16 wCertificateType;
571 # ///
572 # /// The following is the actual certificate. The format of
573 # /// the certificate depends on wCertificateType.
574 # ///
575 # /// UINT8 bCertificate[ANYSIZE_ARRAY];
576 # ///
577 # } WIN_CERTIFICATE;
578
579 WIN_CERTIFICATE_fmt = "<IHH"
580 WinCertLength = struct.calcsize(WIN_CERTIFICATE_fmt)
581
582 def __init__(self, readAbstraction, address = 0):
583 self.f = ReadOnlyFile(readAbstraction, address)
584 # ( ImageType: 'TE'/'PE32'/'PE32+'
585 # OptionalHeaderCollection: Optional Header and Data Directory
586 # HeaderFormat: in struct.Struct() form
587 # TeOffset
588 # HeaderSize)
589 self.PeHdr = None
590 self.TeHdr = None
591 self.TeAdjust = 0
592
593 self.PeCoffType = ''
594 self.MachineType = ''
595 self.PeHdrFmt = None
596 self.PeSections = 0
597 self.FvSection = False
598 self.ZeroList = []
599 self.PeCoffHdrRead ()
600
601 def TeHdrTuple (self, offset=0):
602 data = self.f.Read (EfiPeCoff.TeHdrLength,offset)
603 TeHdr = EfiPeCoff.EFI_TE_IMAGE_HEADER._make (struct.Struct(EfiPeCoff.EFI_TE_IMAGE_HEADER_fmt).unpack_from (data))
604 return (TeHdr, EfiPeCoff.TeHdrLength - TeHdr.StrippedSize)
605
606 def DosHdrTuple (self, offset=0):
607 data = self.f.Read(EfiPeCoff.DosHdrLength,offset)
608 return EfiPeCoff.EFI_IMAGE_DOS_HEADER._make (struct.unpack_from(EfiPeCoff.EFI_IMAGE_DOS_HEADER_fmt, data))
609
610 ImageFileMachine = {
611 0x014c : "IA32",
612 0x0200 : "IPF",
613 0x0EBC : "EBC",
614 0x8664 : "X64",
615 0x01c2 : "ARM",
616 0xAA64 : "AArch64",
617 }
618
619 def PeCoffHdrRead (self):
620 # Test for FV Section (*.te build output)
621 image = self.f.Read(4, 0)
622 if image[0:2] == 'MZ' or image[0:2] == 'VZ' or image[0:4] == 'PE\0\0':
623 offset = 0
624 else:
625 offset = 4
626 self.FvSection = True
627
628 image = self.f.Read(2, offset)
629 if image[0:2] == 'MZ':
630 # PE/COFF starts with DOS Header
631 DosHdr = self.DosHdrTuple (offset)
632 offset += DosHdr.e_lfanew
633 elif image[0:2] == 'VZ':
634 # PE/COFF starts with TE Header
635 self.TeHdr, self.TeAdjust = self.TeHdrTuple (offset)
636 self.PeCoffType = "TE"
637 self.MachineType = self.ImageFileMachine.get (self.TeHdr.Machine, 'Unknown')
638 self.PeSections = EfiPeCoff.TeHdrLength
639
640 data = self.f.Read(EfiPeCoff.TeHdrLength, offset)
641 self.PeHdrFmt = EfiPeCoff.EFI_TE_IMAGE_HEADER_fmt
642 return
643 else:
644 # PE/COFF starts with PE/COFF header
645 offset = 0
646
647 image = self.f.Read(4, offset)
648 if image[0:4] != 'PE\0\0':
649 print "Bad PE/COFF Signature = %4s" % image
650 return ("Unknown", None, "", 0, 0)
651
652 # Check the magic to figure out if 32 or 64 bit PE/COFF
653 (Magic,) = struct.unpack_from ('<H', self.f.Read(2, offset+24))
654 if Magic == EfiPeCoff.EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
655 data = self.f.Read(EfiPeCoff.OptionalHeader32Length, offset)
656 self.PeHdr = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32._make (struct.Struct(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt).unpack_from (data))
657 self.PeCoffType = "PE32"
658 self.PeHdrFmt = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt
659
660 # TimeDateStamp: Offset, size
661 self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt[0:4]), 4])
662 # Checksum: Offset, size
663 self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt[0:29]), 4])
664 elif Magic == EfiPeCoff.EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
665 data = self.f.Read(EfiPeCoff.OptionalHeader64Length, offset)
666 self.PeHdr = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64._make (struct.Struct(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt).unpack_from (data))
667 self.PeCoffType = "PE32+"
668 self.PeHdrFmt = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt
669
670 # TimeDateStamp: Offset, size
671 self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt[0:4]), 4])
672 # Checksum: Offset, size
673 self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt[0:29]), 4])
674 else:
675 print "Unknown Magic 0x%02x" % Magic
676 return ("Unknown", None, "", 0, 0)
677
678 self.MachineType = self.ImageFileMachine.get (self.PeHdr.Machine, 'Unknown')
679
680 # ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
681 self.PeSections = offset + 4 + 20 + self.PeHdr.SizeOfOptionalHeader
682
683 def PeCoffDumpHdr (self):
684 PeHdr = self.PeHdr if self.TeHdr is None else self.TeHdr
685 Width = max (len (s) for s in PeHdr._fields)
686 return "\n".join('{0} = {1:#0{2}x}'.format(s.ljust(Width), getattr(PeHdr, s), FmtStrToWidth(self.PeHdrFmt[i+1])+2) for i, s in enumerate (PeHdr._fields))
687
688 def PeCoffZeroInfo (self):
689 # Return the files offsets and number of bytes that need to get zero'ed
690 return self.ZeroList
691
692 def NumberOfSections (self):
693 if self.PeHdr is not None:
694 return self.PeHdr.NumberOfSections
695 elif self.TeHdr is not None:
696 return self.TeHdr.NumberOfSections
697 else:
698 return 0
699
700 def PeCoffGetSection (self, index):
701 offset = self.PeSections + (index * EfiPeCoff.PeCoffSectionLength)
702 data = self.f.Read(EfiPeCoff.PeCoffSectionLength, offset)
703 return (data[0:8].split('\x00')[0], EfiPeCoff.EFI_IMAGE_SECTION_HEADER._make (struct.Struct(EfiPeCoff.EFI_IMAGE_SECTION_HEADER_fmt).unpack_from (data)))
704
705 def PeCoffDumpSectionHdr (self, Name, Section):
706 Width = max (len (s) for s in Section._fields)
707 result = ''
708 for i, s in enumerate (Section._fields):
709 result += '{0} = '.format(s.ljust(Width))
710 if i == 0 and Name != '':
711 # print name as a string, not a hex value
712 result += Name + '\n'
713 else:
714 result += '{0:#0{1}x}\n'.format(getattr(Section, s), FmtStrToWidth(EfiPeCoff.EFI_IMAGE_SECTION_HEADER_fmt[i+1])+2)
715
716 return result
717
718 def PeCoffDumpSection (self, Name, Section):
719 data = self.f.Read (Section.SizeOfRawData, Section.VirtualAddress)
720 result = []
721 Address = Section.VirtualAddress
722 for i in xrange (0, Section.SizeOfRawData, 16):
723 HexStr = ' '.join(["%02X"%ord(x) for x in data[i:i+16]])
724 TextStr = ''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in data[i:i+16]])
725 result.append("%08X %-*s |%s|\n" % (Address + i, 16*3, HexStr, TextStr))
726
727 return ''.join(result)
728
729
730 def PeCoffGetPdePointer (self, DebugEntry = 0, DebugEntrySize = 0, adjust = 0):
731 #
732 if DebugEntrySize == 0:
733 if self.PeHdr is not None:
734 DebugEntry = self.PeHdr.DataDirVirt_Debug
735 DebugEntrySize = self.PeHdr.DataDirSize_Debug
736 elif self.TeHdr is not None:
737 DebugEntry = self.TeHdr.DataDirVirt_Debug
738 DebugEntrySize = self.TeHdr.DataDirSize_Debug
739 adjust = self.TeAdjust
740 else:
741 return ('','')
742
743 offset = DebugEntry + adjust
744 data = self.f.Read(DebugEntrySize, offset)
745 DirectoryEntry = EfiPeCoff.EFI_IMAGE_DEBUG_DIRECTORY_ENTRY._make (struct.Struct(EfiPeCoff.EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_fmt).unpack_from (data))
746 offset = DirectoryEntry.FileOffset + adjust
747
748 data = self.f.Read(4, offset)
749 guid = ''
750 if data == 'MTOC':
751 data = self.f.Read(16)
752 tup = struct.unpack (EfiPeCoff.EFI_GUID_fmt, data)
753 guid = '{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}'.format(*tup)
754 Str = self.f.ReadCString ()
755 elif data == 'NB10':
756 Str = self.f.ReadCString (offset + 16)
757 elif data == 'RSDS':
758 Str = self.f.ReadCString (offset + 24)
759 else:
760 Str = "\x00"
761
762
763 # Python is more that happy to print out a NULL
764 return (Str.split('\x00')[0], guid)
765
766 def PeCoffDumpRelocations (self, offset, size):
767 data = self.f.Read(size, offset)
768 base = 0
769 baseEnd = size - EfiPeCoff.BaseRelocationLength
770 value = ''
771 while base < baseEnd:
772 (VirtualAddress, SizeOfBlock) = struct.unpack_from (EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt, data[base:base + EfiPeCoff.BaseRelocationLength])
773 if SizeOfBlock == 0 or SizeOfBlock > size:
774 break
775 reloc = base + EfiPeCoff.BaseRelocationLength
776 relocEnd = base + SizeOfBlock
777 value += '0x%08x SizeOfBlock 0x%x\n' % (VirtualAddress, SizeOfBlock)
778 while reloc < relocEnd:
779 rel, = struct.unpack_from ('<H', data[reloc:reloc+2])
780 value += ' 0x%04x 0x%x\n' % ((rel & 0xFFF), rel >> 12, )
781 reloc += 2
782
783 base = relocEnd
784 return value
785
786 def PeCoffDumpCert (self, offset, size):
787 data = self.f.Read(size, offset)
788 value = '\n'
789 if size > 8:
790 (dwLength, wRevision, wCertificateType) = struct.unpack_from (EfiPeCoff.WIN_CERTIFICATE_fmt, data)
791 value += "dwLength = 0x%04x wRevision = 0x%02x wCertificateType = 0x%02x\n" % (dwLength, wRevision, wCertificateType)
792 # UEFI Scheme
793 for i in range(struct.calcsize(EfiPeCoff.WIN_CERTIFICATE_fmt), size, 0x10):
794 value += "0x{:04x}:".format(i),
795 value += " ".join("{:02x}".format(ord(c)) for c in data[i:i+0x10])
796 value += '\n'
797 else:
798 # Loki Scheme
799 start = 0
800 while start < size:
801 (VirtualAddress, SizeOfBlock) = struct.unpack_from (EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt, data[start: start + struct.calcsize(EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt)])
802 start += struct.calcsize(EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt)
803 value += "CERT: 0x%X size 0x%x\n" % (VirtualAddress, SizeOfBlock)
804 cert = self.f.Read(SizeOfBlock, VirtualAddress)
805 for i in range(0, SizeOfBlock, 0x10):
806 value += "0x{:04x}:".format(i)
807 value += " ".join("{:02x}".format(ord(c)) for c in cert[i:i+0x10])
808 value += '\n'
809 return value
810
811 def __str__(self):
812 return self.PeCoffDumpHdr()
813
814 def FmtStrToWidth (c):
815 c = c.upper()
816 if c== 'B':
817 return 1*2
818 if c== 'H':
819 return 2*2
820 if c== 'I' or c=='L':
821 return 4*2
822 if c== 'Q':
823 return 8*2
824 return 0
825
826 #define EFI_FAT_BINARY_MAGIC 0x0ef1fab9
827
828 # typedef struct _EFI_FAT_BINARY_HEADER {
829 # UINT32 magic; /* FAT_MAGIC */
830 # UINT32 nfat_arch; /* number of structs that follow */
831 # } EFI_FAT_BINARY_HEADER;
832
833 # typedef struct _EFI_FAT_BINARY_ARCH {
834 # UINT32 cputype; /* cpu specifier (int) */
835 # UINT32 cpusubtype; /* machine specifier (int) */
836 # UINT32 offset; /* file offset to this object file */
837 # UINT32 size; /* size of this object file */
838 # UINT32 align; /* alignment as a power of 2 */
839 # } EFI_FAT_BINARY_ARCH;
840
841 EFI_FAT_BINARY_ARCH_fmt = '<IIIII'
842
843 fatCpuType = {
844 0x01000007: 'x86_64 (X64)',
845 0x00000007: 'i386 (Ia32)',
846 0x0000000C: 'ARM (Arm)',
847 0x0100000C: 'ARM64 (AArch64)',
848 }
849
850 def CheckForFatBinary (f):
851 '''Return a list of PE/COFF binary objects, from a file object.
852 '''
853 fatEntry = 4 + 4
854 data = f.read(fatEntry)
855 (magic, nfat_arch) = struct.unpack_from ('<II', data)
856 if magic == 0x0ef1fab9:
857 res = []
858 for i in range (nfat_arch):
859 f.seek(fatEntry)
860 fatEntry += struct.calcsize(EFI_FAT_BINARY_ARCH_fmt)
861 data = f.read(struct.calcsize(EFI_FAT_BINARY_ARCH_fmt))
862 (cputype, cpusubtype, offset, size, align) = struct.unpack_from (EFI_FAT_BINARY_ARCH_fmt, data)
863 f.seek(offset)
864 res.append((EfiPeCoff(f.read (size)), "FAT Binary of type %s: offset 0x%x size 0x%x alignment 0x%x" % (fatCpuType.get(cputype, 'Unknown'), offset, size, align)))
865 else:
866 # entire file is a PE/COFF image
867 f.seek(0)
868 res = [(EfiPeCoff(f.read()), "")]
869 return res
870
871 if __name__ == "__main__":
872 usage = "usage: %prog [options] PECOFF_FILE"
873 parser = optparse.OptionParser(usage=usage)
874 parser.add_option('-r', '--relocations', action='store_true', dest='relocation', help='display relocation info', default=False)
875 parser.add_option('-c', '--cert', action='store_true', dest='cert', help='display security cert info', default=False)
876 parser.add_option('-s', '--section', type=str, dest='section', help='dump info on a section', default='')
877 parser.add_option('-z', '--zero', action='store_true', dest='zero', help='Zero out fields to enable build reproducibility', default=False)
878 (options, args) = parser.parse_args(sys.argv)
879
880 if len(args) <= 1:
881 parser.print_help()
882 sys.exit(-1)
883
884 with open(args[1], "rb" if not options.zero else "r+b") as f:
885 for (pecoff, description) in CheckForFatBinary (f):
886 if not options.zero:
887 if description != '':
888 print description
889
890 print "%s is a %s:%s image%s" % (args[1], pecoff.PeCoffType, pecoff.MachineType, ' wrapped in FV Section:' if pecoff.FvSection else ':')
891 if pecoff.PeCoffType == '':
892 sys.exit(-1)
893
894 # print header
895 print pecoff.PeCoffDumpHdr()
896 print
897 print "\nSections:"
898 for i in range (0, pecoff.NumberOfSections()):
899 (Name, Section) = pecoff.PeCoffGetSection (i)
900 print pecoff.PeCoffDumpSectionHdr (Name, Section)
901 print
902
903 if '.reloc' in Name and options.relocation:
904 print pecoff.PeCoffDumpRelocations (Section.PointerToRawData, Section.VirtualSize)
905
906 elif '.debug' in Name:
907 (PdbPointer, Guid) = pecoff.PeCoffGetPdePointer ()
908 if Guid == '':
909 print "PdbPointer:{0}\n".format(PdbPointer)
910 else:
911 print "PdbPointer (Mach-O symbol file):{0}\n (Mach-O UUID): {1}".format(PdbPointer, Guid)
912
913 if options.section in Name and options.section != '':
914 print pecoff.PeCoffDumpSection(Name, Section)
915
916 if options.cert:
917 print pecoff.PeCoffDumpCert (pecoff.PeHdr.DataDirVirt_Security, pecoff.PeHdr.DataDirSize_Security)
918
919 else:
920 # this is necessary to find the 'zero list' entries for the debug section
921 for i in range (0, pecoff.NumberOfSections()):
922 (Name, Section) = pecoff.PeCoffGetSection (i)
923
924 if Section.SizeOfRawData > Section.VirtualSize:
925 sizeDiff = Section.SizeOfRawData - Section.VirtualSize
926 offset = pecoff.TeAdjust + Section.PointerToRawData + Section.SizeOfRawData - sizeDiff
927 pecoff.ZeroList.append( [offset, sizeDiff] )
928
929 # The .debug section also contains a timestamp
930 if '.debug' in Name:
931 pecoff.ZeroList.append([pecoff.TeAdjust + Section.PointerToRawData + struct.calcsize(EfiPeCoff.EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_fmt[0:2]), 4])
932
933 for patch, size in pecoff.PeCoffZeroInfo():
934 #print 'patching 0x%x for 0x%x bytes' % (patch, size)
935 if patch != 0:
936 if size == -1:
937 # -1 means to the end of the file
938 f.seek(0,2)
939 size = f.tell() - patch
940 f.seek(patch)
941 f.write(bytearray(size))
942