この記事は iOS Jailbreaking Advent Calendar 2015 の4日目の記事です。
ターゲット
SIMBLもそうですが、当然dylibをロードしたいプロセスとそうでないプロセス、つまりターゲットがあります。
CydiaSubstrateではdylibと同名のplistファイルに所定の書式で記述しておくことでターゲットのフィルタリングがされます。
フォーマット
OpenStep方式でフルに書くと以下のようになります。※厳密にはCoreFoundationVersionキーを使う場合はOpenStep形式では小数点のある数値を扱えないのでXMLで書く必要があります。
{
Filter = {
Bundles = ("com.apple.mobilesafari", "com.apple.springboard");
Executables = ("backboardd", "mediaserverd");
Classes = ("WKWebView", "AVPlayer");
CoreFoundationVersion = (1140.00, 1240.00);
Mode = "Any";
Flags = 2;
};
}
Bundles
NSBundle.mainBundle.bundleIdentifier
で得られるStringでターゲットを記述します。Arrayなので複数をターゲットに出来ます。
Executables
NSBundle.mainBundle.bundleIdentifier
が設定されていないプロセス(おもにデーモン)をターゲットにする場合にその実行ファイル名を記述します。Arrayなので複数をターゲットに出来ます。
Classes
プロセスに記述したクラスがロードされているかどうかでフィルタリングします。NSClassFromString()がNULLかどうかになります。Arrayなので複数をターゲットに出来ます。
Mode
その昔は前述の3種類のフィルター、Bundles, Executables, Classesは1種類のみを利用する事を想定されていました。判断順序はExecutables -> Bundles -> Classesの順なので例の場合backboarddとmediaserverdのみがターゲットとなりSpringBoardやSafariそしてWKWebViewかAVPlayerクラスがロードされているプロセスへはロードされない実装でした。
これを組み合わせて使えるようにModeパラメータが追加されました。取りうる値は"Any"のみで、これが指定されていると3種類のフィルターのどれかに合致すればロードされます。
CoreFoundationVersion
先日説明したkCFCoreFoundationVersionでiOSバージョンに応じてフィルタリング出来ます。Arrayで値を1つか2つ記述します。
1つの場合はgreater判定のみで上述の例だと1140.00 > kCFCoreFoundationVersionNumber
になります。
2つ記述がある場合はgreater thanとless equalになり
1140.00 > kCFCoreFoundationVersionNumber && 1240.00 <= kCFCoreFoundationVersionNumber
になります。
1140.10がiOS 8.0で1240.10がiOS 9のバージョンなのでそれぞれ少し値を減らす事で例ではiOS 8.xがターゲットになります。
Flags
隠しパラメータのFlagsキー。2を指定するとロードせずにスキップしてくれます。デバッグ用でしょうか。Stringで記述するとエラーになりますのでIntegerで書く必要があります。
<key>Flags</key>
<integer>2</integer>
注意
元祖CoreFoundationVersionフィルター機能がこのターゲットフィルターの記述ですが、PreferenceLoaderにおけるCoreFoundationVersionフィルターはgreater than, less equalではなくgreater equal, less thanとなっていますのでご注意を。個人的にはPreferenceLoaderの形式の方が使いやすいと思います。