This post will walk you through the beginnings of macOS reversing. Specifically, it will focus on techniques for reversing macOS and iOS internals with incomplete source code. In my last post, I discussed tips 1 and 2:
- Have a basic understanding of how projects are generally structured.
- Understand how to read and use version control (Git) and GitHub.
Now, I will discuss techniques for binary analysis.
- Tip 3 – Using binary markers: Binary markers are unique strings or identifiers embedded within compiled binaries. They can help trace the origin of a binary by revealing details such as the source code, project name, or version information.
- Tip 4 – Matching binary code to source functions: Identify how compiled functions correlate with their related source code to help understand the binary’s behavior and context.
- Tip 5 – Analyzing syscalls and inter-process communication (IPC)Â messages: During signature-based analysis, understanding system calls and IPC patterns can reveal how a binary interacts with its environment.
- Tip 6 – Using visual tooling: This provides a different view of the data you’re examining, making it easier to understand.
Tips 4 and 5, and tip 6 were retroactively separated into new posts due to length. See the links above.
Let’s start with…
Dealing with incomplete and inconsistent sources (e.g., headers and missing files)
I often find that files or functions are missing entirely, or they reference non-existent code. Sometimes I can patch around this; other times, I’m stuck. Even if I manage to compile the code, the resulting binary might lack features present in Apple’s original builds.
To learn more, here is a GIANT gist, containing a list of things that can go wrong: “Incomplete and inconsistent source examples in C.”
strings
So, how do I identify the relevant source code for a binary? I might locate markers indicating the project name and build number via strings.
bash$ strings crash_mover
moveLogsAtPath
Could not open and lock %s: %s. Proceeding with copy anyway.
Extensions
...
For instance, running strings on /bin/ls might reveal a line like:
johndoe@JD-MBA-Silver ~ % strings /bin/ls
@(#)PROGRAM:ls PROJECT:file_cmds-457.120.3
|@$FreeBSD$
strings
This information indicates which source package to search for on Apple’s open-source site. Even when no direct project label is found, I might still find hints from file paths or source filenames embedded in the binary, such as host.c from BIND9, indicating that it uses OSS components.
Once I’ve located the main source code, I can try compiling it…
With Xcode, using either command-line via xcodebuild or the Xcode GUI. Mismatched Xcode versions can introduce build errors due to stricter compilers or removed build flags. Sometimes, parts of the source package are simply missing, and Apple no longer provides them.

To see this IRL, you’ll want to navigate to the “Releases” section, which allows you to filter by macOS, iOS, developer tools, etc. Unfortunately, for iOS, Apple releases fewer packages… only things like WebKit or libiconv, which implements the iconv API and other tools for converting text between different character encodings.
This doesn’t mean iOS lacks open source components; only that Apple chooses not to release much of it. However, because macOS and iOS share so much code, you can often find “equivalent” versions in macOS releases.
Currently, macOS 15 is the latest available release
26 was only in beta at the time I wrote this.
A variety of components are included: libc, the dynamic linker, security tools, malloc, and the kernel source code (xnu). I am interested in components like libc, libmalloc, and xnu, because they impact system behavior, memory allocation, and the kernel.
You can download these source packages either as tarballs or view them on Apple’s GitHub. The GitHub repositories are not Apple’s internal development logs; they only contain the final code dumps / binaries, with no developer comments or detailed changelogs. You won’t see the rationale behind each change, only the resulting code.
Now, I am at the point where I am focused on bridging the gap.
Reversing macOS & iOS internals with incomplete source code
And how do we do that? Through binary markers! A binary marker is a unique string or identifier embedded within a compiled binary that can be used to trace the source code, project name, or version information.
🌸👋🏻 Join 10,000+ followers! Let’s take this to your inbox. You’ll receive occasional emails about whatever’s on my mind—offensive security, open source, boats, reversing, software freedom, you get the idea.
Binary markers
Tip 3 is to find relevant source code by using markers in the compiled binaries.
Many binaries embed the project name and version string somewhere in them. For example, running the what command or strings on macOS’s /bin/ls reveals an identifier:
johndoe@JD-MBA-Silver ~ % what /bin/ls
/bin/ls:
PROGRAM:ls PROJECT:file_cmds-457.120.3
Copyright (c) 1989, 1993, 1994
PROGRAM:ls PROJECT:file_cmds-457.120.3
Copyright (c) 1989, 1993, 1994
From this, we learn that the ls utility is part of the file_cmds package (file_cmds-457.120). Using that hint, we can go to Apple’s open source site or GitHub and locate the file_cmds source package that contains the implementation of ls.
In general, search for strings like “PROGRAM:<name> PROJECT:<package>-<version>” within binaries to identify the corresponding open source package.
Once the package name is known, I can often find its source in Apple’s GitHub, or download it from the Apple OSS website. But we can go “lower-level” too.
macOS vs iOS source availability
As we know from my last post, macOS and iOS share a common core (Darwin), so “low-level” components of iOS are covered by the macOS (Darwin) source releases too. In Apple’s Open Source portal, there are separate(d) listings for macOS and iOS, but these often overlap. iOS releases typically include the kernel and other Unix-level components.

Apple’s UIKit.
However, device-specific or higher-level iOS frameworks are not open-sourced. For instance, I doubt I would find UIKit (a framework for building and managing GUIs) or other ~very proprietary~ iOS-specific frameworks in any open source release. Even components present on both platforms might be missing or only released in part for macOS.
A common scenario is that an iOS daemon or framework is equivalent to a macOS component whose source is available. Here, I can study the macOS source as a reference for iOS behavior.
That said, it is important to be mindful of differences. Apple may have iOS-specific code paths (especially where hardware or sandbox differences apply) that aren’t reflected in the published source. In this case, I use the open source code as a starting point, but I know there is more to learn.
Common missing and partial components

corecrypto internal use license agreement.
Some known omissions in Apple’s open source dumps include:
- CoreFoundation
- CFNetwork
launchd: Any analysis of launchd’s internals beyond that point has to be done via reversing.- dyld (Dynamic Linker): There are versions of dyld open sourced, but building the latest dyld from source is yikes.
- Kernel (XNU) for iOS: open-sourced but without the iOS-specific assembly and some drivers.
- Corecrypto: Apple’s cryptography library is released under a very restrictive license (not truly open source in spirit). For example, Apple’s
corecryptodownload requires agreement that I will not redistribute and will delete it after 90 days. This limits its utility for any sort of collaborative research. - Proprietary frameworks: Many frameworks (especially GUI, media, or Apple-specific services) are completely closed. I need to use help (e.g.,
class-dump, disassembly) to understand these.
When the source is missing, my approach shifts to reversing the binaries directly.
Signature-based analysis (tip #4 and tip #5)
Given the length of this post, I separated this section into its own post: signature-based analysis for reversing. It outlines how signature-based analysis uses known byte sequences, source headers, and binary diffing tools (think BinDiff and Diaphora) to match functions in Apple binaries to open-source code, enabling faster identification of functionality or patched vulns. I also explore how to analyze syscalls, Mach IPC, and Objective-C/C++ metadata to understand binary behavior in macOS/iOS components like XNU, KEXTs, and userland daemons.
Binary extraction with visual tooling (tip #6)
Given the length of this post, I separated this section into its own post: binary extraction with visual tooling. It outlines how I extract and analyze macOS/iOS binaries using strings, otool, nm, and class-dump for structure, symbols, and Objective-C interfaces. I also cover extracting libraries from dyld_shared_cache using DyldExtractor or jtool, and using iOS Simulator binaries as an alternative source for symbol-rich libraries.
How do these techniques help in bridging the gap between open-source availability and actual usability within Apple’s ecosystem?
In this section, I’ll summarize the main challenges involved in compiling and working with Apple’s open-source code. These challenges include:
- Missing dependencies
- Custom build tools
- Code signing and SIP implications
- Debugging and patching:
- Strategies for modifying or rebuilding open-source daemons
- Setting realistic expectations (trying to determine when researching X is actually worth your time)
For each challenge, I’ll explain how these techniques have helped me in the context of my previous post.
Challenges in compiling and patching Apple OSS code
In my last post, I covered this general problem: Having source code is great, but what if I want to compile it myself or modify it?
I sometimes try to build Apple’s open source components to experiment or apply patches. However, this can range from straightforward to practically impossible, depending on the project.
🌸👋🏻 Join 10,000+ followers! Let’s take this to your inbox. You’ll receive occasional emails about whatever’s on my mind—offensive security, open source, boats, reversing, software freedom, you get the idea.
Build environment mismatch
Apple’s open source releases are not guaranteed to be buildable on a stock macOS system. In fact, Apple has noted that the Darwin open source is provided as a reference and is “not set up to build the included projects” in many cases.
The projects might rely on Apple-internal build settings, SDKs, or missing components. For example, I might download the source for an Apple daemon only to discover it references (what I think are) private headers, missing libraries, or Xcode configuration files that were not released publicly.
To fix this, I can use:
- Tip 3 (binary markers): Instead of needing a perfect build, I can confirm which OSS package a binary came from (e.g.,
file_cmds-457.120if we cite the earlierwhatexample) and just reference that code. This avoids chasing impossible build environments. - Tip 4 (match functions): Even if I can’t compile, I can line up source functions against the actual binary in IDA/Ghidra/whatever and study behavior.
OSS doesn’t have to build to be useful. I treat it as an annotated pseudocode for the real binary.
Dependency hell

Apple’s software often has intertwined dependencies.
When I try to compile something like launchd or dyld from the released source, I might find it depends on a specific build of XNU or some libraries that are also open source but require building first, and those might also have dependencies.
Some helpful techniques would be:
- Tip 4 (signature matching/diffing): binary diffing lets me spot which parts of
launchd/dyldchanged across versions, without needing to rebuild dependencies. - Tip 6 (visual tooling):
otool -Lornmshows linked dylibs, so I can study dependency graphs without compiling.
Binary analysis lets me observe dependencies on site, instead of attempting to reproduce Apple’s internal build tree. However, it’s not uncommon to spend days (at least for me, lol) fixing dependency issues and tweaking Makefiles or Xcode projects to get something to compile if it can be done at all.
Version skew
The open source snapshot corresponds to a specific OS release, and building it on a later macOS/Xcode can introduce problems. APIs may have changed or been removed. For instance, building a component from macOS 10.15 source on macOS 12 could fail because certain headers or kernel interfaces it expects are no longer present.
Sometimes I need to use the Xcode toolchain from the era of the source. There have been cases where researchers (fG!) had to install an older macOS SDK or even patch the code to compile on a newer SDK.
Patching and replacing system components
Assuming I do manage to compile a component, using it to replace or patch the system’s version is another challenge. For user-space tools and simpler daemons, this can be feasible in a controlled environment in theory. For example, I could compile a custom version of a command-line tool (like cp or launchctl), and run it locally for testing.
With daemons, I might be able to run a debug instance of an open-source daemon on a non-production system by disabling SIP and codesigning requirements.
However, replacing components like launchd or dyld on a live system does not seem to be realistic. These are tightly integrated and protected by the OS. At best, I might use a patched version in a VM or a development device where I can disable security features.
Debugging with source vs binary
A more practical approach than full replacement is to use open source code as a reference while debugging the real binary. This is honestly the main reason I wrote this article since many of these techniques I struggle with.
My hope is that my abilities and knowledge will improve the more I learn and document. The challenge for my readers is… how much mental energy and time do you want to put into consuming my research? I strive to publish meaningful work, but I don’t want to pretend my thoughts are always straightforward, concise, or even correct…
For example, if I suspect a bug in a daemon, I could compile a debug build of the open source version and run it in a user environment to observe its behavior, or step through it in a debugger to understand logic, then apply what I learned to the actual closed-source binary (setting breakpoints at analogous locations, etc.).
Another strategy is to use the open source to identify what log messages or error codes mean, then trigger the behavior on a real system and watch logs or crash reports to confirm.
Since many system daemons log to the unified logging system, having the source lets me interpret log entries. For instance, a log like "[FooDaemon] ERROR 0x17 by mach_port XXX" could be deciphered by searching the open source for where that log is printed and seeing what code 0x17 refers to.
Realistic targets for custom builds
In general, command-line tools and UNIX utilities from Apple’s open source are the easiest to build and experiment with.
Many of these (like the contents of file_cmds, shell_cmds, network_cmds, etc.) compile with less fuss, and I can compare my binary’s behavior against the stock one.
On the other hand, large system services (LaunchDaemons) and the kernel are usually not practically buildable or replaceable. For example, while Apple releases XNU source, building my own XNU and running it requires a custom kernel boot setup, which on macOS is “locked down” without a special entitlement or a developer Mac.
It’s “locked down” by multiple, overlapping protections (software and hardware) designed so you can’t just build-and-swap a kernel or core system service on a Mac without either Apple’s cooperation or exploiting vulnerabilities. Jailbreaking in the sense of “I’ll just flip a switch and replace the kernel” is not realistic AFAIK for macOS on production hardware.
Projects like launchd were removed from open source precisely when it became so entwined with other closed components that a standalone build wouldn’t be very useful. Likewise, dyld (the dynamic linker) source releases exist, but Apple’s internal build prolly uses specific entitlements and code signing that make a custom dyld hard to use for loading system binaries.
🌸👋🏻 Join 10,000+ followers! Let’s take this to your inbox. You’ll receive occasional emails about whatever’s on my mind—offensive security, open source, boats, reversing, software freedom, you get the idea.
Troubleshooting builds
If you attempt to build Apple’s code, be prepared for a lot of trial and error. A few tips:
- Read any README or notes that come with the source; Apple sometimes includes info (e.g., “use xcodebuild with SDK 10.x” or notes about required environment variables).
- Search online for others who tried to build the same component. Often, I will find Stack Overflow questions or GitHub gists with patches. Building
dyld_shared_cache_util, for instance, folks have shared the modifications needed to compile it on some Xcode releases. - When building kernel-related projects or drivers, remember to codesign the resulting kext (with a certificate or disable kext signing) if I actually load them for testing.
In short, compiling Apple’s open source is usually only realistic for research and not for production use. It is helpful to step through in a debugger, but direct usage is limited. An Apple engineer noted that Darwin open source is a general resource, not a turnkey build system. Knowing this, I use the source as a guide and the binary as the authority.
Conclusion
If you want to understand macOS and iOS internals, Apple’s open-source code is one of the best places to start. It’s incomplete, but useful. The best approach is to combine the published source with the current binaries and debugging: the source gives intent, the binary gives reality, and debugging ties them together. Good resources include GitHub mirrors, macOS internals books, and blogs; useful tools include Hopper/IDA/Ghidra for reverse engineering, and LLDB for symbolication and debugging, and utilities like class-dump for introspection.
If you enjoyed this post on reversing macOS using open source as a guide, consider reading Unlocking macOS Internals: A Beginner’s Guide to Apple’s Open Source Code.
Sources, thanks, and where to learn more
Research and blogs
- Observations of Apple Open Source – Andrew Hyatt’s Blog
- Kernel Symbolication – Blacktop
- Preserving Your Digital Sandcastles with an IDA Plugin – Cra0
- Extract the system libraries on macOS Big Sur – Jeff Johnson
- Reversing Apple’s syslogd bug – fG!
- Fresh Apples: Researching New Attack Interfaces on iOS and OSX + and slides + Play fuzzing machine: Hunting iOS/macOS kernel vulnerabilities automatically and smartly – Lilang Wu and Moony Li
- Fun and Games with Mac OS X and iPhone Payloads, Black Hat Europe 2009 – Charlie Miller and Vincenzo Iozzo
- SusanRTTI: an IDAPython plugin for viewing run-time type information – Tyler Colgan
Tools and repos
- ghidra_kernelcache: a Ghidra framework for iOS kernelcache reverse engineering – 0x36
- OSS Distributions – Apple
- Libiconv – Apple
- ida_kernelcache: An IDA Toolkit for analyzing iOS kernelcaches – bazad
- MachOView – gdbinit
Apple documentation
- Core Foundation
- CFNetwork
- IOServiceOpen(_:_:_:_:)
- OSMetaClass
- UIKit
- Mac OS X Manual Page For syslog(3)
- Missing Sources in Apple OSS Distributions


You must be logged in to post a comment.