#!/usr/bin/env python ''' This script dumps the Objective-C metadata from the provided binary and generate a header-like of different structure identified. Note: this script is only working with the extended version of LIEF ''' import sys import lief import argparse from pathlib import Path from typing import Optional def process(filepath: str, skip_protocols: bool = False, output_path: Optional[str] = None) -> int: target = Path(filepath) if not target.is_file(): print(f"'{target}' is not a valid file", file=sys.stderr) return 1 macho = lief.MachO.parse(target) if macho is None: print(f"Can't parse Mach-O file: {target}", file=sys.stderr) metadata = macho.at(0).objc_metadata if metadata is None: print(f"Can't parse ObjC metadata in {target}'", file=sys.stderr) return 1 if skip_protocols: output = "" for cls in metadata.classes: output += cls.to_decl() else: output = metadata.to_decl() print(output) if output_path is not None: out = Path(output_path) if out.is_dir(): out /= f"{target.name}_objc.h" out.write_text(output) print(f"Saved in {out}") else: print(f"Saved in {out}") out.write_text(output) return 0 def main() -> int: parser = argparse.ArgumentParser() parser.add_argument('-o', '--output', help='Output file', default=None) parser.add_argument('--skip-protocols', help='Skip ObjC protocols definition', action='store_true') parser.add_argument("file", help='Mach-O file') args = parser.parse_args() lief.logging.set_level(lief.logging.LEVEL.WARN) return process(args.file, args.skip_protocols, args.output) if __name__ == "__main__": raise SystemExit(main())