"""Read-only disassembly of an explicit PE RVA range; no process attachment.""" import argparse import hashlib import pathlib import struct from capstone import Cs, CS_ARCH_X86, CS_MODE_64 def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--binary', type=pathlib.Path, required=True) parser.add_argument('--rva', type=lambda s: int(s, 0), required=True) parser.add_argument('--size', type=lambda s: int(s, 0), required=True) parser.add_argument('--output', type=pathlib.Path, required=True) parser.add_argument('--containing-function', action='store_true', help='Use the AMD64 exception-table bounds containing the selected RVA') args = parser.parse_args() if not 0 < args.size <= 65536: raise SystemExit('Select a range of 1..65536 bytes') data = args.binary.read_bytes() if data[:2] != b'MZ': raise SystemExit('Expected PE image') pe = struct.unpack_from(' len(data): raise SystemExit('Truncated section') decoder = Cs(CS_ARCH_X86, CS_MODE_64) scope = 'AMD64 exception-table function bounds' if args.containing_function else 'explicit range; function boundaries unproven' lines = [f'; SHA256 {hashlib.sha256(data).hexdigest()}', f'; RVA {args.rva:#x}, length {args.size:#x}; {scope}'] lines += [f'{ins.address:x}: {ins.mnemonic} {ins.op_str}' for ins in decoder.disasm(data[start:start+args.size], args.rva)] args.output.write_text('\n'.join(lines)+'\n', encoding='utf-8') print(f'Wrote {len(lines)-2} instructions to {args.output}') return raise SystemExit('RVA range is not contained in a raw section') if __name__ == '__main__': main()