From 1c238512f759c9b0b91f8086c4eba9e6ceeba87e Mon Sep 17 00:00:00 2001 From: Elliot Nunn Date: Wed, 20 Mar 2019 22:42:35 +0800 Subject: [PATCH] Add script to rip the number of args from 68k code --- search_call_sigs.py | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100755 search_call_sigs.py diff --git a/search_call_sigs.py b/search_call_sigs.py new file mode 100755 index 0000000..5a9685a --- /dev/null +++ b/search_call_sigs.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 + +import argparse + + +parser = argparse.ArgumentParser(description=''' + Search a 68k binary file for the "MOVE.L ,d0; DC.W $FE22" + motif. Use the upper word of the selector to determine how many + 32-bit arguments the call takes. This is useful because, while many + selector names are known from reversing the BlueAbstractionLayerLib, + that PowerPC binary does not reveal anything about their function + signatures. Instead this falls to 68k code, in which the number of + arguments is often passed to a trap via the selector in order to + avoid catastrophic stack damage in the unknown-selector case. +''') + +parser.add_argument('src', action='store', help='Source file') +parser.add_argument('-o', nargs='?', action='store', help='Listing file to update') + +args = parser.parse_args() + + +with open(args.src, 'rb') as f: + binary = f.read() + + +def matches(long, short): + keepers = bytearray() + + for i in range(len(short)): + if short[i] == 0: + keepers.append(long[i]) + + if short[i] not in (0, long[i]): + return False + + return bytes(keepers) + + +MOTIF = b'\x20\x3C\x00\x00\x00\x00\xFE\x22' + +for i in range(len(binary) - len(MOTIF)): + match = matches(binary[i:i+len(MOTIF)], MOTIF) + + if match: + long = int.from_bytes(match, byteorder='big') + + selector = long & 0xFFFF + nargs = long >> 16 + + print('selector %04x: %d' % (selector, nargs)) + + if args.o: + with open(args.o) as f: + lines = [l.rstrip('\n').split(' ') for l in f] + + for line in lines: + line[0] = int(line[0], 16) # interpret the hex at the start! + + for line in lines: + if line[0] == selector: + if line[1] == '?': + print('...updated') + line[1] = str(nargs) + elif line[1] != str(nargs): + print('...WARNING: the listing file says %s' % line[1]) + break + else: + lines.append([selector, nargs, '???']) + lines.sort() + + for line in lines: + line[0] = '%04X' % line[0] + + with open(args.o, 'w') as f: + f.write(''.join(' '.join(l)+'\n' for l in lines))