comparison pytouhou/utils/pe.py @ 229:5afc75f71fed

Add “SHT” support to EoSD, and do a little cleanup.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 30 Dec 2011 18:37:06 +0100
parents
children e15672733c93
comparison
equal deleted inserted replaced
228:8f4cd1c01d22 229:5afc75f71fed
1 # -*- encoding: utf-8 -*-
2 ##
3 ## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com>
4 ##
5 ## This program is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published
7 ## by the Free Software Foundation; version 3 only.
8 ##
9 ## This program is distributed in the hope that it will be useful,
10 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ## GNU General Public License for more details.
13 ##
14
15 from struct import Struct, unpack
16 from collections import namedtuple
17
18
19 class PEStructs:
20 _IMAGE_FILE_HEADER = namedtuple('_IMAGE_FILE_HEADER',
21 ('Machine',
22 'NumberOfSections',
23 'TimeDateStamp',
24 'PointerToSymbolTable',
25 'NumberOfSymbols',
26 'SizeOfOptionalHeader',
27 'Characteristics'))
28 @classmethod
29 def read_image_file_header(cls, file):
30 format = Struct('<HHIIIHH')
31 return cls._IMAGE_FILE_HEADER(*format.unpack(file.read(format.size)))
32
33 _IMAGE_OPTIONAL_HEADER = namedtuple('_IMAGE_OPTIONAL_HEADER',
34 ('Magic',
35 'MajorLinkerVersion', 'MinorLinkerVersion',
36 'SizeOfCode', 'SizeOfInitializedData',
37 'SizeOfUninitializedData',
38 'AddressOfEntryPoint', 'BaseOfCode',
39 'BaseOfData', 'ImageBase',
40 'SectionAlignement', 'FileAlignement',
41 'MajorOperatingSystemVersion',
42 'MinorOperatingSystemVersion',
43 'MajorImageVersion',
44 'MinorImageVersion',
45 'MajorSubsystemVersion',
46 'MinorSubsystemVersion',
47 'Win32VersionValue',
48 'SizeOfImage',
49 'SizeOfHeaders',
50 'CheckSum',
51 'Subsystem',
52 'DllCharacteristics',
53 'SizeOfStackReserve',
54 'SizeOfStackCommit',
55 'SizeOfHeapReserve',
56 'SizeOfHeapCommit',
57 'LoaderFlags',
58 'NumberOfRvaAndSizes',
59 'DataDirectory'))
60 _IMAGE_DATA_DIRECTORY = namedtuple('_IMAGE_DATA_DIRECTORY',
61 ('VirtualAddress', 'Size'))
62 @classmethod
63 def read_image_optional_header(cls, file):
64 format = Struct('<HBBIIIIIIIIIHHHHHHIIIIHHIIIIII')
65 directory_format = Struct('<II')
66 directory = []
67 partial_header = format.unpack(file.read(format.size))
68 directory = [cls._IMAGE_DATA_DIRECTORY(*directory_format.unpack(file.read(directory_format.size))) for i in xrange(16)]
69 return cls._IMAGE_OPTIONAL_HEADER(*(partial_header + (directory,)))
70
71 _IMAGE_SECTION_HEADER = namedtuple('_IMAGE_SECTION_HEADER',
72 ('Name', 'VirtualSize',
73 'VirtualAddress',
74 'SizeOfRawData', 'PointerToRawData',
75 'PointerToRelocations',
76 'PointerToLinenumbers',
77 'NumberOfRelocations',
78 'NumberOfLinenumbers',
79 'Characteristics'))
80 @classmethod
81 def read_image_section_header(cls, file):
82 format = Struct('<8sIIIIIIHHI')
83 return cls._IMAGE_SECTION_HEADER(*format.unpack(file.read(format.size)))
84
85
86
87 class PEFile(object):
88 def __init__(self, file):
89 self.file = file
90
91 self.image_base = 0
92 self.sections = []
93
94 file.seek(0x3c)
95 pe_offset, = unpack('<I', file.read(4))
96
97 file.seek(pe_offset)
98 pe_sig = file.read(4)
99 assert pe_sig == b'PE\0\0'
100
101 pe_file_header = PEStructs.read_image_file_header(file)
102 pe_optional_header = PEStructs.read_image_optional_header(file)
103
104 # Read image base
105 self.image_base = pe_optional_header.ImageBase
106
107 self.sections = [PEStructs.read_image_section_header(file)
108 for i in xrange(pe_file_header.NumberOfSections)]
109
110
111 def seek_to_va(self, va):
112 self.file.seek(self.va_to_offset(va))
113
114
115 def offset_to_rva(self, offset):
116 for section in self.sections:
117 if 0 <= (offset - section.PointerToRawData) < section.SizeOfRawData:
118 #TODO: is that okay?
119 return offset - section.PointerToRawData + section.VirtualAddress
120 raise IndexError #TODO
121
122
123 def offset_to_va(self, offset):
124 return self.offset_to_rva(offset) + self.image_base
125
126
127 def rva_to_offset(self, rva):
128 for section in self.sections:
129 if 0 <= (rva - section.VirtualAddress) < section.SizeOfRawData:
130 #TODO: is that okay?
131 return rva - section.VirtualAddress + section.PointerToRawData
132 raise IndexError #TODO
133
134
135 def va_to_offset(self, va):
136 return self.rva_to_offset(va - self.image_base)
137