Mercurial > touhou
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(): |