1*be691f3bSpatrick#!/usr/bin/env python 2061da546Spatrick 3061da546Spatrickimport cmd 4061da546Spatrickimport dict_utils 5061da546Spatrickimport file_extract 6061da546Spatrickimport optparse 7061da546Spatrickimport re 8061da546Spatrickimport struct 9061da546Spatrickimport string 10061da546Spatrickimport io 11061da546Spatrickimport sys 12061da546Spatrickimport uuid 13061da546Spatrick 14061da546Spatrick# Mach header "magic" constants 15061da546SpatrickMH_MAGIC = 0xfeedface 16061da546SpatrickMH_CIGAM = 0xcefaedfe 17061da546SpatrickMH_MAGIC_64 = 0xfeedfacf 18061da546SpatrickMH_CIGAM_64 = 0xcffaedfe 19061da546SpatrickFAT_MAGIC = 0xcafebabe 20061da546SpatrickFAT_CIGAM = 0xbebafeca 21061da546Spatrick 22061da546Spatrick# Mach haeder "filetype" constants 23061da546SpatrickMH_OBJECT = 0x00000001 24061da546SpatrickMH_EXECUTE = 0x00000002 25061da546SpatrickMH_FVMLIB = 0x00000003 26061da546SpatrickMH_CORE = 0x00000004 27061da546SpatrickMH_PRELOAD = 0x00000005 28061da546SpatrickMH_DYLIB = 0x00000006 29061da546SpatrickMH_DYLINKER = 0x00000007 30061da546SpatrickMH_BUNDLE = 0x00000008 31061da546SpatrickMH_DYLIB_STUB = 0x00000009 32061da546SpatrickMH_DSYM = 0x0000000a 33061da546SpatrickMH_KEXT_BUNDLE = 0x0000000b 34061da546Spatrick 35061da546Spatrick# Mach haeder "flag" constant bits 36061da546SpatrickMH_NOUNDEFS = 0x00000001 37061da546SpatrickMH_INCRLINK = 0x00000002 38061da546SpatrickMH_DYLDLINK = 0x00000004 39061da546SpatrickMH_BINDATLOAD = 0x00000008 40061da546SpatrickMH_PREBOUND = 0x00000010 41061da546SpatrickMH_SPLIT_SEGS = 0x00000020 42061da546SpatrickMH_LAZY_INIT = 0x00000040 43061da546SpatrickMH_TWOLEVEL = 0x00000080 44061da546SpatrickMH_FORCE_FLAT = 0x00000100 45061da546SpatrickMH_NOMULTIDEFS = 0x00000200 46061da546SpatrickMH_NOFIXPREBINDING = 0x00000400 47061da546SpatrickMH_PREBINDABLE = 0x00000800 48061da546SpatrickMH_ALLMODSBOUND = 0x00001000 49061da546SpatrickMH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000 50061da546SpatrickMH_CANONICAL = 0x00004000 51061da546SpatrickMH_WEAK_DEFINES = 0x00008000 52061da546SpatrickMH_BINDS_TO_WEAK = 0x00010000 53061da546SpatrickMH_ALLOW_STACK_EXECUTION = 0x00020000 54061da546SpatrickMH_ROOT_SAFE = 0x00040000 55061da546SpatrickMH_SETUID_SAFE = 0x00080000 56061da546SpatrickMH_NO_REEXPORTED_DYLIBS = 0x00100000 57061da546SpatrickMH_PIE = 0x00200000 58061da546SpatrickMH_DEAD_STRIPPABLE_DYLIB = 0x00400000 59061da546SpatrickMH_HAS_TLV_DESCRIPTORS = 0x00800000 60061da546SpatrickMH_NO_HEAP_EXECUTION = 0x01000000 61061da546Spatrick 62061da546Spatrick# Mach load command constants 63061da546SpatrickLC_REQ_DYLD = 0x80000000 64061da546SpatrickLC_SEGMENT = 0x00000001 65061da546SpatrickLC_SYMTAB = 0x00000002 66061da546SpatrickLC_SYMSEG = 0x00000003 67061da546SpatrickLC_THREAD = 0x00000004 68061da546SpatrickLC_UNIXTHREAD = 0x00000005 69061da546SpatrickLC_LOADFVMLIB = 0x00000006 70061da546SpatrickLC_IDFVMLIB = 0x00000007 71061da546SpatrickLC_IDENT = 0x00000008 72061da546SpatrickLC_FVMFILE = 0x00000009 73061da546SpatrickLC_PREPAGE = 0x0000000a 74061da546SpatrickLC_DYSYMTAB = 0x0000000b 75061da546SpatrickLC_LOAD_DYLIB = 0x0000000c 76061da546SpatrickLC_ID_DYLIB = 0x0000000d 77061da546SpatrickLC_LOAD_DYLINKER = 0x0000000e 78061da546SpatrickLC_ID_DYLINKER = 0x0000000f 79061da546SpatrickLC_PREBOUND_DYLIB = 0x00000010 80061da546SpatrickLC_ROUTINES = 0x00000011 81061da546SpatrickLC_SUB_FRAMEWORK = 0x00000012 82061da546SpatrickLC_SUB_UMBRELLA = 0x00000013 83061da546SpatrickLC_SUB_CLIENT = 0x00000014 84061da546SpatrickLC_SUB_LIBRARY = 0x00000015 85061da546SpatrickLC_TWOLEVEL_HINTS = 0x00000016 86061da546SpatrickLC_PREBIND_CKSUM = 0x00000017 87061da546SpatrickLC_LOAD_WEAK_DYLIB = 0x00000018 | LC_REQ_DYLD 88061da546SpatrickLC_SEGMENT_64 = 0x00000019 89061da546SpatrickLC_ROUTINES_64 = 0x0000001a 90061da546SpatrickLC_UUID = 0x0000001b 91061da546SpatrickLC_RPATH = 0x0000001c | LC_REQ_DYLD 92061da546SpatrickLC_CODE_SIGNATURE = 0x0000001d 93061da546SpatrickLC_SEGMENT_SPLIT_INFO = 0x0000001e 94061da546SpatrickLC_REEXPORT_DYLIB = 0x0000001f | LC_REQ_DYLD 95061da546SpatrickLC_LAZY_LOAD_DYLIB = 0x00000020 96061da546SpatrickLC_ENCRYPTION_INFO = 0x00000021 97061da546SpatrickLC_DYLD_INFO = 0x00000022 98061da546SpatrickLC_DYLD_INFO_ONLY = 0x00000022 | LC_REQ_DYLD 99061da546SpatrickLC_LOAD_UPWARD_DYLIB = 0x00000023 | LC_REQ_DYLD 100061da546SpatrickLC_VERSION_MIN_MACOSX = 0x00000024 101061da546SpatrickLC_VERSION_MIN_IPHONEOS = 0x00000025 102061da546SpatrickLC_FUNCTION_STARTS = 0x00000026 103061da546SpatrickLC_DYLD_ENVIRONMENT = 0x00000027 104061da546Spatrick 105061da546Spatrick# Mach CPU constants 106061da546SpatrickCPU_ARCH_MASK = 0xff000000 107061da546SpatrickCPU_ARCH_ABI64 = 0x01000000 108061da546SpatrickCPU_TYPE_ANY = 0xffffffff 109061da546SpatrickCPU_TYPE_VAX = 1 110061da546SpatrickCPU_TYPE_MC680x0 = 6 111061da546SpatrickCPU_TYPE_I386 = 7 112061da546SpatrickCPU_TYPE_X86_64 = CPU_TYPE_I386 | CPU_ARCH_ABI64 113061da546SpatrickCPU_TYPE_MIPS = 8 114061da546SpatrickCPU_TYPE_MC98000 = 10 115061da546SpatrickCPU_TYPE_HPPA = 11 116061da546SpatrickCPU_TYPE_ARM = 12 117061da546SpatrickCPU_TYPE_MC88000 = 13 118061da546SpatrickCPU_TYPE_SPARC = 14 119061da546SpatrickCPU_TYPE_I860 = 15 120061da546SpatrickCPU_TYPE_ALPHA = 16 121061da546SpatrickCPU_TYPE_POWERPC = 18 122061da546SpatrickCPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64 123061da546Spatrick 124061da546Spatrick# VM protection constants 125061da546SpatrickVM_PROT_READ = 1 126061da546SpatrickVM_PROT_WRITE = 2 127061da546SpatrickVM_PROT_EXECUTE = 4 128061da546Spatrick 129061da546Spatrick# VM protection constants 130061da546SpatrickN_STAB = 0xe0 131061da546SpatrickN_PEXT = 0x10 132061da546SpatrickN_TYPE = 0x0e 133061da546SpatrickN_EXT = 0x01 134061da546Spatrick 135061da546Spatrick# Values for nlist N_TYPE bits of the "Mach.NList.type" field. 136061da546SpatrickN_UNDF = 0x0 137061da546SpatrickN_ABS = 0x2 138061da546SpatrickN_SECT = 0xe 139061da546SpatrickN_PBUD = 0xc 140061da546SpatrickN_INDR = 0xa 141061da546Spatrick 142061da546Spatrick# Section indexes for the "Mach.NList.sect_idx" fields 143061da546SpatrickNO_SECT = 0 144061da546SpatrickMAX_SECT = 255 145061da546Spatrick 146061da546Spatrick# Stab defines 147061da546SpatrickN_GSYM = 0x20 148061da546SpatrickN_FNAME = 0x22 149061da546SpatrickN_FUN = 0x24 150061da546SpatrickN_STSYM = 0x26 151061da546SpatrickN_LCSYM = 0x28 152061da546SpatrickN_BNSYM = 0x2e 153061da546SpatrickN_OPT = 0x3c 154061da546SpatrickN_RSYM = 0x40 155061da546SpatrickN_SLINE = 0x44 156061da546SpatrickN_ENSYM = 0x4e 157061da546SpatrickN_SSYM = 0x60 158061da546SpatrickN_SO = 0x64 159061da546SpatrickN_OSO = 0x66 160061da546SpatrickN_LSYM = 0x80 161061da546SpatrickN_BINCL = 0x82 162061da546SpatrickN_SOL = 0x84 163061da546SpatrickN_PARAMS = 0x86 164061da546SpatrickN_VERSION = 0x88 165061da546SpatrickN_OLEVEL = 0x8A 166061da546SpatrickN_PSYM = 0xa0 167061da546SpatrickN_EINCL = 0xa2 168061da546SpatrickN_ENTRY = 0xa4 169061da546SpatrickN_LBRAC = 0xc0 170061da546SpatrickN_EXCL = 0xc2 171061da546SpatrickN_RBRAC = 0xe0 172061da546SpatrickN_BCOMM = 0xe2 173061da546SpatrickN_ECOMM = 0xe4 174061da546SpatrickN_ECOML = 0xe8 175061da546SpatrickN_LENG = 0xfe 176061da546Spatrick 177061da546Spatrickvm_prot_names = ['---', 'r--', '-w-', 'rw-', '--x', 'r-x', '-wx', 'rwx'] 178061da546Spatrick 179061da546Spatrick 180061da546Spatrickdef dump_memory(base_addr, data, hex_bytes_len, num_per_line): 181061da546Spatrick hex_bytes = data.encode('hex') 182061da546Spatrick if hex_bytes_len == -1: 183061da546Spatrick hex_bytes_len = len(hex_bytes) 184061da546Spatrick addr = base_addr 185061da546Spatrick ascii_str = '' 186061da546Spatrick i = 0 187061da546Spatrick while i < hex_bytes_len: 188061da546Spatrick if ((i / 2) % num_per_line) == 0: 189061da546Spatrick if i > 0: 190061da546Spatrick print(' %s' % (ascii_str)) 191061da546Spatrick ascii_str = '' 192061da546Spatrick print('0x%8.8x:' % (addr + i), end=' ') 193061da546Spatrick hex_byte = hex_bytes[i:i + 2] 194061da546Spatrick print(hex_byte, end=' ') 195061da546Spatrick int_byte = int(hex_byte, 16) 196061da546Spatrick ascii_char = '%c' % (int_byte) 197061da546Spatrick if int_byte >= 32 and int_byte < 127: 198061da546Spatrick ascii_str += ascii_char 199061da546Spatrick else: 200061da546Spatrick ascii_str += '.' 201061da546Spatrick i = i + 2 202061da546Spatrick if ascii_str: 203061da546Spatrick if (i / 2) % num_per_line: 204061da546Spatrick padding = num_per_line - ((i / 2) % num_per_line) 205061da546Spatrick else: 206061da546Spatrick padding = 0 207061da546Spatrick print('%*s%s' % (padding * 3 + 1, '', ascii_str)) 208061da546Spatrick print() 209061da546Spatrick 210061da546Spatrick 211061da546Spatrickclass TerminalColors: 212061da546Spatrick '''Simple terminal colors class''' 213061da546Spatrick 214061da546Spatrick def __init__(self, enabled=True): 215061da546Spatrick # TODO: discover terminal type from "file" and disable if 216061da546Spatrick # it can't handle the color codes 217061da546Spatrick self.enabled = enabled 218061da546Spatrick 219061da546Spatrick def reset(self): 220061da546Spatrick '''Reset all terminal colors and formatting.''' 221061da546Spatrick if self.enabled: 222061da546Spatrick return "\x1b[0m" 223061da546Spatrick return '' 224061da546Spatrick 225061da546Spatrick def bold(self, on=True): 226061da546Spatrick '''Enable or disable bold depending on the "on" parameter.''' 227061da546Spatrick if self.enabled: 228061da546Spatrick if on: 229061da546Spatrick return "\x1b[1m" 230061da546Spatrick else: 231061da546Spatrick return "\x1b[22m" 232061da546Spatrick return '' 233061da546Spatrick 234061da546Spatrick def italics(self, on=True): 235061da546Spatrick '''Enable or disable italics depending on the "on" parameter.''' 236061da546Spatrick if self.enabled: 237061da546Spatrick if on: 238061da546Spatrick return "\x1b[3m" 239061da546Spatrick else: 240061da546Spatrick return "\x1b[23m" 241061da546Spatrick return '' 242061da546Spatrick 243061da546Spatrick def underline(self, on=True): 244061da546Spatrick '''Enable or disable underline depending on the "on" parameter.''' 245061da546Spatrick if self.enabled: 246061da546Spatrick if on: 247061da546Spatrick return "\x1b[4m" 248061da546Spatrick else: 249061da546Spatrick return "\x1b[24m" 250061da546Spatrick return '' 251061da546Spatrick 252061da546Spatrick def inverse(self, on=True): 253061da546Spatrick '''Enable or disable inverse depending on the "on" parameter.''' 254061da546Spatrick if self.enabled: 255061da546Spatrick if on: 256061da546Spatrick return "\x1b[7m" 257061da546Spatrick else: 258061da546Spatrick return "\x1b[27m" 259061da546Spatrick return '' 260061da546Spatrick 261061da546Spatrick def strike(self, on=True): 262061da546Spatrick '''Enable or disable strike through depending on the "on" parameter.''' 263061da546Spatrick if self.enabled: 264061da546Spatrick if on: 265061da546Spatrick return "\x1b[9m" 266061da546Spatrick else: 267061da546Spatrick return "\x1b[29m" 268061da546Spatrick return '' 269061da546Spatrick 270061da546Spatrick def black(self, fg=True): 271061da546Spatrick '''Set the foreground or background color to black. 272061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 273061da546Spatrick if self.enabled: 274061da546Spatrick if fg: 275061da546Spatrick return "\x1b[30m" 276061da546Spatrick else: 277061da546Spatrick return "\x1b[40m" 278061da546Spatrick return '' 279061da546Spatrick 280061da546Spatrick def red(self, fg=True): 281061da546Spatrick '''Set the foreground or background color to red. 282061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 283061da546Spatrick if self.enabled: 284061da546Spatrick if fg: 285061da546Spatrick return "\x1b[31m" 286061da546Spatrick else: 287061da546Spatrick return "\x1b[41m" 288061da546Spatrick return '' 289061da546Spatrick 290061da546Spatrick def green(self, fg=True): 291061da546Spatrick '''Set the foreground or background color to green. 292061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 293061da546Spatrick if self.enabled: 294061da546Spatrick if fg: 295061da546Spatrick return "\x1b[32m" 296061da546Spatrick else: 297061da546Spatrick return "\x1b[42m" 298061da546Spatrick return '' 299061da546Spatrick 300061da546Spatrick def yellow(self, fg=True): 301061da546Spatrick '''Set the foreground or background color to yellow. 302061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 303061da546Spatrick if self.enabled: 304061da546Spatrick if fg: 305061da546Spatrick return "\x1b[43m" 306061da546Spatrick else: 307061da546Spatrick return "\x1b[33m" 308061da546Spatrick return '' 309061da546Spatrick 310061da546Spatrick def blue(self, fg=True): 311061da546Spatrick '''Set the foreground or background color to blue. 312061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 313061da546Spatrick if self.enabled: 314061da546Spatrick if fg: 315061da546Spatrick return "\x1b[34m" 316061da546Spatrick else: 317061da546Spatrick return "\x1b[44m" 318061da546Spatrick return '' 319061da546Spatrick 320061da546Spatrick def magenta(self, fg=True): 321061da546Spatrick '''Set the foreground or background color to magenta. 322061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 323061da546Spatrick if self.enabled: 324061da546Spatrick if fg: 325061da546Spatrick return "\x1b[35m" 326061da546Spatrick else: 327061da546Spatrick return "\x1b[45m" 328061da546Spatrick return '' 329061da546Spatrick 330061da546Spatrick def cyan(self, fg=True): 331061da546Spatrick '''Set the foreground or background color to cyan. 332061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 333061da546Spatrick if self.enabled: 334061da546Spatrick if fg: 335061da546Spatrick return "\x1b[36m" 336061da546Spatrick else: 337061da546Spatrick return "\x1b[46m" 338061da546Spatrick return '' 339061da546Spatrick 340061da546Spatrick def white(self, fg=True): 341061da546Spatrick '''Set the foreground or background color to white. 342061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 343061da546Spatrick if self.enabled: 344061da546Spatrick if fg: 345061da546Spatrick return "\x1b[37m" 346061da546Spatrick else: 347061da546Spatrick return "\x1b[47m" 348061da546Spatrick return '' 349061da546Spatrick 350061da546Spatrick def default(self, fg=True): 351061da546Spatrick '''Set the foreground or background color to the default. 352061da546Spatrick The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.''' 353061da546Spatrick if self.enabled: 354061da546Spatrick if fg: 355061da546Spatrick return "\x1b[39m" 356061da546Spatrick else: 357061da546Spatrick return "\x1b[49m" 358061da546Spatrick return '' 359061da546Spatrick 360061da546Spatrick 361061da546Spatrickdef swap_unpack_char(): 362061da546Spatrick """Returns the unpack prefix that will for non-native endian-ness.""" 363061da546Spatrick if struct.pack('H', 1).startswith("\x00"): 364061da546Spatrick return '<' 365061da546Spatrick return '>' 366061da546Spatrick 367061da546Spatrick 368061da546Spatrickdef dump_hex_bytes(addr, s, bytes_per_line=16): 369061da546Spatrick i = 0 370061da546Spatrick line = '' 371061da546Spatrick for ch in s: 372061da546Spatrick if (i % bytes_per_line) == 0: 373061da546Spatrick if line: 374061da546Spatrick print(line) 375061da546Spatrick line = '%#8.8x: ' % (addr + i) 376061da546Spatrick line += "%02X " % ord(ch) 377061da546Spatrick i += 1 378061da546Spatrick print(line) 379061da546Spatrick 380061da546Spatrick 381061da546Spatrickdef dump_hex_byte_string_diff(addr, a, b, bytes_per_line=16): 382061da546Spatrick i = 0 383061da546Spatrick line = '' 384061da546Spatrick a_len = len(a) 385061da546Spatrick b_len = len(b) 386061da546Spatrick if a_len < b_len: 387061da546Spatrick max_len = b_len 388061da546Spatrick else: 389061da546Spatrick max_len = a_len 390061da546Spatrick tty_colors = TerminalColors(True) 391061da546Spatrick for i in range(max_len): 392061da546Spatrick ch = None 393061da546Spatrick if i < a_len: 394061da546Spatrick ch_a = a[i] 395061da546Spatrick ch = ch_a 396061da546Spatrick else: 397061da546Spatrick ch_a = None 398061da546Spatrick if i < b_len: 399061da546Spatrick ch_b = b[i] 400061da546Spatrick if not ch: 401061da546Spatrick ch = ch_b 402061da546Spatrick else: 403061da546Spatrick ch_b = None 404061da546Spatrick mismatch = ch_a != ch_b 405061da546Spatrick if (i % bytes_per_line) == 0: 406061da546Spatrick if line: 407061da546Spatrick print(line) 408061da546Spatrick line = '%#8.8x: ' % (addr + i) 409061da546Spatrick if mismatch: 410061da546Spatrick line += tty_colors.red() 411061da546Spatrick line += "%02X " % ord(ch) 412061da546Spatrick if mismatch: 413061da546Spatrick line += tty_colors.default() 414061da546Spatrick i += 1 415061da546Spatrick 416061da546Spatrick print(line) 417061da546Spatrick 418061da546Spatrick 419061da546Spatrickclass Mach: 420061da546Spatrick """Class that does everything mach-o related""" 421061da546Spatrick 422061da546Spatrick class Arch: 423061da546Spatrick """Class that implements mach-o architectures""" 424061da546Spatrick 425061da546Spatrick def __init__(self, c=0, s=0): 426061da546Spatrick self.cpu = c 427061da546Spatrick self.sub = s 428061da546Spatrick 429061da546Spatrick def set_cpu_type(self, c): 430061da546Spatrick self.cpu = c 431061da546Spatrick 432061da546Spatrick def set_cpu_subtype(self, s): 433061da546Spatrick self.sub = s 434061da546Spatrick 435061da546Spatrick def set_arch(self, c, s): 436061da546Spatrick self.cpu = c 437061da546Spatrick self.sub = s 438061da546Spatrick 439061da546Spatrick def is_64_bit(self): 440061da546Spatrick return (self.cpu & CPU_ARCH_ABI64) != 0 441061da546Spatrick 442061da546Spatrick cpu_infos = [ 443061da546Spatrick ["arm", CPU_TYPE_ARM, CPU_TYPE_ANY], 444061da546Spatrick ["arm", CPU_TYPE_ARM, 0], 445061da546Spatrick ["armv4", CPU_TYPE_ARM, 5], 446061da546Spatrick ["armv6", CPU_TYPE_ARM, 6], 447061da546Spatrick ["armv5", CPU_TYPE_ARM, 7], 448061da546Spatrick ["xscale", CPU_TYPE_ARM, 8], 449061da546Spatrick ["armv7", CPU_TYPE_ARM, 9], 450061da546Spatrick ["armv7f", CPU_TYPE_ARM, 10], 451061da546Spatrick ["armv7s", CPU_TYPE_ARM, 11], 452061da546Spatrick ["armv7k", CPU_TYPE_ARM, 12], 453061da546Spatrick ["armv7m", CPU_TYPE_ARM, 15], 454061da546Spatrick ["armv7em", CPU_TYPE_ARM, 16], 455061da546Spatrick ["ppc", CPU_TYPE_POWERPC, CPU_TYPE_ANY], 456061da546Spatrick ["ppc", CPU_TYPE_POWERPC, 0], 457061da546Spatrick ["ppc601", CPU_TYPE_POWERPC, 1], 458061da546Spatrick ["ppc602", CPU_TYPE_POWERPC, 2], 459061da546Spatrick ["ppc603", CPU_TYPE_POWERPC, 3], 460061da546Spatrick ["ppc603e", CPU_TYPE_POWERPC, 4], 461061da546Spatrick ["ppc603ev", CPU_TYPE_POWERPC, 5], 462061da546Spatrick ["ppc604", CPU_TYPE_POWERPC, 6], 463061da546Spatrick ["ppc604e", CPU_TYPE_POWERPC, 7], 464061da546Spatrick ["ppc620", CPU_TYPE_POWERPC, 8], 465061da546Spatrick ["ppc750", CPU_TYPE_POWERPC, 9], 466061da546Spatrick ["ppc7400", CPU_TYPE_POWERPC, 10], 467061da546Spatrick ["ppc7450", CPU_TYPE_POWERPC, 11], 468061da546Spatrick ["ppc970", CPU_TYPE_POWERPC, 100], 469061da546Spatrick ["ppc64", CPU_TYPE_POWERPC64, 0], 470061da546Spatrick ["ppc970-64", CPU_TYPE_POWERPC64, 100], 471061da546Spatrick ["i386", CPU_TYPE_I386, 3], 472061da546Spatrick ["i486", CPU_TYPE_I386, 4], 473061da546Spatrick ["i486sx", CPU_TYPE_I386, 0x84], 474061da546Spatrick ["i386", CPU_TYPE_I386, CPU_TYPE_ANY], 475061da546Spatrick ["x86_64", CPU_TYPE_X86_64, 3], 476061da546Spatrick ["x86_64", CPU_TYPE_X86_64, CPU_TYPE_ANY], 477061da546Spatrick ] 478061da546Spatrick 479061da546Spatrick def __str__(self): 480061da546Spatrick for info in self.cpu_infos: 481061da546Spatrick if self.cpu == info[1] and (self.sub & 0x00ffffff) == info[2]: 482061da546Spatrick return info[0] 483061da546Spatrick return "{0}.{1}".format(self.cpu, self.sub) 484061da546Spatrick 485061da546Spatrick class Magic(dict_utils.Enum): 486061da546Spatrick 487061da546Spatrick enum = { 488061da546Spatrick 'MH_MAGIC': MH_MAGIC, 489061da546Spatrick 'MH_CIGAM': MH_CIGAM, 490061da546Spatrick 'MH_MAGIC_64': MH_MAGIC_64, 491061da546Spatrick 'MH_CIGAM_64': MH_CIGAM_64, 492061da546Spatrick 'FAT_MAGIC': FAT_MAGIC, 493061da546Spatrick 'FAT_CIGAM': FAT_CIGAM 494061da546Spatrick } 495061da546Spatrick 496061da546Spatrick def __init__(self, initial_value=0): 497061da546Spatrick dict_utils.Enum.__init__(self, initial_value, self.enum) 498061da546Spatrick 499061da546Spatrick def is_skinny_mach_file(self): 500061da546Spatrick return self.value == MH_MAGIC or self.value == MH_CIGAM or self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64 501061da546Spatrick 502061da546Spatrick def is_universal_mach_file(self): 503061da546Spatrick return self.value == FAT_MAGIC or self.value == FAT_CIGAM 504061da546Spatrick 505061da546Spatrick def unpack(self, data): 506061da546Spatrick data.set_byte_order('native') 507061da546Spatrick self.value = data.get_uint32() 508061da546Spatrick 509061da546Spatrick def get_byte_order(self): 510061da546Spatrick if self.value == MH_CIGAM or self.value == MH_CIGAM_64 or self.value == FAT_CIGAM: 511061da546Spatrick return swap_unpack_char() 512061da546Spatrick else: 513061da546Spatrick return '=' 514061da546Spatrick 515061da546Spatrick def is_64_bit(self): 516061da546Spatrick return self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64 517061da546Spatrick 518061da546Spatrick def __init__(self): 519061da546Spatrick self.magic = Mach.Magic() 520061da546Spatrick self.content = None 521061da546Spatrick self.path = None 522061da546Spatrick 523061da546Spatrick def extract(self, path, extractor): 524061da546Spatrick self.path = path 525061da546Spatrick self.unpack(extractor) 526061da546Spatrick 527061da546Spatrick def parse(self, path): 528061da546Spatrick self.path = path 529061da546Spatrick try: 530061da546Spatrick f = open(self.path) 531061da546Spatrick file_extractor = file_extract.FileExtract(f, '=') 532061da546Spatrick self.unpack(file_extractor) 533061da546Spatrick # f.close() 534061da546Spatrick except IOError as xxx_todo_changeme: 535061da546Spatrick (errno, strerror) = xxx_todo_changeme.args 536061da546Spatrick print("I/O error({0}): {1}".format(errno, strerror)) 537061da546Spatrick except ValueError: 538061da546Spatrick print("Could not convert data to an integer.") 539061da546Spatrick except: 540061da546Spatrick print("Unexpected error:", sys.exc_info()[0]) 541061da546Spatrick raise 542061da546Spatrick 543061da546Spatrick def compare(self, rhs): 544061da546Spatrick self.content.compare(rhs.content) 545061da546Spatrick 546061da546Spatrick def dump(self, options=None): 547061da546Spatrick self.content.dump(options) 548061da546Spatrick 549061da546Spatrick def dump_header(self, dump_description=True, options=None): 550061da546Spatrick self.content.dump_header(dump_description, options) 551061da546Spatrick 552061da546Spatrick def dump_load_commands(self, dump_description=True, options=None): 553061da546Spatrick self.content.dump_load_commands(dump_description, options) 554061da546Spatrick 555061da546Spatrick def dump_sections(self, dump_description=True, options=None): 556061da546Spatrick self.content.dump_sections(dump_description, options) 557061da546Spatrick 558061da546Spatrick def dump_section_contents(self, options): 559061da546Spatrick self.content.dump_section_contents(options) 560061da546Spatrick 561061da546Spatrick def dump_symtab(self, dump_description=True, options=None): 562061da546Spatrick self.content.dump_symtab(dump_description, options) 563061da546Spatrick 564061da546Spatrick def dump_symbol_names_matching_regex(self, regex, file=None): 565061da546Spatrick self.content.dump_symbol_names_matching_regex(regex, file) 566061da546Spatrick 567061da546Spatrick def description(self): 568061da546Spatrick return self.content.description() 569061da546Spatrick 570061da546Spatrick def unpack(self, data): 571061da546Spatrick self.magic.unpack(data) 572061da546Spatrick if self.magic.is_skinny_mach_file(): 573061da546Spatrick self.content = Mach.Skinny(self.path) 574061da546Spatrick elif self.magic.is_universal_mach_file(): 575061da546Spatrick self.content = Mach.Universal(self.path) 576061da546Spatrick else: 577061da546Spatrick self.content = None 578061da546Spatrick 579061da546Spatrick if self.content is not None: 580061da546Spatrick self.content.unpack(data, self.magic) 581061da546Spatrick 582061da546Spatrick def is_valid(self): 583061da546Spatrick return self.content is not None 584061da546Spatrick 585061da546Spatrick class Universal: 586061da546Spatrick 587061da546Spatrick def __init__(self, path): 588061da546Spatrick self.path = path 589061da546Spatrick self.type = 'universal' 590061da546Spatrick self.file_off = 0 591061da546Spatrick self.magic = None 592061da546Spatrick self.nfat_arch = 0 593061da546Spatrick self.archs = list() 594061da546Spatrick 595061da546Spatrick def description(self): 596061da546Spatrick s = '%#8.8x: %s (' % (self.file_off, self.path) 597061da546Spatrick archs_string = '' 598061da546Spatrick for arch in self.archs: 599061da546Spatrick if len(archs_string): 600061da546Spatrick archs_string += ', ' 601061da546Spatrick archs_string += '%s' % arch.arch 602061da546Spatrick s += archs_string 603061da546Spatrick s += ')' 604061da546Spatrick return s 605061da546Spatrick 606061da546Spatrick def unpack(self, data, magic=None): 607061da546Spatrick self.file_off = data.tell() 608061da546Spatrick if magic is None: 609061da546Spatrick self.magic = Mach.Magic() 610061da546Spatrick self.magic.unpack(data) 611061da546Spatrick else: 612061da546Spatrick self.magic = magic 613061da546Spatrick self.file_off = self.file_off - 4 614061da546Spatrick # Universal headers are always in big endian 615061da546Spatrick data.set_byte_order('big') 616061da546Spatrick self.nfat_arch = data.get_uint32() 617061da546Spatrick for i in range(self.nfat_arch): 618061da546Spatrick self.archs.append(Mach.Universal.ArchInfo()) 619061da546Spatrick self.archs[i].unpack(data) 620061da546Spatrick for i in range(self.nfat_arch): 621061da546Spatrick self.archs[i].mach = Mach.Skinny(self.path) 622061da546Spatrick data.seek(self.archs[i].offset, 0) 623061da546Spatrick skinny_magic = Mach.Magic() 624061da546Spatrick skinny_magic.unpack(data) 625061da546Spatrick self.archs[i].mach.unpack(data, skinny_magic) 626061da546Spatrick 627061da546Spatrick def compare(self, rhs): 628061da546Spatrick print('error: comparing two universal files is not supported yet') 629061da546Spatrick return False 630061da546Spatrick 631061da546Spatrick def dump(self, options): 632061da546Spatrick if options.dump_header: 633061da546Spatrick print() 634061da546Spatrick print("Universal Mach File: magic = %s, nfat_arch = %u" % (self.magic, self.nfat_arch)) 635061da546Spatrick print() 636061da546Spatrick if self.nfat_arch > 0: 637061da546Spatrick if options.dump_header: 638061da546Spatrick self.archs[0].dump_header(True, options) 639061da546Spatrick for i in range(self.nfat_arch): 640061da546Spatrick self.archs[i].dump_flat(options) 641061da546Spatrick if options.dump_header: 642061da546Spatrick print() 643061da546Spatrick for i in range(self.nfat_arch): 644061da546Spatrick self.archs[i].mach.dump(options) 645061da546Spatrick 646061da546Spatrick def dump_header(self, dump_description=True, options=None): 647061da546Spatrick if dump_description: 648061da546Spatrick print(self.description()) 649061da546Spatrick for i in range(self.nfat_arch): 650061da546Spatrick self.archs[i].mach.dump_header(True, options) 651061da546Spatrick print() 652061da546Spatrick 653061da546Spatrick def dump_load_commands(self, dump_description=True, options=None): 654061da546Spatrick if dump_description: 655061da546Spatrick print(self.description()) 656061da546Spatrick for i in range(self.nfat_arch): 657061da546Spatrick self.archs[i].mach.dump_load_commands(True, options) 658061da546Spatrick print() 659061da546Spatrick 660061da546Spatrick def dump_sections(self, dump_description=True, options=None): 661061da546Spatrick if dump_description: 662061da546Spatrick print(self.description()) 663061da546Spatrick for i in range(self.nfat_arch): 664061da546Spatrick self.archs[i].mach.dump_sections(True, options) 665061da546Spatrick print() 666061da546Spatrick 667061da546Spatrick def dump_section_contents(self, options): 668061da546Spatrick for i in range(self.nfat_arch): 669061da546Spatrick self.archs[i].mach.dump_section_contents(options) 670061da546Spatrick print() 671061da546Spatrick 672061da546Spatrick def dump_symtab(self, dump_description=True, options=None): 673061da546Spatrick if dump_description: 674061da546Spatrick print(self.description()) 675061da546Spatrick for i in range(self.nfat_arch): 676061da546Spatrick self.archs[i].mach.dump_symtab(True, options) 677061da546Spatrick print() 678061da546Spatrick 679061da546Spatrick def dump_symbol_names_matching_regex(self, regex, file=None): 680061da546Spatrick for i in range(self.nfat_arch): 681061da546Spatrick self.archs[i].mach.dump_symbol_names_matching_regex( 682061da546Spatrick regex, file) 683061da546Spatrick 684061da546Spatrick class ArchInfo: 685061da546Spatrick 686061da546Spatrick def __init__(self): 687061da546Spatrick self.arch = Mach.Arch(0, 0) 688061da546Spatrick self.offset = 0 689061da546Spatrick self.size = 0 690061da546Spatrick self.align = 0 691061da546Spatrick self.mach = None 692061da546Spatrick 693061da546Spatrick def unpack(self, data): 694061da546Spatrick # Universal headers are always in big endian 695061da546Spatrick data.set_byte_order('big') 696061da546Spatrick self.arch.cpu, self.arch.sub, self.offset, self.size, self.align = data.get_n_uint32( 697061da546Spatrick 5) 698061da546Spatrick 699061da546Spatrick def dump_header(self, dump_description=True, options=None): 700061da546Spatrick if options.verbose: 701061da546Spatrick print("CPU SUBTYPE OFFSET SIZE ALIGN") 702061da546Spatrick print("---------- ---------- ---------- ---------- ----------") 703061da546Spatrick else: 704061da546Spatrick print("ARCH FILEOFFSET FILESIZE ALIGN") 705061da546Spatrick print("---------- ---------- ---------- ----------") 706061da546Spatrick 707061da546Spatrick def dump_flat(self, options): 708061da546Spatrick if options.verbose: 709061da546Spatrick print("%#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)) 710061da546Spatrick else: 711061da546Spatrick print("%-10s %#8.8x %#8.8x %#8.8x" % (self.arch, self.offset, self.size, self.align)) 712061da546Spatrick 713061da546Spatrick def dump(self): 714061da546Spatrick print(" cputype: %#8.8x" % self.arch.cpu) 715061da546Spatrick print("cpusubtype: %#8.8x" % self.arch.sub) 716061da546Spatrick print(" offset: %#8.8x" % self.offset) 717061da546Spatrick print(" size: %#8.8x" % self.size) 718061da546Spatrick print(" align: %#8.8x" % self.align) 719061da546Spatrick 720061da546Spatrick def __str__(self): 721061da546Spatrick return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % ( 722061da546Spatrick self.arch.cpu, self.arch.sub, self.offset, self.size, self.align) 723061da546Spatrick 724061da546Spatrick def __repr__(self): 725061da546Spatrick return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % ( 726061da546Spatrick self.arch.cpu, self.arch.sub, self.offset, self.size, self.align) 727061da546Spatrick 728061da546Spatrick class Flags: 729061da546Spatrick 730061da546Spatrick def __init__(self, b): 731061da546Spatrick self.bits = b 732061da546Spatrick 733061da546Spatrick def __str__(self): 734061da546Spatrick s = '' 735061da546Spatrick if self.bits & MH_NOUNDEFS: 736061da546Spatrick s += 'MH_NOUNDEFS | ' 737061da546Spatrick if self.bits & MH_INCRLINK: 738061da546Spatrick s += 'MH_INCRLINK | ' 739061da546Spatrick if self.bits & MH_DYLDLINK: 740061da546Spatrick s += 'MH_DYLDLINK | ' 741061da546Spatrick if self.bits & MH_BINDATLOAD: 742061da546Spatrick s += 'MH_BINDATLOAD | ' 743061da546Spatrick if self.bits & MH_PREBOUND: 744061da546Spatrick s += 'MH_PREBOUND | ' 745061da546Spatrick if self.bits & MH_SPLIT_SEGS: 746061da546Spatrick s += 'MH_SPLIT_SEGS | ' 747061da546Spatrick if self.bits & MH_LAZY_INIT: 748061da546Spatrick s += 'MH_LAZY_INIT | ' 749061da546Spatrick if self.bits & MH_TWOLEVEL: 750061da546Spatrick s += 'MH_TWOLEVEL | ' 751061da546Spatrick if self.bits & MH_FORCE_FLAT: 752061da546Spatrick s += 'MH_FORCE_FLAT | ' 753061da546Spatrick if self.bits & MH_NOMULTIDEFS: 754061da546Spatrick s += 'MH_NOMULTIDEFS | ' 755061da546Spatrick if self.bits & MH_NOFIXPREBINDING: 756061da546Spatrick s += 'MH_NOFIXPREBINDING | ' 757061da546Spatrick if self.bits & MH_PREBINDABLE: 758061da546Spatrick s += 'MH_PREBINDABLE | ' 759061da546Spatrick if self.bits & MH_ALLMODSBOUND: 760061da546Spatrick s += 'MH_ALLMODSBOUND | ' 761061da546Spatrick if self.bits & MH_SUBSECTIONS_VIA_SYMBOLS: 762061da546Spatrick s += 'MH_SUBSECTIONS_VIA_SYMBOLS | ' 763061da546Spatrick if self.bits & MH_CANONICAL: 764061da546Spatrick s += 'MH_CANONICAL | ' 765061da546Spatrick if self.bits & MH_WEAK_DEFINES: 766061da546Spatrick s += 'MH_WEAK_DEFINES | ' 767061da546Spatrick if self.bits & MH_BINDS_TO_WEAK: 768061da546Spatrick s += 'MH_BINDS_TO_WEAK | ' 769061da546Spatrick if self.bits & MH_ALLOW_STACK_EXECUTION: 770061da546Spatrick s += 'MH_ALLOW_STACK_EXECUTION | ' 771061da546Spatrick if self.bits & MH_ROOT_SAFE: 772061da546Spatrick s += 'MH_ROOT_SAFE | ' 773061da546Spatrick if self.bits & MH_SETUID_SAFE: 774061da546Spatrick s += 'MH_SETUID_SAFE | ' 775061da546Spatrick if self.bits & MH_NO_REEXPORTED_DYLIBS: 776061da546Spatrick s += 'MH_NO_REEXPORTED_DYLIBS | ' 777061da546Spatrick if self.bits & MH_PIE: 778061da546Spatrick s += 'MH_PIE | ' 779061da546Spatrick if self.bits & MH_DEAD_STRIPPABLE_DYLIB: 780061da546Spatrick s += 'MH_DEAD_STRIPPABLE_DYLIB | ' 781061da546Spatrick if self.bits & MH_HAS_TLV_DESCRIPTORS: 782061da546Spatrick s += 'MH_HAS_TLV_DESCRIPTORS | ' 783061da546Spatrick if self.bits & MH_NO_HEAP_EXECUTION: 784061da546Spatrick s += 'MH_NO_HEAP_EXECUTION | ' 785061da546Spatrick # Strip the trailing " |" if we have any flags 786061da546Spatrick if len(s) > 0: 787061da546Spatrick s = s[0:-2] 788061da546Spatrick return s 789061da546Spatrick 790061da546Spatrick class FileType(dict_utils.Enum): 791061da546Spatrick 792061da546Spatrick enum = { 793061da546Spatrick 'MH_OBJECT': MH_OBJECT, 794061da546Spatrick 'MH_EXECUTE': MH_EXECUTE, 795061da546Spatrick 'MH_FVMLIB': MH_FVMLIB, 796061da546Spatrick 'MH_CORE': MH_CORE, 797061da546Spatrick 'MH_PRELOAD': MH_PRELOAD, 798061da546Spatrick 'MH_DYLIB': MH_DYLIB, 799061da546Spatrick 'MH_DYLINKER': MH_DYLINKER, 800061da546Spatrick 'MH_BUNDLE': MH_BUNDLE, 801061da546Spatrick 'MH_DYLIB_STUB': MH_DYLIB_STUB, 802061da546Spatrick 'MH_DSYM': MH_DSYM, 803061da546Spatrick 'MH_KEXT_BUNDLE': MH_KEXT_BUNDLE 804061da546Spatrick } 805061da546Spatrick 806061da546Spatrick def __init__(self, initial_value=0): 807061da546Spatrick dict_utils.Enum.__init__(self, initial_value, self.enum) 808061da546Spatrick 809061da546Spatrick class Skinny: 810061da546Spatrick 811061da546Spatrick def __init__(self, path): 812061da546Spatrick self.path = path 813061da546Spatrick self.type = 'skinny' 814061da546Spatrick self.data = None 815061da546Spatrick self.file_off = 0 816061da546Spatrick self.magic = 0 817061da546Spatrick self.arch = Mach.Arch(0, 0) 818061da546Spatrick self.filetype = Mach.FileType(0) 819061da546Spatrick self.ncmds = 0 820061da546Spatrick self.sizeofcmds = 0 821061da546Spatrick self.flags = Mach.Flags(0) 822061da546Spatrick self.uuid = None 823061da546Spatrick self.commands = list() 824061da546Spatrick self.segments = list() 825061da546Spatrick self.sections = list() 826061da546Spatrick self.symbols = list() 827061da546Spatrick self.sections.append(Mach.Section()) 828061da546Spatrick 829061da546Spatrick def description(self): 830061da546Spatrick return '%#8.8x: %s (%s)' % (self.file_off, self.path, self.arch) 831061da546Spatrick 832061da546Spatrick def unpack(self, data, magic=None): 833061da546Spatrick self.data = data 834061da546Spatrick self.file_off = data.tell() 835061da546Spatrick if magic is None: 836061da546Spatrick self.magic = Mach.Magic() 837061da546Spatrick self.magic.unpack(data) 838061da546Spatrick else: 839061da546Spatrick self.magic = magic 840061da546Spatrick self.file_off = self.file_off - 4 841061da546Spatrick data.set_byte_order(self.magic.get_byte_order()) 842061da546Spatrick self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, bits = data.get_n_uint32( 843061da546Spatrick 6) 844061da546Spatrick self.flags.bits = bits 845061da546Spatrick 846061da546Spatrick if self.is_64_bit(): 847061da546Spatrick data.get_uint32() # Skip reserved word in mach_header_64 848061da546Spatrick 849061da546Spatrick for i in range(0, self.ncmds): 850061da546Spatrick lc = self.unpack_load_command(data) 851061da546Spatrick self.commands.append(lc) 852061da546Spatrick 853061da546Spatrick def get_data(self): 854061da546Spatrick if self.data: 855061da546Spatrick self.data.set_byte_order(self.magic.get_byte_order()) 856061da546Spatrick return self.data 857061da546Spatrick return None 858061da546Spatrick 859061da546Spatrick def unpack_load_command(self, data): 860061da546Spatrick lc = Mach.LoadCommand() 861061da546Spatrick lc.unpack(self, data) 862061da546Spatrick lc_command = lc.command.get_enum_value() 863061da546Spatrick if (lc_command == LC_SEGMENT or 864061da546Spatrick lc_command == LC_SEGMENT_64): 865061da546Spatrick lc = Mach.SegmentLoadCommand(lc) 866061da546Spatrick lc.unpack(self, data) 867061da546Spatrick elif (lc_command == LC_LOAD_DYLIB or 868061da546Spatrick lc_command == LC_ID_DYLIB or 869061da546Spatrick lc_command == LC_LOAD_WEAK_DYLIB or 870061da546Spatrick lc_command == LC_REEXPORT_DYLIB): 871061da546Spatrick lc = Mach.DylibLoadCommand(lc) 872061da546Spatrick lc.unpack(self, data) 873061da546Spatrick elif (lc_command == LC_LOAD_DYLINKER or 874061da546Spatrick lc_command == LC_SUB_FRAMEWORK or 875061da546Spatrick lc_command == LC_SUB_CLIENT or 876061da546Spatrick lc_command == LC_SUB_UMBRELLA or 877061da546Spatrick lc_command == LC_SUB_LIBRARY or 878061da546Spatrick lc_command == LC_ID_DYLINKER or 879061da546Spatrick lc_command == LC_RPATH): 880061da546Spatrick lc = Mach.LoadDYLDLoadCommand(lc) 881061da546Spatrick lc.unpack(self, data) 882061da546Spatrick elif (lc_command == LC_DYLD_INFO_ONLY): 883061da546Spatrick lc = Mach.DYLDInfoOnlyLoadCommand(lc) 884061da546Spatrick lc.unpack(self, data) 885061da546Spatrick elif (lc_command == LC_SYMTAB): 886061da546Spatrick lc = Mach.SymtabLoadCommand(lc) 887061da546Spatrick lc.unpack(self, data) 888061da546Spatrick elif (lc_command == LC_DYSYMTAB): 889061da546Spatrick lc = Mach.DYLDSymtabLoadCommand(lc) 890061da546Spatrick lc.unpack(self, data) 891061da546Spatrick elif (lc_command == LC_UUID): 892061da546Spatrick lc = Mach.UUIDLoadCommand(lc) 893061da546Spatrick lc.unpack(self, data) 894061da546Spatrick elif (lc_command == LC_CODE_SIGNATURE or 895061da546Spatrick lc_command == LC_SEGMENT_SPLIT_INFO or 896061da546Spatrick lc_command == LC_FUNCTION_STARTS): 897061da546Spatrick lc = Mach.DataBlobLoadCommand(lc) 898061da546Spatrick lc.unpack(self, data) 899061da546Spatrick elif (lc_command == LC_UNIXTHREAD): 900061da546Spatrick lc = Mach.UnixThreadLoadCommand(lc) 901061da546Spatrick lc.unpack(self, data) 902061da546Spatrick elif (lc_command == LC_ENCRYPTION_INFO): 903061da546Spatrick lc = Mach.EncryptionInfoLoadCommand(lc) 904061da546Spatrick lc.unpack(self, data) 905061da546Spatrick lc.skip(data) 906061da546Spatrick return lc 907061da546Spatrick 908061da546Spatrick def compare(self, rhs): 909061da546Spatrick print("\nComparing:") 910061da546Spatrick print("a) %s %s" % (self.arch, self.path)) 911061da546Spatrick print("b) %s %s" % (rhs.arch, rhs.path)) 912061da546Spatrick result = True 913061da546Spatrick if self.type == rhs.type: 914061da546Spatrick for lhs_section in self.sections[1:]: 915061da546Spatrick rhs_section = rhs.get_section_by_section(lhs_section) 916061da546Spatrick if rhs_section: 917061da546Spatrick print('comparing %s.%s...' % (lhs_section.segname, lhs_section.sectname), end=' ') 918061da546Spatrick sys.stdout.flush() 919061da546Spatrick lhs_data = lhs_section.get_contents(self) 920061da546Spatrick rhs_data = rhs_section.get_contents(rhs) 921061da546Spatrick if lhs_data and rhs_data: 922061da546Spatrick if lhs_data == rhs_data: 923061da546Spatrick print('ok') 924061da546Spatrick else: 925061da546Spatrick lhs_data_len = len(lhs_data) 926061da546Spatrick rhs_data_len = len(rhs_data) 927061da546Spatrick # if lhs_data_len < rhs_data_len: 928061da546Spatrick # if lhs_data == rhs_data[0:lhs_data_len]: 929061da546Spatrick # print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len) 930061da546Spatrick # else: 931061da546Spatrick # # TODO: check padding 932061da546Spatrick # result = False 933061da546Spatrick # elif lhs_data_len > rhs_data_len: 934061da546Spatrick # if lhs_data[0:rhs_data_len] == rhs_data: 935061da546Spatrick # print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len) 936061da546Spatrick # else: 937061da546Spatrick # # TODO: check padding 938061da546Spatrick # result = False 939061da546Spatrick # else: 940061da546Spatrick result = False 941061da546Spatrick print('error: sections differ') 942061da546Spatrick # print 'a) %s' % (lhs_section) 943061da546Spatrick # dump_hex_byte_string_diff(0, lhs_data, rhs_data) 944061da546Spatrick # print 'b) %s' % (rhs_section) 945061da546Spatrick # dump_hex_byte_string_diff(0, rhs_data, lhs_data) 946061da546Spatrick elif lhs_data and not rhs_data: 947061da546Spatrick print('error: section data missing from b:') 948061da546Spatrick print('a) %s' % (lhs_section)) 949061da546Spatrick print('b) %s' % (rhs_section)) 950061da546Spatrick result = False 951061da546Spatrick elif not lhs_data and rhs_data: 952061da546Spatrick print('error: section data missing from a:') 953061da546Spatrick print('a) %s' % (lhs_section)) 954061da546Spatrick print('b) %s' % (rhs_section)) 955061da546Spatrick result = False 956061da546Spatrick elif lhs_section.offset or rhs_section.offset: 957061da546Spatrick print('error: section data missing for both a and b:') 958061da546Spatrick print('a) %s' % (lhs_section)) 959061da546Spatrick print('b) %s' % (rhs_section)) 960061da546Spatrick result = False 961061da546Spatrick else: 962061da546Spatrick print('ok') 963061da546Spatrick else: 964061da546Spatrick result = False 965061da546Spatrick print('error: section %s is missing in %s' % (lhs_section.sectname, rhs.path)) 966061da546Spatrick else: 967dda28197Spatrick print('error: comparing a %s mach-o file with a %s mach-o file is not supported' % (self.type, rhs.type)) 968061da546Spatrick result = False 969061da546Spatrick if not result: 970061da546Spatrick print('error: mach files differ') 971061da546Spatrick return result 972061da546Spatrick 973061da546Spatrick def dump_header(self, dump_description=True, options=None): 974061da546Spatrick if options.verbose: 975061da546Spatrick print("MAGIC CPU SUBTYPE FILETYPE NUM CMDS SIZE CMDS FLAGS") 976061da546Spatrick print("---------- ---------- ---------- ---------- -------- ---------- ----------") 977061da546Spatrick else: 978061da546Spatrick print("MAGIC ARCH FILETYPE NUM CMDS SIZE CMDS FLAGS") 979061da546Spatrick print("------------ ---------- -------------- -------- ---------- ----------") 980061da546Spatrick 981061da546Spatrick def dump_flat(self, options): 982061da546Spatrick if options.verbose: 983061da546Spatrick print("%#8.8x %#8.8x %#8.8x %#8.8x %#8u %#8.8x %#8.8x" % (self.magic, self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, self.flags.bits)) 984061da546Spatrick else: 985061da546Spatrick print("%-12s %-10s %-14s %#8u %#8.8x %s" % (self.magic, self.arch, self.filetype, self.ncmds, self.sizeofcmds, self.flags)) 986061da546Spatrick 987061da546Spatrick def dump(self, options): 988061da546Spatrick if options.dump_header: 989061da546Spatrick self.dump_header(True, options) 990061da546Spatrick if options.dump_load_commands: 991061da546Spatrick self.dump_load_commands(False, options) 992061da546Spatrick if options.dump_sections: 993061da546Spatrick self.dump_sections(False, options) 994061da546Spatrick if options.section_names: 995061da546Spatrick self.dump_section_contents(options) 996061da546Spatrick if options.dump_symtab: 997061da546Spatrick self.get_symtab() 998061da546Spatrick if len(self.symbols): 999061da546Spatrick self.dump_sections(False, options) 1000061da546Spatrick else: 1001061da546Spatrick print("No symbols") 1002061da546Spatrick if options.find_mangled: 1003061da546Spatrick self.dump_symbol_names_matching_regex(re.compile('^_?_Z')) 1004061da546Spatrick 1005061da546Spatrick def dump_header(self, dump_description=True, options=None): 1006061da546Spatrick if dump_description: 1007061da546Spatrick print(self.description()) 1008061da546Spatrick print("Mach Header") 1009061da546Spatrick print(" magic: %#8.8x %s" % (self.magic.value, self.magic)) 1010061da546Spatrick print(" cputype: %#8.8x %s" % (self.arch.cpu, self.arch)) 1011061da546Spatrick print(" cpusubtype: %#8.8x" % self.arch.sub) 1012061da546Spatrick print(" filetype: %#8.8x %s" % (self.filetype.get_enum_value(), self.filetype.get_enum_name())) 1013061da546Spatrick print(" ncmds: %#8.8x %u" % (self.ncmds, self.ncmds)) 1014061da546Spatrick print(" sizeofcmds: %#8.8x" % self.sizeofcmds) 1015061da546Spatrick print(" flags: %#8.8x %s" % (self.flags.bits, self.flags)) 1016061da546Spatrick 1017061da546Spatrick def dump_load_commands(self, dump_description=True, options=None): 1018061da546Spatrick if dump_description: 1019061da546Spatrick print(self.description()) 1020061da546Spatrick for lc in self.commands: 1021061da546Spatrick print(lc) 1022061da546Spatrick 1023061da546Spatrick def get_section_by_name(self, name): 1024061da546Spatrick for section in self.sections: 1025061da546Spatrick if section.sectname and section.sectname == name: 1026061da546Spatrick return section 1027061da546Spatrick return None 1028061da546Spatrick 1029061da546Spatrick def get_section_by_section(self, other_section): 1030061da546Spatrick for section in self.sections: 1031061da546Spatrick if section.sectname == other_section.sectname and section.segname == other_section.segname: 1032061da546Spatrick return section 1033061da546Spatrick return None 1034061da546Spatrick 1035061da546Spatrick def dump_sections(self, dump_description=True, options=None): 1036061da546Spatrick if dump_description: 1037061da546Spatrick print(self.description()) 1038061da546Spatrick num_sections = len(self.sections) 1039061da546Spatrick if num_sections > 1: 1040061da546Spatrick self.sections[1].dump_header() 1041061da546Spatrick for sect_idx in range(1, num_sections): 1042061da546Spatrick print("%s" % self.sections[sect_idx]) 1043061da546Spatrick 1044061da546Spatrick def dump_section_contents(self, options): 1045061da546Spatrick saved_section_to_disk = False 1046061da546Spatrick for sectname in options.section_names: 1047061da546Spatrick section = self.get_section_by_name(sectname) 1048061da546Spatrick if section: 1049061da546Spatrick sect_bytes = section.get_contents(self) 1050061da546Spatrick if options.outfile: 1051061da546Spatrick if not saved_section_to_disk: 1052061da546Spatrick outfile = open(options.outfile, 'w') 1053061da546Spatrick if options.extract_modules: 1054061da546Spatrick # print "Extracting modules from mach file..." 1055061da546Spatrick data = file_extract.FileExtract( 1056061da546Spatrick io.BytesIO(sect_bytes), self.data.byte_order) 1057061da546Spatrick version = data.get_uint32() 1058061da546Spatrick num_modules = data.get_uint32() 1059061da546Spatrick # print "version = %u, num_modules = %u" % 1060061da546Spatrick # (version, num_modules) 1061061da546Spatrick for i in range(num_modules): 1062061da546Spatrick data_offset = data.get_uint64() 1063061da546Spatrick data_size = data.get_uint64() 1064061da546Spatrick name_offset = data.get_uint32() 1065061da546Spatrick language = data.get_uint32() 1066061da546Spatrick flags = data.get_uint32() 1067061da546Spatrick data.seek(name_offset) 1068061da546Spatrick module_name = data.get_c_string() 1069061da546Spatrick # print "module[%u] data_offset = %#16.16x, 1070061da546Spatrick # data_size = %#16.16x, name_offset = 1071061da546Spatrick # %#16.16x (%s), language = %u, flags = 1072061da546Spatrick # %#x" % (i, data_offset, data_size, 1073061da546Spatrick # name_offset, module_name, language, 1074061da546Spatrick # flags) 1075061da546Spatrick data.seek(data_offset) 1076061da546Spatrick outfile.write(data.read_size(data_size)) 1077061da546Spatrick else: 1078061da546Spatrick print("Saving section %s to '%s'" % (sectname, options.outfile)) 1079061da546Spatrick outfile.write(sect_bytes) 1080061da546Spatrick outfile.close() 1081061da546Spatrick saved_section_to_disk = True 1082061da546Spatrick else: 1083061da546Spatrick print("error: you can only save a single section to disk at a time, skipping section '%s'" % (sectname)) 1084061da546Spatrick else: 1085061da546Spatrick print('section %s:\n' % (sectname)) 1086061da546Spatrick section.dump_header() 1087061da546Spatrick print('%s\n' % (section)) 1088061da546Spatrick dump_memory(0, sect_bytes, options.max_count, 16) 1089061da546Spatrick else: 1090061da546Spatrick print('error: no section named "%s" was found' % (sectname)) 1091061da546Spatrick 1092061da546Spatrick def get_segment(self, segname): 1093061da546Spatrick if len(self.segments) == 1 and self.segments[0].segname == '': 1094061da546Spatrick return self.segments[0] 1095061da546Spatrick for segment in self.segments: 1096061da546Spatrick if segment.segname == segname: 1097061da546Spatrick return segment 1098061da546Spatrick return None 1099061da546Spatrick 1100061da546Spatrick def get_first_load_command(self, lc_enum_value): 1101061da546Spatrick for lc in self.commands: 1102061da546Spatrick if lc.command.value == lc_enum_value: 1103061da546Spatrick return lc 1104061da546Spatrick return None 1105061da546Spatrick 1106061da546Spatrick def get_symtab(self): 1107061da546Spatrick if self.data and not self.symbols: 1108061da546Spatrick lc_symtab = self.get_first_load_command(LC_SYMTAB) 1109061da546Spatrick if lc_symtab: 1110061da546Spatrick symtab_offset = self.file_off 1111061da546Spatrick if self.data.is_in_memory(): 1112061da546Spatrick linkedit_segment = self.get_segment('__LINKEDIT') 1113061da546Spatrick if linkedit_segment: 1114061da546Spatrick linkedit_vmaddr = linkedit_segment.vmaddr 1115061da546Spatrick linkedit_fileoff = linkedit_segment.fileoff 1116061da546Spatrick symtab_offset = linkedit_vmaddr + lc_symtab.symoff - linkedit_fileoff 1117061da546Spatrick symtab_offset = linkedit_vmaddr + lc_symtab.stroff - linkedit_fileoff 1118061da546Spatrick else: 1119061da546Spatrick symtab_offset += lc_symtab.symoff 1120061da546Spatrick 1121061da546Spatrick self.data.seek(symtab_offset) 1122061da546Spatrick is_64 = self.is_64_bit() 1123061da546Spatrick for i in range(lc_symtab.nsyms): 1124061da546Spatrick nlist = Mach.NList() 1125061da546Spatrick nlist.unpack(self, self.data, lc_symtab) 1126061da546Spatrick self.symbols.append(nlist) 1127061da546Spatrick else: 1128061da546Spatrick print("no LC_SYMTAB") 1129061da546Spatrick 1130061da546Spatrick def dump_symtab(self, dump_description=True, options=None): 1131061da546Spatrick self.get_symtab() 1132061da546Spatrick if dump_description: 1133061da546Spatrick print(self.description()) 1134061da546Spatrick for i, symbol in enumerate(self.symbols): 1135061da546Spatrick print('[%5u] %s' % (i, symbol)) 1136061da546Spatrick 1137061da546Spatrick def dump_symbol_names_matching_regex(self, regex, file=None): 1138061da546Spatrick self.get_symtab() 1139061da546Spatrick for symbol in self.symbols: 1140061da546Spatrick if symbol.name and regex.search(symbol.name): 1141061da546Spatrick print(symbol.name) 1142061da546Spatrick if file: 1143061da546Spatrick file.write('%s\n' % (symbol.name)) 1144061da546Spatrick 1145061da546Spatrick def is_64_bit(self): 1146061da546Spatrick return self.magic.is_64_bit() 1147061da546Spatrick 1148061da546Spatrick class LoadCommand: 1149061da546Spatrick 1150061da546Spatrick class Command(dict_utils.Enum): 1151061da546Spatrick enum = { 1152061da546Spatrick 'LC_SEGMENT': LC_SEGMENT, 1153061da546Spatrick 'LC_SYMTAB': LC_SYMTAB, 1154061da546Spatrick 'LC_SYMSEG': LC_SYMSEG, 1155061da546Spatrick 'LC_THREAD': LC_THREAD, 1156061da546Spatrick 'LC_UNIXTHREAD': LC_UNIXTHREAD, 1157061da546Spatrick 'LC_LOADFVMLIB': LC_LOADFVMLIB, 1158061da546Spatrick 'LC_IDFVMLIB': LC_IDFVMLIB, 1159061da546Spatrick 'LC_IDENT': LC_IDENT, 1160061da546Spatrick 'LC_FVMFILE': LC_FVMFILE, 1161061da546Spatrick 'LC_PREPAGE': LC_PREPAGE, 1162061da546Spatrick 'LC_DYSYMTAB': LC_DYSYMTAB, 1163061da546Spatrick 'LC_LOAD_DYLIB': LC_LOAD_DYLIB, 1164061da546Spatrick 'LC_ID_DYLIB': LC_ID_DYLIB, 1165061da546Spatrick 'LC_LOAD_DYLINKER': LC_LOAD_DYLINKER, 1166061da546Spatrick 'LC_ID_DYLINKER': LC_ID_DYLINKER, 1167061da546Spatrick 'LC_PREBOUND_DYLIB': LC_PREBOUND_DYLIB, 1168061da546Spatrick 'LC_ROUTINES': LC_ROUTINES, 1169061da546Spatrick 'LC_SUB_FRAMEWORK': LC_SUB_FRAMEWORK, 1170061da546Spatrick 'LC_SUB_UMBRELLA': LC_SUB_UMBRELLA, 1171061da546Spatrick 'LC_SUB_CLIENT': LC_SUB_CLIENT, 1172061da546Spatrick 'LC_SUB_LIBRARY': LC_SUB_LIBRARY, 1173061da546Spatrick 'LC_TWOLEVEL_HINTS': LC_TWOLEVEL_HINTS, 1174061da546Spatrick 'LC_PREBIND_CKSUM': LC_PREBIND_CKSUM, 1175061da546Spatrick 'LC_LOAD_WEAK_DYLIB': LC_LOAD_WEAK_DYLIB, 1176061da546Spatrick 'LC_SEGMENT_64': LC_SEGMENT_64, 1177061da546Spatrick 'LC_ROUTINES_64': LC_ROUTINES_64, 1178061da546Spatrick 'LC_UUID': LC_UUID, 1179061da546Spatrick 'LC_RPATH': LC_RPATH, 1180061da546Spatrick 'LC_CODE_SIGNATURE': LC_CODE_SIGNATURE, 1181061da546Spatrick 'LC_SEGMENT_SPLIT_INFO': LC_SEGMENT_SPLIT_INFO, 1182061da546Spatrick 'LC_REEXPORT_DYLIB': LC_REEXPORT_DYLIB, 1183061da546Spatrick 'LC_LAZY_LOAD_DYLIB': LC_LAZY_LOAD_DYLIB, 1184061da546Spatrick 'LC_ENCRYPTION_INFO': LC_ENCRYPTION_INFO, 1185061da546Spatrick 'LC_DYLD_INFO': LC_DYLD_INFO, 1186061da546Spatrick 'LC_DYLD_INFO_ONLY': LC_DYLD_INFO_ONLY, 1187061da546Spatrick 'LC_LOAD_UPWARD_DYLIB': LC_LOAD_UPWARD_DYLIB, 1188061da546Spatrick 'LC_VERSION_MIN_MACOSX': LC_VERSION_MIN_MACOSX, 1189061da546Spatrick 'LC_VERSION_MIN_IPHONEOS': LC_VERSION_MIN_IPHONEOS, 1190061da546Spatrick 'LC_FUNCTION_STARTS': LC_FUNCTION_STARTS, 1191061da546Spatrick 'LC_DYLD_ENVIRONMENT': LC_DYLD_ENVIRONMENT 1192061da546Spatrick } 1193061da546Spatrick 1194061da546Spatrick def __init__(self, initial_value=0): 1195061da546Spatrick dict_utils.Enum.__init__(self, initial_value, self.enum) 1196061da546Spatrick 1197061da546Spatrick def __init__(self, c=None, l=0, o=0): 1198061da546Spatrick if c is not None: 1199061da546Spatrick self.command = c 1200061da546Spatrick else: 1201061da546Spatrick self.command = Mach.LoadCommand.Command(0) 1202061da546Spatrick self.length = l 1203061da546Spatrick self.file_off = o 1204061da546Spatrick 1205061da546Spatrick def unpack(self, mach_file, data): 1206061da546Spatrick self.file_off = data.tell() 1207061da546Spatrick self.command.value, self.length = data.get_n_uint32(2) 1208061da546Spatrick 1209061da546Spatrick def skip(self, data): 1210061da546Spatrick data.seek(self.file_off + self.length, 0) 1211061da546Spatrick 1212061da546Spatrick def __str__(self): 1213061da546Spatrick lc_name = self.command.get_enum_name() 1214061da546Spatrick return '%#8.8x: <%#4.4x> %-24s' % (self.file_off, 1215061da546Spatrick self.length, lc_name) 1216061da546Spatrick 1217061da546Spatrick class Section: 1218061da546Spatrick 1219061da546Spatrick def __init__(self): 1220061da546Spatrick self.index = 0 1221061da546Spatrick self.is_64 = False 1222061da546Spatrick self.sectname = None 1223061da546Spatrick self.segname = None 1224061da546Spatrick self.addr = 0 1225061da546Spatrick self.size = 0 1226061da546Spatrick self.offset = 0 1227061da546Spatrick self.align = 0 1228061da546Spatrick self.reloff = 0 1229061da546Spatrick self.nreloc = 0 1230061da546Spatrick self.flags = 0 1231061da546Spatrick self.reserved1 = 0 1232061da546Spatrick self.reserved2 = 0 1233061da546Spatrick self.reserved3 = 0 1234061da546Spatrick 1235061da546Spatrick def unpack(self, is_64, data): 1236061da546Spatrick self.is_64 = is_64 1237061da546Spatrick self.sectname = data.get_fixed_length_c_string(16, '', True) 1238061da546Spatrick self.segname = data.get_fixed_length_c_string(16, '', True) 1239061da546Spatrick if self.is_64: 1240061da546Spatrick self.addr, self.size = data.get_n_uint64(2) 1241061da546Spatrick self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3 = data.get_n_uint32( 1242061da546Spatrick 8) 1243061da546Spatrick else: 1244061da546Spatrick self.addr, self.size = data.get_n_uint32(2) 1245061da546Spatrick self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2 = data.get_n_uint32( 1246061da546Spatrick 7) 1247061da546Spatrick 1248061da546Spatrick def dump_header(self): 1249061da546Spatrick if self.is_64: 1250061da546Spatrick print("INDEX ADDRESS SIZE OFFSET ALIGN RELOFF NRELOC FLAGS RESERVED1 RESERVED2 RESERVED3 NAME") 1251061da546Spatrick print("===== ------------------ ------------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------") 1252061da546Spatrick else: 1253061da546Spatrick print("INDEX ADDRESS SIZE OFFSET ALIGN RELOFF NRELOC FLAGS RESERVED1 RESERVED2 NAME") 1254061da546Spatrick print("===== ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------") 1255061da546Spatrick 1256061da546Spatrick def __str__(self): 1257061da546Spatrick if self.is_64: 1258061da546Spatrick return "[%3u] %#16.16x %#16.16x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % ( 1259061da546Spatrick self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3, self.segname, self.sectname) 1260061da546Spatrick else: 1261061da546Spatrick return "[%3u] %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % ( 1262061da546Spatrick self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.segname, self.sectname) 1263061da546Spatrick 1264061da546Spatrick def get_contents(self, mach_file): 1265061da546Spatrick '''Get the section contents as a python string''' 1266061da546Spatrick if self.size > 0 and mach_file.get_segment( 1267061da546Spatrick self.segname).filesize > 0: 1268061da546Spatrick data = mach_file.get_data() 1269061da546Spatrick if data: 1270061da546Spatrick section_data_offset = mach_file.file_off + self.offset 1271061da546Spatrick # print '%s.%s is at offset 0x%x with size 0x%x' % 1272061da546Spatrick # (self.segname, self.sectname, section_data_offset, 1273061da546Spatrick # self.size) 1274061da546Spatrick data.push_offset_and_seek(section_data_offset) 1275061da546Spatrick bytes = data.read_size(self.size) 1276061da546Spatrick data.pop_offset_and_seek() 1277061da546Spatrick return bytes 1278061da546Spatrick return None 1279061da546Spatrick 1280061da546Spatrick class DylibLoadCommand(LoadCommand): 1281061da546Spatrick 1282061da546Spatrick def __init__(self, lc): 1283061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1284061da546Spatrick self.name = None 1285061da546Spatrick self.timestamp = 0 1286061da546Spatrick self.current_version = 0 1287061da546Spatrick self.compatibility_version = 0 1288061da546Spatrick 1289061da546Spatrick def unpack(self, mach_file, data): 1290061da546Spatrick byte_order_char = mach_file.magic.get_byte_order() 1291061da546Spatrick name_offset, self.timestamp, self.current_version, self.compatibility_version = data.get_n_uint32( 1292061da546Spatrick 4) 1293061da546Spatrick data.seek(self.file_off + name_offset, 0) 1294061da546Spatrick self.name = data.get_fixed_length_c_string(self.length - 24) 1295061da546Spatrick 1296061da546Spatrick def __str__(self): 1297061da546Spatrick s = Mach.LoadCommand.__str__(self) 1298061da546Spatrick s += "%#8.8x %#8.8x %#8.8x " % (self.timestamp, 1299061da546Spatrick self.current_version, 1300061da546Spatrick self.compatibility_version) 1301061da546Spatrick s += self.name 1302061da546Spatrick return s 1303061da546Spatrick 1304061da546Spatrick class LoadDYLDLoadCommand(LoadCommand): 1305061da546Spatrick 1306061da546Spatrick def __init__(self, lc): 1307061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1308061da546Spatrick self.name = None 1309061da546Spatrick 1310061da546Spatrick def unpack(self, mach_file, data): 1311061da546Spatrick data.get_uint32() 1312061da546Spatrick self.name = data.get_fixed_length_c_string(self.length - 12) 1313061da546Spatrick 1314061da546Spatrick def __str__(self): 1315061da546Spatrick s = Mach.LoadCommand.__str__(self) 1316061da546Spatrick s += "%s" % self.name 1317061da546Spatrick return s 1318061da546Spatrick 1319061da546Spatrick class UnixThreadLoadCommand(LoadCommand): 1320061da546Spatrick 1321061da546Spatrick class ThreadState: 1322061da546Spatrick 1323061da546Spatrick def __init__(self): 1324061da546Spatrick self.flavor = 0 1325061da546Spatrick self.count = 0 1326061da546Spatrick self.register_values = list() 1327061da546Spatrick 1328061da546Spatrick def unpack(self, data): 1329061da546Spatrick self.flavor, self.count = data.get_n_uint32(2) 1330061da546Spatrick self.register_values = data.get_n_uint32(self.count) 1331061da546Spatrick 1332061da546Spatrick def __str__(self): 1333061da546Spatrick s = "flavor = %u, count = %u, regs =" % ( 1334061da546Spatrick self.flavor, self.count) 1335061da546Spatrick i = 0 1336061da546Spatrick for register_value in self.register_values: 1337061da546Spatrick if i % 8 == 0: 1338061da546Spatrick s += "\n " 1339061da546Spatrick s += " %#8.8x" % register_value 1340061da546Spatrick i += 1 1341061da546Spatrick return s 1342061da546Spatrick 1343061da546Spatrick def __init__(self, lc): 1344061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1345061da546Spatrick self.reg_sets = list() 1346061da546Spatrick 1347061da546Spatrick def unpack(self, mach_file, data): 1348061da546Spatrick reg_set = Mach.UnixThreadLoadCommand.ThreadState() 1349061da546Spatrick reg_set.unpack(data) 1350061da546Spatrick self.reg_sets.append(reg_set) 1351061da546Spatrick 1352061da546Spatrick def __str__(self): 1353061da546Spatrick s = Mach.LoadCommand.__str__(self) 1354061da546Spatrick for reg_set in self.reg_sets: 1355061da546Spatrick s += "%s" % reg_set 1356061da546Spatrick return s 1357061da546Spatrick 1358061da546Spatrick class DYLDInfoOnlyLoadCommand(LoadCommand): 1359061da546Spatrick 1360061da546Spatrick def __init__(self, lc): 1361061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1362061da546Spatrick self.rebase_off = 0 1363061da546Spatrick self.rebase_size = 0 1364061da546Spatrick self.bind_off = 0 1365061da546Spatrick self.bind_size = 0 1366061da546Spatrick self.weak_bind_off = 0 1367061da546Spatrick self.weak_bind_size = 0 1368061da546Spatrick self.lazy_bind_off = 0 1369061da546Spatrick self.lazy_bind_size = 0 1370061da546Spatrick self.export_off = 0 1371061da546Spatrick self.export_size = 0 1372061da546Spatrick 1373061da546Spatrick def unpack(self, mach_file, data): 1374061da546Spatrick byte_order_char = mach_file.magic.get_byte_order() 1375061da546Spatrick self.rebase_off, self.rebase_size, self.bind_off, self.bind_size, self.weak_bind_off, self.weak_bind_size, self.lazy_bind_off, self.lazy_bind_size, self.export_off, self.export_size = data.get_n_uint32( 1376061da546Spatrick 10) 1377061da546Spatrick 1378061da546Spatrick def __str__(self): 1379061da546Spatrick s = Mach.LoadCommand.__str__(self) 1380061da546Spatrick s += "rebase_off = %#8.8x, rebase_size = %u, " % ( 1381061da546Spatrick self.rebase_off, self.rebase_size) 1382061da546Spatrick s += "bind_off = %#8.8x, bind_size = %u, " % ( 1383061da546Spatrick self.bind_off, self.bind_size) 1384061da546Spatrick s += "weak_bind_off = %#8.8x, weak_bind_size = %u, " % ( 1385061da546Spatrick self.weak_bind_off, self.weak_bind_size) 1386061da546Spatrick s += "lazy_bind_off = %#8.8x, lazy_bind_size = %u, " % ( 1387061da546Spatrick self.lazy_bind_off, self.lazy_bind_size) 1388061da546Spatrick s += "export_off = %#8.8x, export_size = %u, " % ( 1389061da546Spatrick self.export_off, self.export_size) 1390061da546Spatrick return s 1391061da546Spatrick 1392061da546Spatrick class DYLDSymtabLoadCommand(LoadCommand): 1393061da546Spatrick 1394061da546Spatrick def __init__(self, lc): 1395061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1396061da546Spatrick self.ilocalsym = 0 1397061da546Spatrick self.nlocalsym = 0 1398061da546Spatrick self.iextdefsym = 0 1399061da546Spatrick self.nextdefsym = 0 1400061da546Spatrick self.iundefsym = 0 1401061da546Spatrick self.nundefsym = 0 1402061da546Spatrick self.tocoff = 0 1403061da546Spatrick self.ntoc = 0 1404061da546Spatrick self.modtaboff = 0 1405061da546Spatrick self.nmodtab = 0 1406061da546Spatrick self.extrefsymoff = 0 1407061da546Spatrick self.nextrefsyms = 0 1408061da546Spatrick self.indirectsymoff = 0 1409061da546Spatrick self.nindirectsyms = 0 1410061da546Spatrick self.extreloff = 0 1411061da546Spatrick self.nextrel = 0 1412061da546Spatrick self.locreloff = 0 1413061da546Spatrick self.nlocrel = 0 1414061da546Spatrick 1415061da546Spatrick def unpack(self, mach_file, data): 1416061da546Spatrick byte_order_char = mach_file.magic.get_byte_order() 1417061da546Spatrick self.ilocalsym, self.nlocalsym, self.iextdefsym, self.nextdefsym, self.iundefsym, self.nundefsym, self.tocoff, self.ntoc, self.modtaboff, self.nmodtab, self.extrefsymoff, self.nextrefsyms, self.indirectsymoff, self.nindirectsyms, self.extreloff, self.nextrel, self.locreloff, self.nlocrel = data.get_n_uint32( 1418061da546Spatrick 18) 1419061da546Spatrick 1420061da546Spatrick def __str__(self): 1421061da546Spatrick s = Mach.LoadCommand.__str__(self) 1422061da546Spatrick # s += "ilocalsym = %u, nlocalsym = %u, " % (self.ilocalsym, self.nlocalsym) 1423061da546Spatrick # s += "iextdefsym = %u, nextdefsym = %u, " % (self.iextdefsym, self.nextdefsym) 1424061da546Spatrick # s += "iundefsym %u, nundefsym = %u, " % (self.iundefsym, self.nundefsym) 1425061da546Spatrick # s += "tocoff = %#8.8x, ntoc = %u, " % (self.tocoff, self.ntoc) 1426061da546Spatrick # s += "modtaboff = %#8.8x, nmodtab = %u, " % (self.modtaboff, self.nmodtab) 1427061da546Spatrick # s += "extrefsymoff = %#8.8x, nextrefsyms = %u, " % (self.extrefsymoff, self.nextrefsyms) 1428061da546Spatrick # s += "indirectsymoff = %#8.8x, nindirectsyms = %u, " % (self.indirectsymoff, self.nindirectsyms) 1429061da546Spatrick # s += "extreloff = %#8.8x, nextrel = %u, " % (self.extreloff, self.nextrel) 1430061da546Spatrick # s += "locreloff = %#8.8x, nlocrel = %u" % (self.locreloff, 1431061da546Spatrick # self.nlocrel) 1432061da546Spatrick s += "ilocalsym = %-10u, nlocalsym = %u\n" % ( 1433061da546Spatrick self.ilocalsym, self.nlocalsym) 1434061da546Spatrick s += " iextdefsym = %-10u, nextdefsym = %u\n" % ( 1435061da546Spatrick self.iextdefsym, self.nextdefsym) 1436061da546Spatrick s += " iundefsym = %-10u, nundefsym = %u\n" % ( 1437061da546Spatrick self.iundefsym, self.nundefsym) 1438061da546Spatrick s += " tocoff = %#8.8x, ntoc = %u\n" % ( 1439061da546Spatrick self.tocoff, self.ntoc) 1440061da546Spatrick s += " modtaboff = %#8.8x, nmodtab = %u\n" % ( 1441061da546Spatrick self.modtaboff, self.nmodtab) 1442061da546Spatrick s += " extrefsymoff = %#8.8x, nextrefsyms = %u\n" % ( 1443061da546Spatrick self.extrefsymoff, self.nextrefsyms) 1444061da546Spatrick s += " indirectsymoff = %#8.8x, nindirectsyms = %u\n" % ( 1445061da546Spatrick self.indirectsymoff, self.nindirectsyms) 1446061da546Spatrick s += " extreloff = %#8.8x, nextrel = %u\n" % ( 1447061da546Spatrick self.extreloff, self.nextrel) 1448061da546Spatrick s += " locreloff = %#8.8x, nlocrel = %u" % ( 1449061da546Spatrick self.locreloff, self.nlocrel) 1450061da546Spatrick return s 1451061da546Spatrick 1452061da546Spatrick class SymtabLoadCommand(LoadCommand): 1453061da546Spatrick 1454061da546Spatrick def __init__(self, lc): 1455061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1456061da546Spatrick self.symoff = 0 1457061da546Spatrick self.nsyms = 0 1458061da546Spatrick self.stroff = 0 1459061da546Spatrick self.strsize = 0 1460061da546Spatrick 1461061da546Spatrick def unpack(self, mach_file, data): 1462061da546Spatrick byte_order_char = mach_file.magic.get_byte_order() 1463061da546Spatrick self.symoff, self.nsyms, self.stroff, self.strsize = data.get_n_uint32( 1464061da546Spatrick 4) 1465061da546Spatrick 1466061da546Spatrick def __str__(self): 1467061da546Spatrick s = Mach.LoadCommand.__str__(self) 1468061da546Spatrick s += "symoff = %#8.8x, nsyms = %u, stroff = %#8.8x, strsize = %u" % ( 1469061da546Spatrick self.symoff, self.nsyms, self.stroff, self.strsize) 1470061da546Spatrick return s 1471061da546Spatrick 1472061da546Spatrick class UUIDLoadCommand(LoadCommand): 1473061da546Spatrick 1474061da546Spatrick def __init__(self, lc): 1475061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1476061da546Spatrick self.uuid = None 1477061da546Spatrick 1478061da546Spatrick def unpack(self, mach_file, data): 1479061da546Spatrick uuid_data = data.get_n_uint8(16) 1480061da546Spatrick uuid_str = '' 1481061da546Spatrick for byte in uuid_data: 1482061da546Spatrick uuid_str += '%2.2x' % byte 1483061da546Spatrick self.uuid = uuid.UUID(uuid_str) 1484061da546Spatrick mach_file.uuid = self.uuid 1485061da546Spatrick 1486061da546Spatrick def __str__(self): 1487061da546Spatrick s = Mach.LoadCommand.__str__(self) 1488061da546Spatrick s += self.uuid.__str__() 1489061da546Spatrick return s 1490061da546Spatrick 1491061da546Spatrick class DataBlobLoadCommand(LoadCommand): 1492061da546Spatrick 1493061da546Spatrick def __init__(self, lc): 1494061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1495061da546Spatrick self.dataoff = 0 1496061da546Spatrick self.datasize = 0 1497061da546Spatrick 1498061da546Spatrick def unpack(self, mach_file, data): 1499061da546Spatrick byte_order_char = mach_file.magic.get_byte_order() 1500061da546Spatrick self.dataoff, self.datasize = data.get_n_uint32(2) 1501061da546Spatrick 1502061da546Spatrick def __str__(self): 1503061da546Spatrick s = Mach.LoadCommand.__str__(self) 1504061da546Spatrick s += "dataoff = %#8.8x, datasize = %u" % ( 1505061da546Spatrick self.dataoff, self.datasize) 1506061da546Spatrick return s 1507061da546Spatrick 1508061da546Spatrick class EncryptionInfoLoadCommand(LoadCommand): 1509061da546Spatrick 1510061da546Spatrick def __init__(self, lc): 1511061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1512061da546Spatrick self.cryptoff = 0 1513061da546Spatrick self.cryptsize = 0 1514061da546Spatrick self.cryptid = 0 1515061da546Spatrick 1516061da546Spatrick def unpack(self, mach_file, data): 1517061da546Spatrick byte_order_char = mach_file.magic.get_byte_order() 1518061da546Spatrick self.cryptoff, self.cryptsize, self.cryptid = data.get_n_uint32(3) 1519061da546Spatrick 1520061da546Spatrick def __str__(self): 1521061da546Spatrick s = Mach.LoadCommand.__str__(self) 1522061da546Spatrick s += "file-range = [%#8.8x - %#8.8x), cryptsize = %u, cryptid = %u" % ( 1523061da546Spatrick self.cryptoff, self.cryptoff + self.cryptsize, self.cryptsize, self.cryptid) 1524061da546Spatrick return s 1525061da546Spatrick 1526061da546Spatrick class SegmentLoadCommand(LoadCommand): 1527061da546Spatrick 1528061da546Spatrick def __init__(self, lc): 1529061da546Spatrick Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off) 1530061da546Spatrick self.segname = None 1531061da546Spatrick self.vmaddr = 0 1532061da546Spatrick self.vmsize = 0 1533061da546Spatrick self.fileoff = 0 1534061da546Spatrick self.filesize = 0 1535061da546Spatrick self.maxprot = 0 1536061da546Spatrick self.initprot = 0 1537061da546Spatrick self.nsects = 0 1538061da546Spatrick self.flags = 0 1539061da546Spatrick 1540061da546Spatrick def unpack(self, mach_file, data): 1541061da546Spatrick is_64 = self.command.get_enum_value() == LC_SEGMENT_64 1542061da546Spatrick self.segname = data.get_fixed_length_c_string(16, '', True) 1543061da546Spatrick if is_64: 1544061da546Spatrick self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint64( 1545061da546Spatrick 4) 1546061da546Spatrick else: 1547061da546Spatrick self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint32( 1548061da546Spatrick 4) 1549061da546Spatrick self.maxprot, self.initprot, self.nsects, self.flags = data.get_n_uint32( 1550061da546Spatrick 4) 1551061da546Spatrick mach_file.segments.append(self) 1552061da546Spatrick for i in range(self.nsects): 1553061da546Spatrick section = Mach.Section() 1554061da546Spatrick section.unpack(is_64, data) 1555061da546Spatrick section.index = len(mach_file.sections) 1556061da546Spatrick mach_file.sections.append(section) 1557061da546Spatrick 1558061da546Spatrick def __str__(self): 1559061da546Spatrick s = Mach.LoadCommand.__str__(self) 1560061da546Spatrick if self.command.get_enum_value() == LC_SEGMENT: 1561061da546Spatrick s += "%#8.8x %#8.8x %#8.8x %#8.8x " % ( 1562061da546Spatrick self.vmaddr, self.vmsize, self.fileoff, self.filesize) 1563061da546Spatrick else: 1564061da546Spatrick s += "%#16.16x %#16.16x %#16.16x %#16.16x " % ( 1565061da546Spatrick self.vmaddr, self.vmsize, self.fileoff, self.filesize) 1566061da546Spatrick s += "%s %s %3u %#8.8x" % (vm_prot_names[self.maxprot], vm_prot_names[ 1567061da546Spatrick self.initprot], self.nsects, self.flags) 1568061da546Spatrick s += ' ' + self.segname 1569061da546Spatrick return s 1570061da546Spatrick 1571061da546Spatrick class NList: 1572061da546Spatrick 1573061da546Spatrick class Type: 1574061da546Spatrick 1575061da546Spatrick class Stab(dict_utils.Enum): 1576061da546Spatrick enum = { 1577061da546Spatrick 'N_GSYM': N_GSYM, 1578061da546Spatrick 'N_FNAME': N_FNAME, 1579061da546Spatrick 'N_FUN': N_FUN, 1580061da546Spatrick 'N_STSYM': N_STSYM, 1581061da546Spatrick 'N_LCSYM': N_LCSYM, 1582061da546Spatrick 'N_BNSYM': N_BNSYM, 1583061da546Spatrick 'N_OPT': N_OPT, 1584061da546Spatrick 'N_RSYM': N_RSYM, 1585061da546Spatrick 'N_SLINE': N_SLINE, 1586061da546Spatrick 'N_ENSYM': N_ENSYM, 1587061da546Spatrick 'N_SSYM': N_SSYM, 1588061da546Spatrick 'N_SO': N_SO, 1589061da546Spatrick 'N_OSO': N_OSO, 1590061da546Spatrick 'N_LSYM': N_LSYM, 1591061da546Spatrick 'N_BINCL': N_BINCL, 1592061da546Spatrick 'N_SOL': N_SOL, 1593061da546Spatrick 'N_PARAMS': N_PARAMS, 1594061da546Spatrick 'N_VERSION': N_VERSION, 1595061da546Spatrick 'N_OLEVEL': N_OLEVEL, 1596061da546Spatrick 'N_PSYM': N_PSYM, 1597061da546Spatrick 'N_EINCL': N_EINCL, 1598061da546Spatrick 'N_ENTRY': N_ENTRY, 1599061da546Spatrick 'N_LBRAC': N_LBRAC, 1600061da546Spatrick 'N_EXCL': N_EXCL, 1601061da546Spatrick 'N_RBRAC': N_RBRAC, 1602061da546Spatrick 'N_BCOMM': N_BCOMM, 1603061da546Spatrick 'N_ECOMM': N_ECOMM, 1604061da546Spatrick 'N_ECOML': N_ECOML, 1605061da546Spatrick 'N_LENG': N_LENG 1606061da546Spatrick } 1607061da546Spatrick 1608061da546Spatrick def __init__(self, magic=0): 1609061da546Spatrick dict_utils.Enum.__init__(self, magic, self.enum) 1610061da546Spatrick 1611061da546Spatrick def __init__(self, t=0): 1612061da546Spatrick self.value = t 1613061da546Spatrick 1614061da546Spatrick def __str__(self): 1615061da546Spatrick n_type = self.value 1616061da546Spatrick if n_type & N_STAB: 1617061da546Spatrick stab = Mach.NList.Type.Stab(self.value) 1618061da546Spatrick return '%s' % stab 1619061da546Spatrick else: 1620061da546Spatrick type = self.value & N_TYPE 1621061da546Spatrick type_str = '' 1622061da546Spatrick if type == N_UNDF: 1623061da546Spatrick type_str = 'N_UNDF' 1624061da546Spatrick elif type == N_ABS: 1625061da546Spatrick type_str = 'N_ABS ' 1626061da546Spatrick elif type == N_SECT: 1627061da546Spatrick type_str = 'N_SECT' 1628061da546Spatrick elif type == N_PBUD: 1629061da546Spatrick type_str = 'N_PBUD' 1630061da546Spatrick elif type == N_INDR: 1631061da546Spatrick type_str = 'N_INDR' 1632061da546Spatrick else: 1633061da546Spatrick type_str = "??? (%#2.2x)" % type 1634061da546Spatrick if n_type & N_PEXT: 1635061da546Spatrick type_str += ' | PEXT' 1636061da546Spatrick if n_type & N_EXT: 1637061da546Spatrick type_str += ' | EXT ' 1638061da546Spatrick return type_str 1639061da546Spatrick 1640061da546Spatrick def __init__(self): 1641061da546Spatrick self.index = 0 1642061da546Spatrick self.name_offset = 0 1643061da546Spatrick self.name = 0 1644061da546Spatrick self.type = Mach.NList.Type() 1645061da546Spatrick self.sect_idx = 0 1646061da546Spatrick self.desc = 0 1647061da546Spatrick self.value = 0 1648061da546Spatrick 1649061da546Spatrick def unpack(self, mach_file, data, symtab_lc): 1650061da546Spatrick self.index = len(mach_file.symbols) 1651061da546Spatrick self.name_offset = data.get_uint32() 1652061da546Spatrick self.type.value, self.sect_idx = data.get_n_uint8(2) 1653061da546Spatrick self.desc = data.get_uint16() 1654061da546Spatrick if mach_file.is_64_bit(): 1655061da546Spatrick self.value = data.get_uint64() 1656061da546Spatrick else: 1657061da546Spatrick self.value = data.get_uint32() 1658061da546Spatrick data.push_offset_and_seek( 1659061da546Spatrick mach_file.file_off + 1660061da546Spatrick symtab_lc.stroff + 1661061da546Spatrick self.name_offset) 1662061da546Spatrick # print "get string for symbol[%u]" % self.index 1663061da546Spatrick self.name = data.get_c_string() 1664061da546Spatrick data.pop_offset_and_seek() 1665061da546Spatrick 1666061da546Spatrick def __str__(self): 1667061da546Spatrick name_display = '' 1668061da546Spatrick if len(self.name): 1669061da546Spatrick name_display = ' "%s"' % self.name 1670061da546Spatrick return '%#8.8x %#2.2x (%-20s) %#2.2x %#4.4x %16.16x%s' % (self.name_offset, 1671061da546Spatrick self.type.value, self.type, self.sect_idx, self.desc, self.value, name_display) 1672061da546Spatrick 1673061da546Spatrick class Interactive(cmd.Cmd): 1674061da546Spatrick '''Interactive command interpreter to mach-o files.''' 1675061da546Spatrick 1676061da546Spatrick def __init__(self, mach, options): 1677061da546Spatrick cmd.Cmd.__init__(self) 1678061da546Spatrick self.intro = 'Interactive mach-o command interpreter' 1679061da546Spatrick self.prompt = 'mach-o: %s %% ' % mach.path 1680061da546Spatrick self.mach = mach 1681061da546Spatrick self.options = options 1682061da546Spatrick 1683061da546Spatrick def default(self, line): 1684061da546Spatrick '''Catch all for unknown command, which will exit the interpreter.''' 1685061da546Spatrick print("uknown command: %s" % line) 1686061da546Spatrick return True 1687061da546Spatrick 1688061da546Spatrick def do_q(self, line): 1689061da546Spatrick '''Quit command''' 1690061da546Spatrick return True 1691061da546Spatrick 1692061da546Spatrick def do_quit(self, line): 1693061da546Spatrick '''Quit command''' 1694061da546Spatrick return True 1695061da546Spatrick 1696061da546Spatrick def do_header(self, line): 1697061da546Spatrick '''Dump mach-o file headers''' 1698061da546Spatrick self.mach.dump_header(True, self.options) 1699061da546Spatrick return False 1700061da546Spatrick 1701061da546Spatrick def do_load(self, line): 1702061da546Spatrick '''Dump all mach-o load commands''' 1703061da546Spatrick self.mach.dump_load_commands(True, self.options) 1704061da546Spatrick return False 1705061da546Spatrick 1706061da546Spatrick def do_sections(self, line): 1707061da546Spatrick '''Dump all mach-o sections''' 1708061da546Spatrick self.mach.dump_sections(True, self.options) 1709061da546Spatrick return False 1710061da546Spatrick 1711061da546Spatrick def do_symtab(self, line): 1712061da546Spatrick '''Dump all mach-o symbols in the symbol table''' 1713061da546Spatrick self.mach.dump_symtab(True, self.options) 1714061da546Spatrick return False 1715061da546Spatrick 1716061da546Spatrickif __name__ == '__main__': 1717061da546Spatrick parser = optparse.OptionParser( 1718061da546Spatrick description='A script that parses skinny and universal mach-o files.') 1719061da546Spatrick parser.add_option( 1720061da546Spatrick '--arch', 1721061da546Spatrick '-a', 1722061da546Spatrick type='string', 1723061da546Spatrick metavar='arch', 1724061da546Spatrick dest='archs', 1725061da546Spatrick action='append', 1726061da546Spatrick help='specify one or more architectures by name') 1727061da546Spatrick parser.add_option( 1728061da546Spatrick '-v', 1729061da546Spatrick '--verbose', 1730061da546Spatrick action='store_true', 1731061da546Spatrick dest='verbose', 1732061da546Spatrick help='display verbose debug info', 1733061da546Spatrick default=False) 1734061da546Spatrick parser.add_option( 1735061da546Spatrick '-H', 1736061da546Spatrick '--header', 1737061da546Spatrick action='store_true', 1738061da546Spatrick dest='dump_header', 1739061da546Spatrick help='dump the mach-o file header', 1740061da546Spatrick default=False) 1741061da546Spatrick parser.add_option( 1742061da546Spatrick '-l', 1743061da546Spatrick '--load-commands', 1744061da546Spatrick action='store_true', 1745061da546Spatrick dest='dump_load_commands', 1746061da546Spatrick help='dump the mach-o load commands', 1747061da546Spatrick default=False) 1748061da546Spatrick parser.add_option( 1749061da546Spatrick '-s', 1750061da546Spatrick '--symtab', 1751061da546Spatrick action='store_true', 1752061da546Spatrick dest='dump_symtab', 1753061da546Spatrick help='dump the mach-o symbol table', 1754061da546Spatrick default=False) 1755061da546Spatrick parser.add_option( 1756061da546Spatrick '-S', 1757061da546Spatrick '--sections', 1758061da546Spatrick action='store_true', 1759061da546Spatrick dest='dump_sections', 1760061da546Spatrick help='dump the mach-o sections', 1761061da546Spatrick default=False) 1762061da546Spatrick parser.add_option( 1763061da546Spatrick '--section', 1764061da546Spatrick type='string', 1765061da546Spatrick metavar='sectname', 1766061da546Spatrick dest='section_names', 1767061da546Spatrick action='append', 1768061da546Spatrick help='Specify one or more section names to dump', 1769061da546Spatrick default=[]) 1770061da546Spatrick parser.add_option( 1771061da546Spatrick '-o', 1772061da546Spatrick '--out', 1773061da546Spatrick type='string', 1774061da546Spatrick dest='outfile', 1775061da546Spatrick help='Used in conjunction with the --section=NAME option to save a single section\'s data to disk.', 1776061da546Spatrick default=False) 1777061da546Spatrick parser.add_option( 1778061da546Spatrick '-i', 1779061da546Spatrick '--interactive', 1780061da546Spatrick action='store_true', 1781061da546Spatrick dest='interactive', 1782061da546Spatrick help='enable interactive mode', 1783061da546Spatrick default=False) 1784061da546Spatrick parser.add_option( 1785061da546Spatrick '-m', 1786061da546Spatrick '--mangled', 1787061da546Spatrick action='store_true', 1788061da546Spatrick dest='find_mangled', 1789061da546Spatrick help='dump all mangled names in a mach file', 1790061da546Spatrick default=False) 1791061da546Spatrick parser.add_option( 1792061da546Spatrick '-c', 1793061da546Spatrick '--compare', 1794061da546Spatrick action='store_true', 1795061da546Spatrick dest='compare', 1796061da546Spatrick help='compare two mach files', 1797061da546Spatrick default=False) 1798061da546Spatrick parser.add_option( 1799061da546Spatrick '-M', 1800061da546Spatrick '--extract-modules', 1801061da546Spatrick action='store_true', 1802061da546Spatrick dest='extract_modules', 1803061da546Spatrick help='Extract modules from file', 1804061da546Spatrick default=False) 1805061da546Spatrick parser.add_option( 1806061da546Spatrick '-C', 1807061da546Spatrick '--count', 1808061da546Spatrick type='int', 1809061da546Spatrick dest='max_count', 1810061da546Spatrick help='Sets the max byte count when dumping section data', 1811061da546Spatrick default=-1) 1812061da546Spatrick 1813061da546Spatrick (options, mach_files) = parser.parse_args() 1814061da546Spatrick if options.extract_modules: 1815061da546Spatrick if options.section_names: 1816061da546Spatrick print("error: can't use --section option with the --extract-modules option") 1817061da546Spatrick exit(1) 1818061da546Spatrick if not options.outfile: 1819061da546Spatrick print("error: the --output=FILE option must be specified with the --extract-modules option") 1820061da546Spatrick exit(1) 1821061da546Spatrick options.section_names.append("__apple_ast") 1822061da546Spatrick if options.compare: 1823061da546Spatrick if len(mach_files) == 2: 1824061da546Spatrick mach_a = Mach() 1825061da546Spatrick mach_b = Mach() 1826061da546Spatrick mach_a.parse(mach_files[0]) 1827061da546Spatrick mach_b.parse(mach_files[1]) 1828061da546Spatrick mach_a.compare(mach_b) 1829061da546Spatrick else: 1830061da546Spatrick print('error: --compare takes two mach files as arguments') 1831061da546Spatrick else: 1832061da546Spatrick if not (options.dump_header or options.dump_load_commands or options.dump_symtab or options.dump_sections or options.find_mangled or options.section_names): 1833061da546Spatrick options.dump_header = True 1834061da546Spatrick options.dump_load_commands = True 1835061da546Spatrick if options.verbose: 1836061da546Spatrick print('options', options) 1837061da546Spatrick print('mach_files', mach_files) 1838061da546Spatrick for path in mach_files: 1839061da546Spatrick mach = Mach() 1840061da546Spatrick mach.parse(path) 1841061da546Spatrick if options.interactive: 1842061da546Spatrick interpreter = Mach.Interactive(mach, options) 1843061da546Spatrick interpreter.cmdloop() 1844061da546Spatrick else: 1845061da546Spatrick mach.dump(options) 1846