To demonstrate how to use Substrate to build an extension, we will now walk through the implementation of a concrete example: an extension that modifies the color of numerous interface components to become shades of fuchsia. This extension is useless, but has the advantage of being immediately noticeable.
This example uses Substrate's runtime API and macros. Most developers actually use Logos, a popular preprocessor that takes a declarative hook syntax and generates code that directly uses Substrate.
The code for UIColor is in a library called UIKit, which has the bundle identifier com.apple.UIKit.
Filter = { Bundles = ("com.apple.UIKit"); };
$ plutil -convert binary1 FuchsiaExample.plist
Our filter is in a separate file, so we only need declare a function for our initialization code.
#include <CydiaSubstrate/CydiaSubstrate.h> // this is a macro that uses __attribute__((__constructor__)) MSInitialize { // ... code to run when extension is loaded }
The implementation of the method is replaced at the Objective-C runtime level. We thereby specify our replacement implementation using the calling convention of an Objective-C IMP.
To call the previous implementation, we use the function pointer provided when we hooked.
Here, we call through to the original and modify the result, removing all green from the color and jacking up the red (yielding shades of fuchsia).
UIColor *(*_UIColor$init)(id self, SEL _cmd, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); UIColor *$UIColor$init(id self, SEL _cmd, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha ) { return _UIColor$init(self, _cmd, 1, 0, blue, alpha); } MSInitialize { MSHookMessageEx([UIColor class], @selector(initWithRed:green:blue:alpha:), (IMP) &$UIColor$init, (IMP) &_UIColor$init); }