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:
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:
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.
I use one of the little Blackbag tools, but you could just use ‘dd’: ‘cat universal.bin | bkb shf 0x53ea000 > universal.ppc’.
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:
Open the Universal binary in a hex editor.
Search for “0xFEEDFACE”, the PPC Mach-O magic number
Note the offset, and “cat file | dd bs=1 iskip=the-offset > file.out”.


renaud
November 2nd, 2006 1:16 pmTry :
lipo -thin i386 file -output file.i386
or
lipo -thin ppc file -output file.ppc
Chris
November 2nd, 2006 1:56 pmhttp://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/lipo.1.html
Matt
November 2nd, 2006 3:57 pmWhile 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 pmI 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 pmDang, 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 pmOnce I have a ‘thin’ i386 mach-o executable, how do I disassemble it into it’s source?
Thomas Ptacek
February 9th, 2007 10:50 pmWith objdump.
Leave a reply