MachObfuscator is a programming-language-agnostic Mach-O apps obfuscator (for Apple platforms).
โ โ means feature is completed, โ โ means feature is todo/in-progress.
- โ Mach-O iOS
- โ Mach-O macOS
- โ iOS NIBs (including storyboards)
โ ๏ธ macOS NIBs (including storyboards) โ does not support bindings yet- โ MOMs (CoreData)
- โ Mach-O watchOS
- โ Mach-O tvOS
- โ Bitcode
- โ automatic code re-signing (need to re-sign all images manually, see resign.sh)
MachObfuscator is a binary symbolic obfuscator. What does it mean? There are a few important terms:
- Obfuscator โ a tool which makes software hard to be reverse engineered.
- Binary obfuscator โ a type of obfuscator that operates on machine code, not on a source code.
- Symbolic obfuscator โ a type of obfuscator that obfuscates only symbol names, does not change program control-flow.
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 [-qvhtD] [-m mangler_key] APP_BUNDLE
Obfuscates application APP_BUNDLE in-place.
Options:
-h help screen (this screen)
-q quiet mode, no output to stdout
-v verbose mode, output verbose info to stdout
-t obfuscate methType section (objc/runtime.h methods may work incorrectly)
-D MachOViewDoom, MachOView crashes after trying to open your binary (doesn't work with caesarMangler)
-m mangler_key select mangler to generate obfuscated symbols
Available manglers by mangler_key:
caesar - ROT13 all objc symbols and dyld info
realWords - replace objc symbols with random words (dyld info obfuscation supported)
In a great simplification, MachObfuscator:
- looks for all executables in the app bundle,
- searches recursively for all dependent libraries, dependencies of those libraries and so on,
- searches for all NIB files in the app bundle,
- discriminates obfuscable files (files in the app bundle) and unobfuscable files (files outside the app bundle),
- collects Obj-C symbols, export tries and import lists from the whole dependency graph,
- creates symbols whitelist and symbol blacklist (symbols used in unobfuscable files),
- mangles whitelist symbols, export tries and import lists using selected mangler,
- replaces symbols in obfuscable files,
- clears sections which are optional,
- saves all the files at once.
MachObfuscator changes following Mach-O sections:
__TEXT, __objc_classname
โ mangles symbol names__TEXT, __objc_methname
โ mangles symbol names__TEXT, __objc_methtype
โ (optional, enabled with-t
parameter) fills whole section with0
s__TEXT, __swift3_typeref
,__TEXT, __swift4_typeref
โ fills whole section with0
s__TEXT, __swift3_reflstr
โ fills whole section with0
sLC_DYLD_INFO_ONLY
โ mangles export tries and binding listsLC_SYMTAB
โ fills whole section with0
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:
- Play with MachOView, open some binaries and try to feel Mach-O layout.
- Read
/usr/include/mach-o/loader.h
from any macOS. - Read
Mach+Loading.swift
from MachObfuscator repo.
This project is licensed under the MIT License - see the LICENSE file for details.