Posted at

Meta class hooking.

More than 3 years have passed since last update.

この記事は iOS Jailbreaking Advent Calendar 2015 の7日目の記事です。

メタプログラミング的なのかはよくわかってない。


シチュエーション

iOS x用にこんなコードのtweakがあったとする。


Tweak.xm

%hook AClass

- (void)sampleMethod
{
// some code...
}
%end

そしてiOS yがリリースされ、AClassがリネームされBClassになっていた場合、というシチュエーションにとる手法の話。


愚直方式

処理を関数に外出しして%hookは愚直に記載していく方法。

%origを使う場合はout of %hook blockエラーになるので#defineのCマクロにしてpreprocessをlogo preprocessより先に実行する方法もあるけど、結構使いにくいのでオススメ出来ません。

方法としてこれはこれでアリです。function内のコードは複数iOSで利用される事を想定しないとアップデートしたら前のiOSで動かなくなるのでそこには注意。


Tweak.xm

static void function()

{
// some code...
}

%hook AClass
- (void)sampleMethod
{
function();
}
%end

%hook BClass
- (void)sampleMethod
{
function();
}
%end



meta hook

hookするクラスを動的にすりゃあいいんだろう!のための記法がtheosにはあります。

こんなコードになります、ジャーン!


Tweak.xm

%group MetaHookGroup

%hook MetaClass
- (void)sampleMethod
{
// some code...
}
%end
%end // End of metaHookGroup

%ctor
{
Class $hookClass = %c(AClass) ?: %c(BClass);
%init(MetaHookGroup, MetaClass = $hookClass);
}


これでAClassが存在する場合は-[AClass sampleMethod]がhookされ、BClassが存在する場合は-[BClass sampleMethod]hookされます。

この場合もsome code...の部分は前バージョンに対してリグレッションをおこさないよう留意する必要はあります。

この手法は複数バージョンにわたって1バイナリでサポートする時にそこそこ利用します。5プロジェクトに1つぐらいで。