皆様こんにちは!医科歯科デンタルのSpicaと申します。
今回はiOSにおけるHooking(ネイティブ関数)の方法とその対策について書いていきます。
必要なもの
1.脱獄済みiOS
2.Theos
3.IDA, Hopper,Cutter等のdeassembler
複合化されたバイナリ取得
CrackerXI iGameGod Frida-dump等様々な方法があります。複数の方法があり割と調べると出てくると思うので割愛します。
ASLRスライド
ASLR はAddress Space Layout Randomisationの略で、今日のほぼすべてのシステムに見られるセキュリティです。これは、アプリが起動されるたびにそのメモリ アドレス空間をランダム化することで、メモリ内でプログラムの特定の部分を見つけることを困難にすることを目的としています。
ARM64バイナリではASLRが適用されるためdeassemblerのオフセットと実際のバイナリオフセットはASLRの値分だけずれます。
※vm_WriteDataは定義内でASLRが自動的にずれるので計算する必要がないです。
#import <mach-o/dyld.h>
uint64_t getRealOffset(uint64_t offset){
return _dyld_get_image_vmaddr_slide(0)+offset;
}
バイナリ解析
IDAなどお好みのdeassemblerで複合化されたバイナリを解析します。
かなり時間を要するため睡眠中に放置することを勧めます。
armの命令を読むのに以下のサイトが私的には良かったです。
Hooking
いよいよHookingです。Tweak.xmの最初では以下のようにインポートしてください。
#import <vm_writeData.h>
#import <substrate.h>
オフセットで関数をフックするときには
MSHookFunction((void *)getRealOffset(0x100000000), (void *)func, (void **)&org_func);
関数
funcに上書きしたい処理を持つ関数org_funcは元の処理を保つ関数MSHookFuntionのvoidはvoid型にキャストして渡すものなので常にvoidfuncとorg_funcの戻り値の型にはその関数が返す戻り値の型を指定
引数
必ず最初にthisポインタを含める
アプリ内で定義されるクラスのポインタの場合: void* として受け取る
アプリ内で定義されるクラスのインスタンスの場合: 自分で定義する
アプリ内の関数を呼び出す
アプリ内の関数において関数は引数としてthisのみをとり、返り値はアプリ内で定義されているexempligratia型のポインタであるとします。その時には返り値はvoid型ポインタで受け取ります。
例
void* (*exempligratia)(void* this_) = (void* (*)(void*))getRealOffset(0x123456789);
(void* (*)(void*))はvoid*を返り値に持ち、引数にvoid*を持つ関数ポインタでキャストすることを意味します。これは関数ポインタですが、呼び出すときは普通の関数のように呼び出せます。
対策方法
対策方法はいろいろ思い浮かびますが一番簡単に行えるのは脱獄できないバージョンを要求することです。脱獄検知等で対処するという手もありますが攻撃者と堂々巡りになります。攻撃者との戦いは大企業であるappleに任せましょう。
終わりに
いかがでしたか?
他にも書きたいことがあるのでまた次回書くかもです。