There are 5 different targets in this Xcode project, the macOS bin & library, an iOS library & bin and a tvOS bin. Choose the respective target and build all of them through Xcode, OR build all the targets using the bundled build scripts for Debug and Release respectively.
The core functionality of classdump has also be made into a separate library for iOS and macOS, its still a bit rough around the edges but I primarily did that to use inside HeaderHelperApp, its the app I built to make dumping newer iOS/tvOS version files into the various repos I host with private headers & entitlements.
This project is an amalgam of a few different versions of classdump. Initially based on a version by DreamDevLost made as an iOS port from nygard/class-dump. From there I have manually merged in bits and pieces from various PR's against the original ie #78 and then made a working macOS version again.
In iOS 13 Apple introduced some new load commands into dyld (specifically LC_DYLD_CHAINED_FIXUPS
and LC_DYLD_EXPORTS_TRIE
) But didn't start widely using them
until iOS 15, once binaries are built with -fixup_chains
any class-dump projects that relied on the old methodolgy would no longer work. This writeup and related code was instrumental in me understanding how to implement this newer methodology.
My only prior experience with working on class dump was the cleanup work I did in classdump-dyld, I didn't really fully understand the process or how dyld and mach-o files fundamentally worked, and in getting this project updated and working I have a much better understanding. I can't overstate how much value I found in the resources gathered at this repo granted the open source apple code is available elsewhere for otool's (cctools) et al, it's nice to have a central place of reference.
I usedCDLCDyldInfo
as a template for the CDLCChainedFixups
that does most of the heavy lifting for the newer process. It walks the fixup chains and stores the binds and the rebases in two separate dictionaries, which are subsequently referenced as applicable. The biggest 'gotchas' of this process were the need byte swap and/or bitshift in random circumstances for inexplicable reasons. The samples I modified from llios's macho-parser section (included in this repo in the samples
folder) were instrumental in figuring this process out. Using some of the undocumented flags I added (-v,-d,-F,-z,-x etc..) On these sample files can give a better understanding on what im talking about, and the journey to figure all of this stuff out. The other big piece of the puzzle was making the adjustments for the differing DYLD_CHAINED_PTR_64_OFFSET
vs DYLD_CHAINED_PTR_64
pointer_format's when rebinding & rebasing.
While researching the new LC_DYLD_CHAINED_FIXUPS
based world I was experimenting with otool
output on the provided 'sample' files to see what kind of output I would get from the commands based around dumping the obj-c portions of the file and I noticed something curious when dumping iOS binaries.
Notice anything different? In the iOS section, even otool has trouble resolving the symbols i.e. 0x4790 (0x10000c460 extends past end of file)
Maybe because of entsize differences? (24 v 12)
I also noticed the 'rebased' addresses typically were identical with the upper bits being 'discarded'. ie 0x10000100007cc8
would become 0x100007CC8
So I thought, when I run into these scenarios where the offset would extend past end of file
I would discard the upper bits and then re-add the preferredLoadAddress
in an attempt to rectify this problem (preferredLoadAddress is re-added as an implementation detail to keep things working the same as the pre chained fixup workflow) Low and behold files that had failed to dump before would finally resolve missing symbols and stop crashing and burning, huzzah!
I apologize if any of my lingo isn't stated properly, this kind of bit/byte shifting chicanery has never been my strong suit, explaining this as best I can.
Another thing I realized when trying to do my normal course of header dump repos, was the usual tools (ldid, jtool) I use to dump entitlements from binaries were all coming up empty on *OS 15 and *OS 16 binaries. At first to rectify this I used a hacky bruteforce route by treating the files as pure text files and used NSScanner's to identify the app entitlements. Upon further analysis I realized there is a new section in the __TEXT segment labeled __entitlements. Turns out saving that section to a file is all that is necessary to dump entitlements off of binaries, I still havent fully deciphered how they used to get dumped, so I threw my old hacky string scanning code as a fallback for the time being, and added the -e
flag to dump entitlements as a new feature in classdump-c.
- Steve Nygard for the original class-dump
- DreamDevLost for his iOS port
- Derek Selander for this amazing writeup
- Qing Yang For his llios repo and related writeups
- Noah Martin For the linked writeup on
LC_DYLD_CHAINED_FIXUPS
- blacktop All that awesome golang code in ipsw and related work, helped me get a better understanding of fixup chains.
NOTE: The master branch is now obsolete, the macos branch works on both mobile OSes and macOS