De-Universalizing Mac Binaries for Disassembly

Thomas Ptacek | November 2nd, 2006 | Filed Under: Reversing, Uncategorized

I’m taking a peek inside a complex commercial Mac application. It’s an x86/PPC Universal Binary, which my tools don’t like much. They’ve got no problem with vanilla PPC Mach-O though; how do I “strip out” the PPC binary from the “fat” Mach-O?

There’s probably some cryptic option to “otool” to do this, but this task is so easily accomplished with a hex editor and standard Unix tools that I’m not going to bother looking. Instead:

  1. Read over the Apple Mach-O ABI documentation. Apple’s always got good technical writing, but… damn, yo. The Apple ABI docs are amazing. At any rate, skip to the end, and find:

  2. Universal Binaries are a simple archive format. The archive header:

  • u32 0xCAFEBABE
  • u32 number-of-segment-descriptors
  • Descriptors:
  • u32 CPU (7 is Intel, mach/machine.h).
  • u32 CPU subtype
  • u32 offset to segment
  • u32 size
  • u32 alignment

3. Find the PPC descriptor and its offset. My PPC segment starts at 0x53ea00 and runs ~600,000 bytes.

  1. I use one of the little Blackbag tools, but you could just use ‘dd’: ‘cat universal.bin | bkb shf 0x53ea000 > universal.ppc’.

  2. Check my work:

$ file universal.ppc universal.ppc: Mach-O executable ppc

I’m guessing that most of the time, you can get away with something even easier:

  1. Open the Universal binary in a hex editor.

  2. Search for “0xFEEDFACE”, the PPC Mach-O magic number

  3. Note the offset, and “cat file | dd bs=1 iskip=the-offset > file.out”.

7 Comments so far

  • renaud

    November 2nd, 2006 1:16 pm

    Try :

    lipo -thin i386 file -output file.i386
    or
    lipo -thin ppc file -output file.ppc

  • Chris

    November 2nd, 2006 1:56 pm
  • Matt

    November 2nd, 2006 3:57 pm

    While renaud and Chris have hit upon the Right Answer, I feel compelled to mention that telling dd to read and write one byte at a time is… less than efficient. “tail -c +offset file > file.out” will (I believe) give you the same results with many fewer I/O syscalls.

  • Thomas Ptacek

    November 2nd, 2006 4:48 pm

    I fully expected to be schooled after writing this post. Thank you Renaud and Chris.

    Matt, the actual offset and length for my binary wasn’t a multiple of 512; I didn’t know about the “tail” trick though, that rules, thank you.

  • Ryan Russell

    November 2nd, 2006 6:21 pm

    Dang, I knew this one and everyone beat me to it. But yes, after using lipo, they load in IDA Pro just fine. ;) Interestingly, I’ve observer that on the two PPC platforms I’ve tried (AIX, OS X PPC) binaries always seem to have more names than they need to. At least, I get a lot more names than I do from a Windows binary, before reaching for the .PDB file.

  • Matthew

    February 9th, 2007 9:03 pm

    Once I have a ‘thin’ i386 mach-o executable, how do I disassemble it into it’s source?

  • Thomas Ptacek

    February 9th, 2007 10:50 pm

    With objdump.

  • Leave a reply