โ๏ธโ๏ธโ๏ธ
MachObfuscator does not currently support binaries with minimum Deployment Target >= 12.X,
MachObfuscator does not currently run on macOS Deployment Target >= 12.X.
MachObfuscator is a programming-language-agnostic Mach-O apps obfuscator (for Apple platforms).
โ โ means feature is completed, โ โ means feature is todo/in-progress.
MachObfuscator is a binary symbolic obfuscator. What does it mean? There are a few important terms:
MachObfuscator transforms symbols in Mach-O files directly. Mach-O format is used mainly on Apple platforms as a machine code container for executables and libraries. MachObfuscator doesn't need access to the app source code in order to obfuscate it.
Let's see MachObfuscator obfuscating SampleApp.app
application:
Results can be seen by opening app's main executable in MachOView. MachOView shows obfuscated ObjC selectors:
and obfuscated ObjC class names:
Only sample changes are shown above. MachObfuscator changes more Mach-O sections.
$ ./MachObfuscator
usage: ./MachObfuscator [-qvdhtD] [-m mangler_key] APP_BUNDLE|FILE
Obfuscates application bundle in given directory (APP_BUNDLE) or Mach-O file (FILE) in-place.
Options:
-h, --help help screen (this screen)
-q, --quiet quiet mode, no output to stdout
-v, --verbose verbose mode, output verbose info to stdout
-d, --debug debug mode, output more verbose info to stdout
--dry-run analyze only, do not save obfuscated files
--erase-methtype erase methType section (objc/runtime.h methods may work incorrectly)
-D, --machoview-doom MachOViewDoom, MachOView crashes after trying to open your binary (doesn't work with caesarMangler)
--swift-reflection obfuscate Swift reflection sections (typeref and reflstr). May cause problems for Swift >= 4.2
--objc-blacklist-class NAME[,NAME...] do not obfuscate given classes. Option may occur mutliple times.
--objc-blacklist-class-regex REGEXP do not obfuscate classes matching given regular expression. Option may occur mutliple times.
--objc-blacklist-selector NAME[,NAME...] do not obfuscate given selectors. Option may occur mutliple times.
--objc-blacklist-selector-regex REGEXP do not obfuscate selectors matching given regular expression. Option may occur mutliple times.
--preserve-symtab do not erase SYMTAB strings
--erase-section SEGMENT,SECTION erase given section, for example: __TEXT,__swift5_reflstr
--erase-source-file-names PREFIX erase source file paths from binary. Erases paths starting with given prefix
by replacing them by constant string
--replace-cstring STRING replace arbitrary __cstring with given replacement (use with caution). Matches entire string,
--replace-cstring-with STRING adds padding 0's if needed. These options must be used as a pair.
--skip-all-frameworks do not obfuscate frameworks
--skip-framework framework do not obfuscate given framework
--obfuscate-framework framework obfuscate given framework (whitelist for --skip-all-frameworks)
-m mangler_key,
--mangler mangler_key select mangler to generate obfuscated symbols
--skip-symbols-from-sources PATH
Don't obfuscate all the symbols found in PATH (searches for all nested *.[hm] files).
This option can be used multiple times to add multiple paths.
--skip-symbols-from-list PATH
Don't obfuscate all the symbols from the list in PATH (symbols need to be new-line
separated). This option can be used multiple times to add multiple lists. `strings`
output can be used as a symbols list.
--report-to-console report obfuscated symbols mapping to console
Development options:
--xx-no-analyze-dependencies do not analyze dependencies
--xx-dump-metadata dump ObjC metadata of images being obfuscated
--xx-find-symbol NAME[,NAME...] find given ObjC symbol in all analysed images
Available manglers by mangler_key:
caesar - ROT13 all objc symbols and dyld info
realWords - replace objc symbols with random words and fill dyld info symbols with numbers
MachObfuscator can be easily integrated with fastlane builds:
obfuscate.sh
script available for fastlane.obfuscate.sh
to obfuscate your IPA:
MACH_OBFUSCATOR
environment variable.obfuscate.sh
can also resign the application if you pass certificate name or pass NO_RESIGN
to resign later using fastlane._obf.ipa
suffix. Here is an example fastlane configuration assuming that compiled MachObfuscator and the script are in main project directory, IPA was built to ./exported_ipa/#{TARGET_NAME}.ipa
and you want final products in ./app
directory:
# Copy unobfusated app
rsync(
destination: "./app/#{IPA_NAME}_unobfuscated.ipa",
source: "./exported_ipa/#{TARGET_NAME}.ipa"
)
# Obfuscate
# sh runs in fastlane directory not main project directory
sh("MACH_OBFUSCATOR=../MachObfuscator ../obfuscate.sh ../exported_ipa/#{TARGET_NAME}.ipa NO_RESIGN -v | tee ../app/obfuscation.log")
# Copy obfuscated app
rsync(
destination: "./app/#{IPA_NAME}.ipa",
source: "./exported_ipa/#{TARGET_NAME}.ipa_obf.ipa"
)
# Sign obfuscated app
resign(
ipa: "./app/#{IPA_NAME}.ipa",
signing_identity: "[IDENTITY]",
provisioning_profile: {
"#{APP_IDENTIFIER}" => "#{PROVISION_PATH}"
}
)
In a great simplification, MachObfuscator:
MachObfuscator changes following Mach-O sections:
__TEXT, __objc_classname
โ mangles symbol names__TEXT, __objc_methname
โ mangles symbol names__TEXT, __objc_methtype
โ mangles symbol names or optionally (enabled with --erase-methtype
parameter) fills whole section with 0
s__TEXT, __swift3_typeref
, __TEXT, __swift4_typeref
, __TEXT, __swift5_typeref
โ fills whole section with 0
s__TEXT, __swift3_reflstr
, __TEXT, __swift4_reflstr
, __TEXT, __swift5_reflstr
โ fills whole section with 0
sLC_DYLD_INFO_ONLY
โ mangles export tries and binding listsLC_SYMTAB
โ fills whole section with 0
s__TEXT, __swift*
are sections used by Swift's reflection mechanism (Mirror
). Mirror
works even after clearing those sections, just returns less detailed data. LC_SYMTAB
is used by lldb
.
MachObfuscator does not affect crash symbolication because dSYMs are generated during compilation โ that is before obfuscation.
If you have any idea for improving MachObfuscator, let's chat on Twitter (@kam800).
If you want to write some code, but don't feel confortable with Mach-O, I suggest doing some preparations first:
/usr/include/mach-o/loader.h
from any macOS.Mach+Loading.swift
from MachObfuscator repo.This project is licensed under the MIT License - see the LICENSE file for details.