196の日記

セキュリティ系の勉強、その他開発メモとか雑談、忘れそうな計算式などを書き溜める場所になっています. githhubはUnity触っていた頃ものがメイン https://github.com/196kakinuma

アナライジングマルウェア 5章 カーネルモード(Ring0)で動作するマルウェアの解析

WinDbgカーネルモードデバッガ。ゲストOSとパイプで繋ぎ、デバッグを行う。

今回触れるものは(アナライジング・マルウェア ―フリーツールを使った感染事案対処 (Art Of Reversing) 出版社: オライリージャパン (2010/12/20) ISBN-10: 4873114551)を読んでの元です。


カーネルモード(Ring0)マルウェアの概要

大別すると以下の3つがある

  1. システムリソースの隠蔽を行うマルウェア
  2. システム内の制限を解除するマルウェア
  3. フルカーネルマルウェア

1はユーザモードのプロセスやファイル、オープンしているTCP/IPポートなどを隠蔽し、セットで実行されているユーザモードのマルウェアのプロセスや実行ファイルを隠蔽する。
2は本来カーネルがユーザモードのプロセスに設けている制限を解除することを目的としている。またプロセスに特権を付与したりも。
3悪意のある行動をほとんどカーネルモードで行う。Rustick,Srizbi. アンチウィルスソフトが検知しにくい。

SSDT Hooking

System Service Descriptior Table Hooking はWindows Sysinternalsのリソースを監視するツールでも利用されている代表的なカーネルモードでのフック手法。古典的だが実装が用意。ユーザモードのプロセスは通常、システムコールをラップしているkernel32.dll等のDLLが提供しているAPIを介してシステムコールを呼ぶ。SSDT Hookingを行う際、KiServiceTableの関数ポイントの値を自身がインジェクションしたコードを指す値の改ざんすることで特定システムコールの依田氏をフックする。インジェクションしたコード内では途中でオリジナルコードを呼び出すが、再びインジェクションしたコード内に戻ってくるのでその時に結果を改ざんして返すことで成立する。

f:id:thinline196:20180905000922p:plain

Runtime Patching(Inline Hooking)

SSDTは知識があれば簡単に検知できる。これはフックしたい関数自体を改ざんしSSDTと同じような効果を上げる。SSDTに含まれていないものやエクスポートされていない関数なども標的にできる。

  1. call orig_funcにより、orig_func関数が呼ばれEIPがorig_func関数の先頭アドレス(jmp hook_funcに改ざんされている)を指す
  2. orig_func関数の先頭でjmpし、hook_func関数へジャンプ。EIPはhook_func関数の先頭アドレス(push ebp)を指す
  3. 攻撃者はあらかじめorig_func関数の先頭5バイトの命令をあらかじめ確保しているバッファ@trampolineに保存しておく。攻撃者はインジェクションしたコードからこれを呼び出すことでorig_func関数を実行
  4. @trampoline直後にorig_func+5へジャンプするコードを配置。(mov xxx,xxx)を実行するように。
  5. orig_funcが完了しretが実行されるとtrampoline直後に戻る。
  6. 攻撃者はorig_funcの実行結果を改ざんするなどした後、retを実行し、最初のorig_func関数を呼び出した位置に戻る。


f:id:thinline196:20180905000943p:plain

IDT Hooking

IDTは割り込みを処理するための半ぢらへにポインタが格納されたデータ構造体で、割り込みの番号に応じて呼び出される割り込みハンドラが登録されている。フックできる箇所が割り込みハンドラのみに限られるため、上のものより柔軟性にかけるが、SSDTとは異なる処理の制御を奪えるため、キーロガーやメモリ上の値の隠蔽などに利用される。

通常の流れ

  1. 割り込みの発生を補足→IDTRレジスタからIDTのアドレスを取得
  2. 割り込み発生時の割り込み番号をインデックスとしてIDTから該当するエントリーを取り出す
  3. 該当エントリ(割り込みディスクリプタ)からLowOffsetとHighOffsetの値を取得し、割り込みハンドラのアドレスを計算
  4. EIPに割り込みハンドラのアドレスをセットして実行

以下に構造体を貼りましたが、書籍よりメンバの数が増えてます。。

typedef struct _IDTENTRY
{
    unsigned short LowOffset;
    unsigned short selector;
    unsigned char retention:5;
    unsigned char zero1:3;
    unsigned char gate_type:1;
    unsigned char zero2:1;
    unsigned char interrupt_gate_size:1;
    unsigned char zero3:1;
    unsigned char zero4:1;
    unsigned char DPL:2;
    unsigned char P:1;
    unsigned short HiOffset;
} IDTENTRY,*PIDTENTRY;

上のLowOffsetとHighOffsetを改ざんしてインジェクションしたコードを指すようにすることで、フックを可能にする。



IRP Hooking

IRP(I/O Request Racket)割り込みディスパッチテーブルはデバイスドライバごとに保持される関数ポインタ配列の1つ。Windows環境ではデバイスドライバに対して処理要求を出すと、I/OマネージャがIRPデータ構造を作成、デバイスドライバにIRPを渡す。デバイスドライバはIRPの中身を確認し、要求に応じて地震のテーブルに登録してあるハンドラを呼び出して、このIRPを処理。


攻撃者はターゲットのデバイスドライバのドライバオブジェクトを取得しIRPのテーブルに格納されている特定のIRPのハンドラへの関数ポインタをインジェクションしたコードのアドレスを指すように書き換える。




MSR Hooking (sysenter Hooking)

今まではカーネル領域のメモリ上の値を書き換えて、カーネルのフローを改ざんしていた。これはシステムレジスタの値を書き換える。ユーザモードアプリケーションがシステムコールを呼ぶ際に実行するsysenter命令のジャンプ先が格納されているMSR(Model Specific Register)の値を改ざんする。sysenter命令が実行されるときに参照されるMSRは、IA32_SYSENTER_CS(0x174),IA32_SYSENTER_ESP(0x175),IA32_SYSENTER_EIP(0x176)の3つ。
攻撃を行う場合、IA32_SYSENTER_EIPでセットされるEIPの値を、インジェクションしたコードを指すようにする。


DKOM

Dynamic Kernel Object Manipulationは本来常にOSによって変更が加えられる動的なデータ領域を改ざんする。今までの手法は、静的な場所が多く、目立ちやすかった。
Windowsカーネルはプロセス情報をEPROCESS構造体で管理している。プロセス1つに対してEPROCESS1つ生成される。全てのプロセス情報はEPROCESS構造体の双方向リンクリストで管理しているため、隠蔽したいプロセスを双方向リンクから外すことで、プロセスの隠蔽を測ることができる。これにより、タスクマネージャからプロセスの存在を確認できない。