第 6 章 新しい Windows への適応性に関する検討 67
6.4 Alkanet10 の実装
図 6.5 syscallフックとsysretフック
6.4.1 システムコールのフック
前述のように,x64版Windowsのシステムコールは,syscall命令を用いて KiSystem-Call64 に遷移し,KiSystemServiceExit 内の sysret 命令により復帰する.Alkanet10 では,それぞれsyscall フック, sysretフックとしてブレイクポイントを設定する.
図6.5に Alkanet10 における2つのフックポイントを示す.Windows Vista 以降の Windowsでは,ASLR (Address Space Layout Randomization)によりシンボルのマッ プ位置が固定でなくなっているため,システムコールの出入口のアドレスの取得が困 難となっている.そこで,syscall命令のジャンプ先を設定するIA32 LSTAR MSRか
らKiSystemCall64のアドレスを取得する.さらに,シンボル情報により,カーネルの
先頭からKiSystemCall64までのRVA (Relative Virtual Address)が取得できるため,
取得したKiSystemCall64のアドレスとRVAの値から,カーネルのベースアドレスが
特定できる.KiSystemServiceExitについても,図6.5のようにKiSystemCall64のア ドレスとシンボル情報から得られるRVAから計算できる.同様に,データ構造解釈機 能などで使用する特定のシンボルについても,そのシンボルのRVAとカーネルベース アドレスを用いて実際にマッピングされたアドレスを算出できる.
6.4. Alkanet10の実装 75
6.4.2 システムコールの特定
前述のように,Windows では,x86,x64ともにシステムコール発行時にシステム コール番号が EAX レジスタに格納される.したがって, syscall フックでは,EAX レジスタからシステムコール番号を取得することができる.一方,sysret実行時には,
RAXレジスタはシステムコールの戻り値を保持しているため,sysretフックでは,他 の方法でシステムコール番号を取得する必要がある.そこで,sysretフックでは,ス レッドオブジェクトが持つ SystemCallNumber メンバやAlkanetXPと同様に戻り先 スタブなどから番号を取得する.
6.4.3 プロセスとスレッドの特定
Alkanetでは,Windowsの持つPCRを利用し,システムコールを発行したスレッド
の情報を取得する.6.3.2項で述べたとおり,x64版Windows におけるPCRはカーネ ルGSセグメントの先頭に存在し,そのベースアドレスはIA32 GS BASE MSR もし くはIA32 KERNEL GS BASE MSRによって示される.Alkanet10は, 上記のMSR から PCR のアドレスを取得する.また,PCRやスレッドオブジェクト,プロセスオ ブジェクトなどのデータ構造は,Windowsの各バージョンごとにそれぞれ細かな差異 があるため,シンボル情報を元に Windows 10 x64 にあったデータ構造解釈機能を実 装する.
6.4.4 引数と戻り値の取得
6.3項で述べたように,システムコール引数は,システムコールの第 1引数から第4 引数は,R10,RDX,R8,R9レジスタ,第5引数以降はスタックに与えられる.した
がって,syscall フックでは,これらのレジスタおよびスタックより取得が可能である.
一方,sysret フックでは,上記レジスタの値は既に揮発して別の値となっているた
め,第1 引数から第4 引数が取得できない.そこで,syscall フック時に上記レジスタ の値を保存しておくことで,sysretフック時に第 1引数から第 4引数の取得を可能と する.なお,第5引数以降はsyscallフック時と同様にスタックより取得が可能である.
また,sysretフック時には,RAXレジスタからシステムコールの戻り値も取得する.
Alkanetは,引数に与えられるポインタや OS 固有のデータ構造を解釈し,マルウェ
ア解析に必要な情報を取得する.当該機能については,監視対象とするシステムコー
ル個別の処理や引数に与えられるデータ構造ごとにWindows 10 x64向けの実装が必 要となる.
6.4.5 WOW64 システムコールのトレース
6.3.4項で述べた2つのケースは,ともに syscall命令でシステムコールを発行する.
そのため,WOW64システムコールのフックは,通常のシステムコールと同様に行え る.また,システムコールの発行元プロセスがWOW64プロセスであることは,プロ セスオブジェクトを確認することで判定できる.これにより,WOW64システムコー ルと通常のシステムコールを区別できる.
前述のケースのうち,ケース(1)のものは,通常のシステムコールと同様に情報の 取得が可能である.一方,ケース(2)では,Win64側のスタブを経由しないため,シ ステムコール番号の上位16ビットが設定されたままシステムコールに至る.そこで,
Alkanet10 でも取得したシステムコール番号の上位16ビットはWOW64で行われた
エミュレーション方法の特定に利用し,下位16ビットを本来のシステムコール番号と して取り扱う.
また,sysret命令の戻り先である CpupSyscallStub は,各システムコール用に用 意されたスタブではないため,スタブを参照する方法ではシステムコール番号を得 ることができない.そこで,スタックに積まれているWOW64への戻りアドレスを
取得し,WOW64側のスタブから番号を取得する.ただし,エミュレーションの過程
で複数回システムコールが呼ばれる場合もあるため,スレッドオブジェクトが持つ
SystemCallNumber を優先して用いる.なお,引数は,エミュレーション関数によっ
て通常のシステムコールと同様にカーネルに受け渡される.したがって,通常のシス テムコールと同様に取得が可能である.