]>
Commit | Line | Data |
---|---|---|
e456bf10 A |
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 | ||
897 | print "\nSections:" | |
898 | for i in range (0, pecoff.NumberOfSections()): | |
899 | (Name, Section) = pecoff.PeCoffGetSection (i) | |
900 | print pecoff.PeCoffDumpSectionHdr (Name, Section) | |
901 | ||
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 |