comparison pytouhou/formats/exe.py @ 261:2876c267be00

Add heuristics to extract character data from the demo .exe.
author Thibaut Girka <thib@sitedethib.com>
date Mon, 23 Jan 2012 00:03:06 +0100
parents 741860192b56
children 92a6fd2632f1
comparison
equal deleted inserted replaced
260:e22e0d73f614 261:2876c267be00
93 and 0 <= ptr2 - text_va < text_size - 8): 93 and 0 <= ptr2 - text_va < text_size - 8):
94 break 94 break
95 95
96 # So far, this character definition seems to be valid. 96 # So far, this character definition seems to be valid.
97 # Now, make sure the shoot function wrappers pass valid addresses 97 # Now, make sure the shoot function wrappers pass valid addresses
98 pe_file.seek_to_va(ptr1 + 4) 98
99 shtptr1, = unpack('<I', pe_file.file.read(4)) 99 # Search for the “push” instruction
100 pe_file.seek_to_va(ptr2 + 4) 100 for i in xrange(20):
101 shtptr2, = unpack('<I', pe_file.file.read(4)) 101 # Find the “push” instruction
102 pe_file.seek_to_va(ptr1 + i)
103 instr1, shtptr1 = unpack('<BI', pe_file.file.read(5))
104 pe_file.seek_to_va(ptr2 + i)
105 instr2, shtptr2 = unpack('<BI', pe_file.file.read(5))
106 if instr1 == 0x68 and instr2 == 0x68 and (0 <= shtptr1 - data_va < data_size - 12
107 and 0 <= shtptr2 - data_va < data_size - 12):
108 # It is unlikely this character record is *not* valid, but
109 # just to be sure, let's check the first SHT definition.
110 pe_file.seek_to_va(shtptr1)
111 nb_shots, power, shotsptr = unpack('<III', pe_file.file.read(12))
112 if (0 < nb_shots <= 1000
113 and 0 <= power < 1000
114 and 0 <= shotsptr - data_va < data_size - 36*nb_shots):
115 break
116 # Check if everything is fine...
102 if not (0 <= shtptr1 - data_va < data_size - 12 117 if not (0 <= shtptr1 - data_va < data_size - 12
103 and 0 <= shtptr2 - data_va < data_size - 12): 118 and 0 <= shtptr2 - data_va < data_size - 12
104 break 119 and 0 < nb_shots <= 1000
105
106 # It is unlikely this character record is *not* valid, but
107 # just to be sure, let's check the first SHT definition.
108 pe_file.seek_to_va(shtptr1)
109 nb_shots, power, shotsptr = unpack('<III', pe_file.file.read(12))
110 if not (0 < nb_shots <= 1000
111 and 0 <= power < 1000 120 and 0 <= power < 1000
112 and 0 <= shotsptr - data_va < data_size - 36*nb_shots): 121 and 0 <= shotsptr - data_va < data_size - 36*nb_shots):
113 break 122 break
114 123
115 else: 124 else:
121 130
122 131
123 @classmethod 132 @classmethod
124 def read(cls, file): 133 def read(cls, file):
125 pe_file = PEFile(file) 134 pe_file = PEFile(file)
135 data_section = [section for section in pe_file.sections
136 if section.Name.startswith('.data')][0]
137 text_section = [section for section in pe_file.sections
138 if section.Name.startswith('.text')][0]
139 data_va = pe_file.image_base + data_section.VirtualAddress
140 data_size = data_section.SizeOfRawData
141 text_va = pe_file.image_base + text_section.VirtualAddress
142 text_size = text_section.SizeOfRawData
126 143
127 character_records_va = list(cls.find_character_defs(pe_file))[0] 144 character_records_va = list(cls.find_character_defs(pe_file))[0]
128 145
129 characters = [] 146 characters = []
130 shots_offsets = {} 147 shots_offsets = {}
146 # focused or not, but properties read earlier apply to both modes. 163 # focused or not, but properties read earlier apply to both modes.
147 focused_sht = copy(sht) 164 focused_sht = copy(sht)
148 characters.append((sht, focused_sht)) 165 characters.append((sht, focused_sht))
149 166
150 for sht, func_offset in ((sht, shots_func_offset), (focused_sht, shots_func_offset_focused)): 167 for sht, func_offset in ((sht, shots_func_offset), (focused_sht, shots_func_offset_focused)):
151 # Read from “push” operand 168 # Search for the “push” instruction
152 pe_file.seek_to_va(func_offset + 4) 169 for i in xrange(20):
153 offset, = unpack('<I', file.read(4)) 170 # Find the “push” instruction
171 pe_file.seek_to_va(func_offset + i)
172 instr, offset = unpack('<BI', file.read(5))
173 if instr == 0x68 and 0 <= offset - data_va < data_size - 12:
174 pe_file.seek_to_va(offset)
175 nb_shots, power, shotsptr = unpack('<III', pe_file.file.read(12))
176 if (0 < nb_shots <= 1000
177 and 0 <= power < 1000
178 and 0 <= shotsptr - data_va < data_size - 36*nb_shots):
179 break
154 if offset not in shots_offsets: 180 if offset not in shots_offsets:
155 shots_offsets[offset] = [] 181 shots_offsets[offset] = []
156 shots_offsets[offset].append(sht) 182 shots_offsets[offset].append(sht)
157 183
158 for shots_offset, shts in shots_offsets.iteritems(): 184 for shots_offset, shts in shots_offsets.iteritems():