macOS Code Signing for Patched Binaries
• Reverse Engineering
The Problem
When patching a macOS application binary (like modifying RobloxPlayer to disable purchase prompts), you'll quickly discover that modern macOS won't let you run modified binaries that still have their original code signature. The OS detects the mismatch and refuses to execute the binary.
But simply removing the signature isn't enough on macOS 15 and later - the system still refuses to launch unsigned binaries with cryptic errors.
The Journey
Step 1: Removing the Original Signature
First, verify the binary is signed:
codesign -d -vv "/Applications/Roblox.app/Contents/MacOS/RobloxPlayer"
You'll see output showing the developer's signature, authority chain, and team identifier. To remove it:
codesign --remove-signature "/Applications/Roblox.app/Contents/MacOS/RobloxPlayer"
Verify it's gone:
codesign -d "/Applications/Roblox.app/Contents/MacOS/RobloxPlayer"
# Output: code object is not signed at all
Step 2: The Launch Failure
Attempting to launch the unsigned binary results in:
Error Domain=RBSRequestErrorDomain Code=5 "Launch failed."
Error Domain=NSPOSIXErrorDomain Code=153 "Unknown error: 153"
Launchd job spawn failed
Error 153 indicates that macOS Gatekeeper or launchd is blocking the execution of the unsigned binary. Modern macOS versions are increasingly strict about running unsigned code.
Step 3: Ad-Hoc Re-Signing
The solution is to re-sign the binary with an ad-hoc signature. This tells macOS "yes, this binary is intentionally modified and I trust it":
codesign -s - -f --deep "/Applications/Roblox.app"
Breaking down the flags:
-s -- Sign with an ad-hoc signature (the dash means "no identity")
-f- Force - replace any existing signature
--deep- Sign nested code (frameworks, plugins, etc. within the app bundle)
Why This Works
An ad-hoc signature doesn't provide cryptographic verification of the code's origin (like a Developer ID does), but it does:
- Satisfy launchd's requirement that binaries have some form of signature
- Create a code directory hash that the OS can verify hasn't been tampered with after signing
- Allow the binary to pass basic security checks without needing a developer certificate
The ad-hoc signature essentially says "I, the local user, vouch for this binary" rather than "Apple and this developer vouch for this binary".
Verification
After ad-hoc signing, verify the new signature:
codesign -d -vv "/Applications/Roblox.app/Contents/MacOS/RobloxPlayer"
You'll see it now has a signature, but with no authority chain - just "Signature=adhoc".
Important Considerations
System Integrity Protection (SIP)
This technique works for applications in user-writable locations like /Applications. System binaries protected by SIP cannot be modified even with root privileges.
Gatekeeper
First launch may still trigger a Gatekeeper warning. You can bypass this via:
- Right-click → Open
- System Settings → Privacy & Security → "Open Anyway"
- Command line:
xattr -cr /Applications/Roblox.appto remove quarantine attributes
Updates
Any update to the application will replace your patched binary with the official version. You'll need to reapply patches and re-sign after each update.
Online Verification
Some applications perform additional integrity checks (comparing hashes with a server, verifying specific code sections, etc.). Ad-hoc signing won't help with those - you'd need to patch the verification routines as well.
Complete Workflow
The full process for patching and running a macOS binary:
- Make a backup:
cp -R /Applications/App.app /Applications/App.app.backup - Patch the binary (with Ghidra, hex editor, etc.)
- Remove original signature:
codesign --remove-signature /Applications/App.app/Contents/MacOS/Binary - Ad-hoc re-sign:
codesign -s - -f --deep /Applications/App.app - Launch and test