# HG changeset patch # User Thibaut Girka # Date 1325268649 -3600 # Node ID 1c24a6d93c1b5a5b733b2af60a289eb244d7993c # Parent 5afc75f71fed186d228ceee1b9439e81e10a458a Improve find_character_defs, clean up a bit, and disable attack types 2 and 3 for now diff --git a/pytouhou/formats/exe.py b/pytouhou/formats/exe.py --- a/pytouhou/formats/exe.py +++ b/pytouhou/formats/exe.py @@ -34,13 +34,10 @@ class Shot(object): self.speed = 0. self.damage = 0 self.orb = 0 - self.shot_type = 0 + self.type = 0 self.sprite = 0 self.unknown1 = None - def __repr__(self): - return '(%d, %d, %f, %f, %d, %d, %d, %d, %d)' % (self.interval, self.delay, self.angle, self.speed, self.damage, self.orb, self.shot_type, self.sprite, self.unknown1) - class SHT(object): def __init__(self): @@ -61,33 +58,63 @@ class SHT(object): @classmethod - def find_character_records(self, file, pe_file): + def find_character_defs(cls, pe_file): + """Generator returning the possible VA of character definition blocks. + + Based on knowledge of the structure, it tries to find valid definition blocks + without embedding any copyrighted material or hard-coded offsets that would + only be useful for a specific build of the game. + """ + format = Struct('<4f2I') - data_section = [section for section in pe_file.sections if section.Name.startswith('.data')][0] - text_section = [section for section in pe_file.sections if section.Name.startswith('.text')][0] + data_section = [section for section in pe_file.sections + if section.Name.startswith('.data')][0] + text_section = [section for section in pe_file.sections + if section.Name.startswith('.text')][0] data_va = pe_file.image_base + data_section.VirtualAddress + data_size = data_section.SizeOfRawData text_va = pe_file.image_base + text_section.VirtualAddress + text_size = text_section.SizeOfRawData - for addr in xrange(data_va, data_va + data_section.SizeOfRawData, 4): + # Search the whole data segment for 4 successive character definitions + for addr in xrange(data_va, data_va + data_size, 4): for character_id in xrange(4): pe_file.seek_to_va(addr + character_id * 24) - speed1, speed2, speed3, speed4, ptr1, ptr2 = format.unpack(file.read(format.size)) + (speed1, speed2, speed3, speed4, + ptr1, ptr2) = format.unpack(pe_file.file.read(format.size)) - if not (all(0. < x < 8. for x in (speed1, speed2, speed3, speed4)) + # Check whether the character's speed make sense, + # and whether the function pointers point to valid addresses + if not (all(0. < x < 10. for x in (speed1, speed2, speed3, speed4)) and speed2 <= speed1 - and 0 <= ptr1 - text_va < text_section.SizeOfRawData - 8 - and 0 <= ptr2 - text_va < text_section.SizeOfRawData - 8): + and 0 <= ptr1 - text_va < text_size - 8 + and 0 <= ptr2 - text_va < text_size - 8): break + # So far, this character definition seems to be valid. + # Now, make sure the shoot function wrappers pass valid addresses pe_file.seek_to_va(ptr1 + 4) - shtptr1, = unpack('