x84-64環境でシステムコールをフックする

はじめに

x86-64環境において,syscall命令実行時のエントリポイントを書き換えることで,システムコールをフックする. システムコールを呼び出す従来の手法では,int 0x80命令による割り込みが用いられていたが,x86-64環境ではではより高速なsyscall命令が用いられる.
ユーザ空間からsyscall命令が発行されると,カーネルは,MSRレジスタのMSR_LSTARに設定されている値をRIPにセットする. この値が,システムコールのエントリポイントのアドレスとなっており,システムコールが実行される. システムコールのエントリポイントでは,スタックポインタの切り替えや,ユーザ空間のレジスタの退避を行い,システムコール番号や引数を元に対応するシステムコールが呼び出される. syscall命令によるシステムコールをフックするには,MSRレジスタのMSR_LSTARの値を任意の値に書き換えることで実現する. なお,MSRレジスタの読み書き込みは,特権命令であるrdmsr/wrmsr命令でのみ行える.

設計

前述の通り,syscall命令によるシステムコール呼び出しでは,MSRレジスタのMSR_LSTARの値がシステムコールのエントリポイントを表す.
システムコールをフックするためには,このMSR_LSTARの値を任意の値に書き換えれば良い.
今回は,MSR_LSTARの値をトランポリンのアドレスに書き換え,プロセスの生成/終了に関わるシステムコールを検知する.その後,正規のエントリポイントから命令を実行させ,システムコールを継続させる.

まとめると以下のようになる.

トランポリンにおける処理

実装

SyscallHooking

参考

Linuxシステムコール徹底ガイド