SENTO NO OBOEGAKI

技術よりのメモやポエムを書いていきます。

MENU

Immunity DebuggerでWin32 APIのフックをやってみる

「Immunity Debuggerを使ってみる」でPyCommandデビューしたため、もっと実用的なそれっぽいことをやってみる。

環境

・Windows 10 Pro 64bit版

・Immunity Debugger v1.85

・Python 2.7.9

 

デバッグ対象

・C:\Windows\SysWOW64\notepad.exe

 

Win32 APIのフック

Immunity DebuggerではFastLogHookというオブジェクトが提供されており、簡単にフックをセットアップできる。フックをセットする一連のコードは次のようになる。

imm = immlib.Debugger()
fast = immlib.FastLogHook(imm)

fast.logFunction(address,num_arguments)     #フックポイントを定義
fast.logRegister(register)                  #フック時における特定のレジスタの値をログ出力
fast.logDirectMemory(address)               #フック時における一定のメモリオフセットをログ出力
fast.logBaseDisplacement(register,offset)   #レジスタから一定のオフセットに位置するデータをログ出力
fast.Hook()

メソッドFastLogHook()でフックポイントを設定できる。このメソッドはフックを設定すべきアドレスと捕捉すべき引数の数を受け取る。logRegister(),logDirectMemory(),logBaseDisplacement()が実際にログ出力するメソッドであり、状況によって使い分けることができる。

フックポイントに到達してログ出力メソッドが実行されると、捕捉された情報はFastLogHookオブジェクトが作成したアロケート済みメモリ領域に保存される。そのためフックの結果を取得する必要があり、それにはgetAllLog()というメソッドが使える。このメソッドは対象のメモリ領域の内容を解析して次の形のリストを返す。

[(hook_address,(arg1,arg2,...,argN)),...]

 

呼出し規約による違い

ここまでの説明ではFastLogHook()を使用すると書いたが、Win32 APIではstdcall呼出し規約が使われているためSTDCALLFastLogHook()というメソッドを使う必要がある。ただし、使い方は上で説明したFastLogHook()と変わらない。

 

実際にPyCommandを作成してみる

ここではRtlAllocateHeap関数をフックポイントに設定し、3つのパラメータを捕捉しログ出力する。

RtlAllocateHeapのプロトタイプは次のようになっている。

PVOID RtlAllocateHeap(
  _In_     PVOID  HeapHandle,
  _In_opt_ ULONG  Flags,
  _In_     SIZE_T Size
);

実際にスクリプトを書くと次のようになる。

import immlib

def main(args):
    imm = immlib.Debugger()

    fast = imm.getKnowledge("my_hook")
    if fast:                                                      #すでにフックが設定されていたら結果をログ出力
        hook_list = fast.getAllLog()
        for a in hook_list:
           imm.log("RtlAllocateHeap(0x%08x,0x%08x,0x%08x)" % (a[1][0],a[1][1],a[1][2]))
        return "Logged : %d hook hits." % len(hook_list)
        
    imm.pause()                                                   #デバッガを停止
    addr_rtlallocate = imm.getAddress("ntdll.RtlAllocateHeap")    #ntdll.dll!RtlAllocateHeapのアドレスを取得
    imm.log("ntdll.RtlAllocateHeap : 0x%08x" % addr_rtlallocate)
    
    #ここからフックの構築
    fast = immlib.STDCALLFastLogHook(imm)
    fast.logFunction(addr_rtlallocate,3)
    fast.Hook()                                                   #フックの設定
    imm.addKnowledge("my_hook",fast,force_add=1)                  #あとから結果を取得できるようにフックオブジェクト(fast)を保存

    return "Hook set, press F9 to continue the process."

addKnowledge()メソッドはPythonのオブジェクトをタグ(1つ目のパラメータ)をつけてナレッジデータベースに追加するメソッドで、getKnowledge()で、追加したPythonオブジェクトをタグを指定して取り出すことができる。上のコードではフックが設定されているかどうかをこのメソッドで確かめている。

このスクリプトを次の手順で実際に使ってみる。

  1. Immunity Debuggerを起動しnotepad.exeを開く
  2. コマンドバーに!myhookのように感嘆符に続けてスクリプト名を入力しENTERキーを押下
  3. F9キーでnotepad.exeのウィンドウが表示されるまで進める
  4. 2と同様にスクリプトを実行

上の手順通りに進めるとログウィンドウ([View] -> [Log])に次のような結果が表示され、RtlAllocateHeapのパラメータを捕捉できていることが分かる。

f:id:sentoneibisu:20151003181106p:plain

 

おまけ:フック後のアセンブリコードを見てみる

RtlAllocateHeapの逆アセンブルコードは次のようになっている。

f:id:sentoneibisu:20151003190347p:plain

しかしフック後は先頭の5バイト(MOV EDI,EDI;PUSH EBP;MOV EBP,ESP)がJMP命令(JMP 060F0008)に書き換えられている。このジャンプ先がフックコードである。

f:id:sentoneibisu:20151003190507p:plain

CPUウィンドウで[Ctrl-G] -> 060f0008を入力しJMP先のアドレスを見てみると、以下のフックコードが生成されているのが分かる。

f:id:sentoneibisu:20151003190603p:plain

上のコードでは060F0008PUSHAD,060F0078POPADによって元のレジスタの値を保存している。

上のフックコードの処理内容を簡単にまとめると次のようになる。

  1. 060F0000から(捕捉したRtlAllocateHeapのパラメータが保存される)メモリ領域へのアドレスをEDIに格納する
  2. 060F0042MOV EAX,DWORD PTR SS:[ESP+C]PUSHADで保存したESPの値をEAXに格納する
  3. 060F0049MOV EAX,DWORD PTR DS:[EAX+4]で1つ目のパラメータ([ESP+4])をEAXに格納する
  4. 060F004FSTOS DWORD PTR ES:[EDI]で1つ目のパラメータをEDIの指す先に格納する
  5. 2~4と同様に2つ目、3つ目のパラメータもメモリ領域に格納する
  6. 最後に060F0000に格納されたメモリ領域へのアドレスを更新する

捕捉したRtlAllocateHeapのパラメータが保存されるメモリ領域を確認してみる。

16進ダンプウィンドウで[Ctrl-G] -> 060f0000を入力すると、赤枠部分に目的のアドレスが格納されているのが分かる。

f:id:sentoneibisu:20151003191046p:plain

16進ダンプウィンドウで[Ctrl-G] -> 060f6b24を入力して少し上にスクロールすると、ピンク枠部分に捕捉したRtlAllocateHeapのパラメータが保存されているのが分かる。

f:id:sentoneibisu:20151003191342p:plain

060F0079から最後までの命令は次のようになっており、フックコードへのJMP命令で書き換えられていた5バイトの命令を実行した後、元のRtlAllocateHeapにリターンしているのが分かる。

MOV  EDI,EDI
PUSH EBP
MOV  EBP,ESP
PUSH 7752DA95
RETN