Windows 10でDynamoRIOを使ってみた
DynamoRIOを使ってみたので忘れる前にメモを書いておく。 DynamoRIOはランタイムコード操作 (変換・コード挿入など) を行うためのツールである。いわゆる、Dynamic Binary Instrumentation(DBI)ツールの一つという位置づけで知られている。 DBIツールとしてIntel Pinも有名だが、Windows10で動かない(?)ようなので今回はWindows10でも動作するDynamoRIOを使ってみることにした。
環境
- Windows 10 Pro 64bit
- Visual Studio Community 2015
>systeminfo OS 名: Microsoft Windows 10 Pro OS バージョン: 10.0.14393 N/A ビルド 14393 OS ビルドの種類: Multiprocessor Free システムの種類: x64-based PC プロセッサ: 1 プロセッサインストール済みです。 [01]: Intel64 Family 6 Model 58 Stepping 9 GenuineIntel ~1900 Mhz
インストール
インストール方法について詳しくはここを参照してほしい。 今回はビルド済みのバイナリを含んだzip版をDirect Download Linksからダウンロードする。 サンプルコードのビルド用にCMakeとVisual Studioもインストールしておく。
サンプルコードの実行
ユーザはDynamoRIOが提供しているAPIを使用してDynamoRIOクライアントを作成できる。DynamoRIO本体と組み合わせる形で使用される自作のプログラムのことをDynamoRIOクライアントと呼んでいるらしい。Windowsの場合これをDLLにコンパイルして使うことになる。
まずは最初からsamples/
以下に含まれているサンプルコードを動かしてみる。サンプルコードを実行する場合は-c
パラメータの後にdllファイルのパスを指定する。
>bin32\drrun.exe -c samples\bin32\opcodes.dll -- notepad
opcodes.dllは実行されたオペコードをカウントする機能が実装されており、実行するとnotepadが立ち上がり、ウィンドウを閉じると実行されたオペコードTop15が表示される。
ツールの実行
サンプルコードとは別にDynamoRIOにはいくつかのツール1が内蔵されている。これを実行するには-t
パラメータの後にツール名を指定する。
>bin32\drrun.exe -t drstrace -- notepad
drstraceはシステムコールをトレースし、ログに書き出す。
NtQueryVirtualMemory arg 0: 0xffffffff (type=HANDLE, size=0x4) arg 1: 0x002ea880 (type=void *, size=0x4) arg 2: 0x0 (type=int, size=0x4) arg 3: 0x02abf4f8 (type=<struct>*, size=0x4) arg 4: 0x1c (type=unsigned int, size=0x4) arg 5: 0x02abf4d4 (type=unsigned int*, size=0x4) succeeded => arg 3: <NYI> (type=<struct>*, size=0x4) arg 5: 0x02abf4d4 => 0x1c (type=unsigned int*, size=0x4) retval: 0x0 (type=NTSTATUS, size=0x4) NtQueryVirtualMemory arg 0: 0xffffffff (type=HANDLE, size=0x4) arg 1: 0x002ea880 (type=void *, size=0x4) arg 2: 0x3 (type=int, size=0x4) arg 3: 0x02abf514 (type=<struct>*, size=0x4) arg 4: 0x14 (type=unsigned int, size=0x4) arg 5: 0x00000000 (type=unsigned int*, size=0x4) succeeded => arg 3: <NYI> (type=<struct>*, size=0x4) arg 5: 0x00000000 (type=unsigned int*, size=0x4) retval: 0x0 (type=NTSTATUS, size=0x4) NtQueryVirtualMemory arg 0: 0xffffffff (type=HANDLE, size=0x4) arg 1: 0x002ea880 (type=void *, size=0x4) arg 2: 0x2 (type=int, size=0x4) arg 3: 0x02abf54c (type=<struct>*, size=0x4) arg 4: 0x212 (type=unsigned int, size=0x4) arg 5: 0x00000000 (type=unsigned int*, size=0x4) succeeded => arg 3: <NYI> (type=<struct>*, size=0x4) arg 5: 0x00000000 (type=unsigned int*, size=0x4) retval: 0x0 (type=NTSTATUS, size=0x4) NtQueryInformationProcess arg 0: 0xffffffff (type=HANDLE, size=0x4) arg 1: 0x24 (type=int, size=0x4) arg 2: 0x02abf520 (type=<struct>*, size=0x4) arg 3: 0x4 (type=unsigned int, size=0x4) arg 4: 0x00000000 (type=unsigned int*, size=0x4) succeeded => arg 2: <NYI> (type=<struct>*, size=0x4) arg 4: 0x00000000 (type=unsigned int*, size=0x4) retval: 0x0 (type=NTSTATUS, size=0x4)
サンプルコードのビルド
ここではマニュアルを参考に適当なサンプルコードsample_cli.cを書いてビルドしてみる。 sample_cli.cは実行された基本ブロックの数をカウントする最低限のコードで、エラー処理は含めていない。
sample_cli.c
#include "dr_api.h" static void event_exit(void); static void bbcount(); static dr_emit_flags_t event_bb(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating); static unsigned int global_count = 0; DR_EXPORT void dr_client_main(client_id_t id, int argc, const char *argv[]) { dr_enable_console_printing(); dr_register_exit_event(event_exit); dr_register_bb_event(event_bb); } static void event_exit(void) { dr_printf("bb count: %d\n", global_count); } static void bbcount() { global_count++; } static dr_emit_flags_t event_bb(void *drcontext, void *tag, instrlist_t *bb, bool for_trace, bool translating) { dr_insert_clean_call(drcontext, bb, instrlist_first_app(bb), (void *)bbcount, false, 0); return DR_EMIT_DEFAULT; }
CMakeLists.txt
add_library(sample_cli SHARED sample_cli.c) find_package(DynamoRIO) if(NOT DynamoRIO_FOUND) message(FATAL_ERROR"DynamoRIO package required to build") endif(NOT DynamoRIO_FOUND) configure_DynamoRIO_client(sample_cli)
フォルダ階層(ビルド前)
フォルダは以下の構成になっている。ここでは作成したVSプロジェクトと自作のサンプルコード置き場としてmybuild/
とmysamples/
を事前に作っている。
sample_cli.cとCMakeLists.txtはmysamples/
内のsample_cli/
以下に置いている。
C:. ├─bin32 ├─bin64 ├─cmake ├─docs ├─drmemory ├─dynamorio ├─ext ├─include ├─lib32 ├─lib64 ├─logs ├─mybuild #VSプロジェクト置き場 ├─mysamples #自作サンプルコード置き場 │ └─sample_cli │ ├─CMakeLists.txt │ └─sample_cli.c ├─samples └─tools
サンプルコードのビルド手順
>cd mybuild >mkdir sample_cli && cd sample_cli >cmake -DDynamoRIO_DIR="..\..\cmake" ..\..\mysamples\sample_cli >(作成されたProject.slnをVisual Stduioで開いてソリューションのビルドを実行) #Debugフォルダにtest_cli.dll、test_cli.lib、その他もろもろが作成される
フォルダ階層(ビルド後)
C:. ├─bin32 ├─bin64 ├─cmake ├─docs ├─drmemory ├─dynamorio ├─ext ├─include ├─lib32 ├─lib64 ├─logs ├─mybuild │ └─sample_cli │ └─Debug │ ├─sample_cli.dll │ └─sample_cli.lib ├─mysamples │ └─sample_cli │ ├─CMakeLists.txt │ └─sample_cli.c ├─samples └─tools
自作サンプルコードの実行
>bin32\drrun.exe -c mybuild\sample_cli\Debug\sample_cli.dll -- notepad bb count: 10147879
参考リンク
- DynamoRIO Dynamic Instrumentation Tool Platform
- How To Build · DynamoRIO/dynamorio Wiki · GitHub
- Downloads · DynamoRIO/dynamorio Wiki · GitHub
- GitHub - DynamoRIO/dynamorio: Dynamic Instrumentation Tool Platform
- DynamoRIO API: The DynamoRIO API
-
実際にはサンプルコードより大規模で洗練されたDynamoRIOクライアントである。↩
CTF for ビギナーズ 2016 弘前 Write-up
CTF for ビギナーズ 2016 弘前が、私の所属する研究室から徒歩8秒の講義室で開催されたので、参加してきました。結果は1100ptsで4位(同点が結構いましたが)でした(1位は3人で1400ptsでした)。
最後のCTF演習のwrite-upだけ簡単に書きます(※最後のbin300は時間内に解けてません)。
Misc100: README
問題文に書かれたctf4b{}形式のflagをコピペして終わり。
Forensics100: みてみよう
与えられたpcapファイルをWiresharkで開いてみてみると、HTTPでflag.pngをダウンロードしているのを見つけたのでそのファイルを抽出。開いて見ても真っ白い画像だったので、バイナリエディタで眺めてみたらflagがあった。
Forensics200: エクスポートできるかな?
与えられたpcapファイルを見ると、FTPでPNGデータをやりとりしていたので、エクスポートして開くとflagが書いてた。
Forensics200: ICMP?
与えられたpcapファイルを見ると、ICMPのrequestとreplyがひたすら続いていたので眺めてると、何やら明らかにサイズがでかいICMPパケットがいくつかある。ということでデータ部分をよく見ると、なぜかHTTPリクエストとHTTPレスポンスが入っている。HTTPリクエストでflag.txtを要求しているので、レスポンスのボディを見てみるとbase64っぽい文字列がありデコードするとflagが得られた。
Binary100: HiddenFlag
strings bin100_1 | grep ctf4b
でflagが出た。
Binary200: 復習
講義でやった内容(5つのkeyを探す問題)のkeyが3つバージョン。与えられたバイナリ内の3つの関数Stage1~Stage3の戻り値(eax)がそのままkeyになるので、命令を辿っていけば分かる。
echo -en "23\n945\n-46\n" | ./bin200_1
でflagが出た。
Binary200: ASCII
とりあえず与えられたバイナリを実行してみるとInput flag>>
と出てくる。objdumpで逆アセンブルしてみるとcheck_flagという関数があるので見てみると次のように命令が並んでいる。
mov BYTE PTR [ebp-0x28],0x63 mov BYTE PTR [ebp-0x27],0x74 mov BYTE PTR [ebp-0x26],0x66 mov BYTE PTR [ebp-0x25],0x34 mov BYTE PTR [ebp-0x24],0x62 mov BYTE PTR [ebp-0x23],0x7b mov BYTE PTR [ebp-0x22],0x63 mov BYTE PTR [ebp-0x21],0x30 mov BYTE PTR [ebp-0x20],0x6d mov BYTE PTR [ebp-0x1f],0x70 mov BYTE PTR [ebp-0x1e],0x34 mov BYTE PTR [ebp-0x1d],0x72 mov BYTE PTR [ebp-0x1c],0x31 mov BYTE PTR [ebp-0x1b],0x6e mov BYTE PTR [ebp-0x1a],0x67 mov BYTE PTR [ebp-0x19],0x5f mov BYTE PTR [ebp-0x18],0x77 mov BYTE PTR [ebp-0x17],0x31 mov BYTE PTR [ebp-0x16],0x37 mov BYTE PTR [ebp-0x15],0x68 mov BYTE PTR [ebp-0x14],0x5f mov BYTE PTR [ebp-0x13],0x31 mov BYTE PTR [ebp-0x12],0x6e mov BYTE PTR [ebp-0x11],0x70 mov BYTE PTR [ebp-0x10],0x75 mov BYTE PTR [ebp-0xf],0x37 mov BYTE PTR [ebp-0xe],0x7d mov BYTE PTR [ebp-0xd],0x0
ASCIIっぽい値と文字列の終端っぽい0x0を格納しているのでこれをASCIIに直したらflagが出た。
Binary300: HiddenFlag -returns-
とりあえず与えられたバイナリを実行してみると
HiddenFlag returns You cannot get flag! Haha
と言われる。objdumpで逆アセンブルしてみるとmain関数は文字列をputsで出力するだけで終わっている。しかし、main以外にgenflagという関数が一つあり、関数名からここでflagを生成しているっぽい。
08048514 <genflag>:
8048514: 55 push ebp
8048515: 89 e5 mov ebp,esp
8048517: 56 push esi
8048518: 53 push ebx
8048519: 83 ec 40 sub esp,0x40
804851c: 65 a1 14 00 00 00 mov eax,gs:0x14
8048522: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
8048525: 31 c0 xor eax,eax
8048527: c6 45 df 04 mov BYTE PTR [ebp-0x21],0x4
804852b: c6 45 e0 b2 mov BYTE PTR [ebp-0x20],0xb2
804852f: c6 45 e1 0f mov BYTE PTR [ebp-0x1f],0xf
8048533: c6 45 e2 47 mov BYTE PTR [ebp-0x1e],0x47
8048537: c6 45 e3 33 mov BYTE PTR [ebp-0x1d],0x33
804853b: c6 45 e4 84 mov BYTE PTR [ebp-0x1c],0x84
804853f: c6 45 e5 7f mov BYTE PTR [ebp-0x1b],0x7f
8048543: c6 45 e6 dd mov BYTE PTR [ebp-0x1a],0xdd
8048547: c6 45 e7 44 mov BYTE PTR [ebp-0x19],0x44
804854b: c6 45 e8 bd mov BYTE PTR [ebp-0x18],0xbd
804854f: c6 45 e9 d6 mov BYTE PTR [ebp-0x17],0xd6
8048553: c6 45 ea 98 mov BYTE PTR [ebp-0x16],0x98
8048557: c6 45 eb ad mov BYTE PTR [ebp-0x15],0xad
804855b: c6 45 ec 98 mov BYTE PTR [ebp-0x14],0x98
804855f: c6 45 ed d2 mov BYTE PTR [ebp-0x13],0xd2
8048563: c6 45 ee 36 mov BYTE PTR [ebp-0x12],0x36
8048567: c6 45 ef 14 mov BYTE PTR [ebp-0x11],0x14
804856b: c6 45 f0 f1 mov BYTE PTR [ebp-0x10],0xf1
804856f: c6 45 f1 26 mov BYTE PTR [ebp-0xf],0x26
8048573: c6 45 f2 85 mov BYTE PTR [ebp-0xe],0x85
8048577: c6 45 f3 1b mov BYTE PTR [ebp-0xd],0x1b
804857b: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0
8048582: e8 49 fe ff ff call 80483d0 <srand@plt>
8048587: c7 04 24 16 00 00 00 mov DWORD PTR [esp],0x16
804858e: e8 0d fe ff ff call 80483a0 <malloc@plt>
8048593: 89 45 d8 mov DWORD PTR [ebp-0x28],eax
8048596: c7 45 d4 00 00 00 00 mov DWORD PTR [ebp-0x2c],0x0
804859d: eb 21 jmp 80485c0 <genflag+0xac>
804859f: 8b 55 d4 mov edx,DWORD PTR [ebp-0x2c]
80485a2: 8b 45 d8 mov eax,DWORD PTR [ebp-0x28]
80485a5: 8d 1c 02 lea ebx,[edx+eax*1]
80485a8: 8d 55 df lea edx,[ebp-0x21]
80485ab: 8b 45 d4 mov eax,DWORD PTR [ebp-0x2c]
80485ae: 01 d0 add eax,edx
80485b0: 0f b6 30 movzx esi,BYTE PTR [eax]
80485b3: e8 38 fe ff ff call 80483f0 <rand@plt>
80485b8: 31 f0 xor eax,esi
80485ba: 88 03 mov BYTE PTR [ebx],al
80485bc: 83 45 d4 01 add DWORD PTR [ebp-0x2c],0x1
80485c0: 8b 45 d4 mov eax,DWORD PTR [ebp-0x2c]
80485c3: 83 f8 14 cmp eax,0x14
80485c6: 76 d7 jbe 804859f <genflag+0x8b>
80485c8: 8b 55 d4 mov edx,DWORD PTR [ebp-0x2c]
80485cb: 8b 45 d8 mov eax,DWORD PTR [ebp-0x28]
80485ce: 01 d0 add eax,edx
80485d0: c6 00 00 mov BYTE PTR [eax],0x0
80485d3: 8b 45 d8 mov eax,DWORD PTR [ebp-0x28]
80485d6: 8b 4d f4 mov ecx,DWORD PTR [ebp-0xc]
80485d9: 65 33 0d 14 00 00 00 xor ecx,DWORD PTR gs:0x14
80485e0: 74 05 je 80485e7 <genflag+0xd3>
80485e2: e8 a9 fd ff ff call 8048390 <__stack_chk_fail@plt>
80485e7: 83 c4 40 add esp,0x40
80485ea: 5b pop ebx
80485eb: 5e pop esi
80485ec: 5d pop ebp
80485ed: c3 ret
80485ee: 66 90 xchg ax,ax
さらっと見てみると、先ほどの問題と同じようにmov BYTE PTR [ebp-0xYY],0xZZ
のような命令が並んでいる。しかし、ASCIIではない。そこでもう少し詳しく見ていくと、どうやらrand()で得られる乱数と1byteずつxorして、malloc()で確保した領域に入れているっぽい。ということで、gdbを使用しmainで実行を止めた後、eipをgenflagのアドレスに書き換えて、ループが終わったあたりまで実行し、malloc()で確保した領域を表示してみたらflagが出た。
$ gdb -q bin300 (gdb) b *main (gdb) run (gdb) set $eip=*genflag (gdb) u *0x80485d6 (gdb) x/s $eax
感想
今回初めて「CTFの講義」を聴きましたが、知らなかったこともいろいろあり勉強になりました。webの講義も受けていたのにweb問を1問も解けなかったのが残念でした。久しぶりのCTFでしたが全体的に難しすぎない良い感じの問題が多かったので楽しめました。同じ大学の同期や後輩も参加していましたが、みんな楽しめたようで良かったです。
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オブジェクトをタグを指定して取り出すことができる。上のコードではフックが設定されているかどうかをこのメソッドで確かめている。
このスクリプトを次の手順で実際に使ってみる。
- Immunity Debuggerを起動し
notepad.exe
を開く - コマンドバーに
!myhook
のように感嘆符に続けてスクリプト名を入力しENTERキーを押下 - F9キーで
notepad.exe
のウィンドウが表示されるまで進める - 2と同様にスクリプトを実行
上の手順通りに進めるとログウィンドウ([View] -> [Log]
)に次のような結果が表示され、RtlAllocateHeapのパラメータを捕捉できていることが分かる。
おまけ:フック後のアセンブリコードを見てみる
RtlAllocateHeapの逆アセンブルコードは次のようになっている。
しかしフック後は先頭の5バイト(MOV EDI,EDI;PUSH EBP;MOV EBP,ESP
)がJMP命令(JMP 060F0008
)に書き換えられている。このジャンプ先がフックコードである。
CPUウィンドウで[Ctrl-G] -> 060f0008
を入力しJMP先のアドレスを見てみると、以下のフックコードが生成されているのが分かる。
上のコードでは060F0008
のPUSHAD
,060F0078
のPOPAD
によって元のレジスタの値を保存している。
上のフックコードの処理内容を簡単にまとめると次のようになる。
060F0000
から(捕捉したRtlAllocateHeapのパラメータが保存される)メモリ領域へのアドレスをEDI
に格納する060F0042
のMOV EAX,DWORD PTR SS:[ESP+C]
でPUSHAD
で保存したESP
の値をEAX
に格納する060F0049
のMOV EAX,DWORD PTR DS:[EAX+4]
で1つ目のパラメータ([ESP+4]
)をEAX
に格納する060F004F
のSTOS DWORD PTR ES:[EDI]
で1つ目のパラメータをEDI
の指す先に格納する- 2~4と同様に2つ目、3つ目のパラメータもメモリ領域に格納する
- 最後に
060F0000
に格納されたメモリ領域へのアドレスを更新する
捕捉したRtlAllocateHeapのパラメータが保存されるメモリ領域を確認してみる。
16進ダンプウィンドウで[Ctrl-G] -> 060f0000
を入力すると、赤枠部分に目的のアドレスが格納されているのが分かる。
16進ダンプウィンドウで[Ctrl-G] -> 060f6b24
を入力して少し上にスクロールすると、ピンク枠部分に捕捉したRtlAllocateHeapのパラメータが保存されているのが分かる。
060F0079
から最後までの命令は次のようになっており、フックコードへのJMP命令で書き換えられていた5バイトの命令を実行した後、元のRtlAllocateHeapにリターンしているのが分かる。
MOV EDI,EDI PUSH EBP MOV EBP,ESP PUSH 7752DA95 RETN
Immunity Debuggerを使ってみる
Immunity Debuggerとは
高機能なGUIユーザーモードデバッガ。Pythonによる機能拡張が可能。
以下のリンクからダウンロードできる(はず)
http://debugger.immunityinc.com/
メインインタフェース
Immunity Debuggerのメインインタフェースは次の5つの区画で構成されている。
①プロセスのアセンブリコードを表示するウィンドウ
②各種レジスタを表示するウィンドウ
③メモリの16進ダンプを表示するウィンドウ
④スタックを表示するウィンドウ
⑤コマンドバー
PyCommandとは
Immunity Debuggerの内部で動かせるPythonスクリプト。ここでは、簡単なPyCommandを作成して実際に動作させてみる。
PyCommandは次のコードのように、必ず一つのパラメータ(PyCommandに渡される引数のリスト)を受け取り、文字列を返す必要がある。
import immlib def main(args): imm = immlib.Debugger() return "PyCommand Executed!"
PyCommandを実行させるためには、Immunity Debuggerのインストールディレクトリ中のPyCommandsというディレクトリにスクリプトを保存し、Immunity Debuggerのコマンドバーで感嘆符に続けてスクリプト名を入力(!<スクリプト名>
)する。このとき、拡張子は入力しない。
簡単なPyCommandを作成してみる
環境
・Windows 10 Pro 64bit版
・Immunity Debugger v1.85
・Python 2.7.9
デバッグ対象
・notepad.exe
Immunity Debuggerは64bitアプリケーションには対応していないため、ここではC:\Windows\SysWOW64*1\notepad.exeをデバッグ対象とする。
モジュールntdll.dll内の関数を列挙するスクリプトは次のように書ける。
import immlib def main(args): imm = immlib.Debugger() #immlib.Debuggerをインスタンス化 ntdll = imm.getModule("ntdll.dll") #モジュールオブジェクトを返す addr_ntdll = ntdll.getBaseAddress() #ベースアドレスを取得 imm.log("================================") imm.log("Address of ntdll.dll : 0x%08x" % addr_ntdll) imm.log("================================") func_list = imm.getAllFunctions(addr_ntdll) #関数のアドレスのリストを返す for func in func_list: imm.log("0x%08x" % func) return "F I N I S H !!!"
Immunity DebuggerのAPIリファレンスについてはインストールディレクトリ中のDocumentation\Refを参照のこと。
出力結果はLogウィンドウ([View] -> [Log]
)に出力される。
*1:Windows 32bit On Windows 64bit
セキュリティ・キャンプ全国大会2015に行ってきたお話
4泊5日のキャンプに行ってきたので学んできたことや感想をまとめます。
(何かまずいこと書いていたら教えてください)
キャンプ1日目
半日あれば青森県から千葉県へ余裕で着けそうだったため、前泊はせずに当日朝5時に起床して行きました。
起きた
— セント (@sentoneibisu) 2015, 8月 10
空の旅では丁度窓側で良い席だったため写真を撮ったりして旅行(?)を楽しみました。
来たぜ!都会! pic.twitter.com/QUWt1Xhr1r
— セント (@sentoneibisu) 2015, 8月 11
羽田に到着し迷子になりつつバスに乗り、会場近くの海浜幕張駅へ。
バスの中ではTwitterのTL上に常に存在していた「友利奈緒」をググったり景色を眺めたりしていました。
— セント (@sentoneibisu) 2015, 8月 11
そんなこんなで会場のクロス・ウェーブ幕張に10時45分に到着!
ついに pic.twitter.com/57fAElqyiX
— セント (@sentoneibisu) 2015, 8月 11
緊張しながら会場に入るとすでに到着していた参加者がちらほら。
楽しそうに談笑していました。
誰だコイツ...って感じのコワイ目で見られたのは一生忘れません(※冗談です)。みんな優しい目で迎えてくれました!
そこでコミュ障を発揮しつつ名刺交換をしたりワイワイしました。
受付を済ませたあとは一旦ホールに移動し、名刺交換などで軽く交流したのち食堂でランチセッションでした。
昼食を済ませた後は開講式・オリエンテーションと続き、経済産業省の方やIPAの会長さん、講師主査の上野さんからのお話などがありました。
まもるくん
そして、今回スペシャルゲストにあの、まもるくんが遥々まもりの国から来てくれました。
\キャー!/ \ダレ?/ \スゴーイ!/ \カワイー!/ と、すごい盛り上がっていたように思いました。
一部のまもるくんを知らない人のためにプロフィールを載せときます。
情報処理推進機構:IPA 情報セキュリティ 標語・ポスターコンクール:まもるくん-PROFILE-
セキュリティ基礎
まもるくんからのお話(?)の後は遂に上野さんによる「セキュリティ基礎」の講義が始まりました。『情報漏えいはなぜ起こるのか』、『メールの添付ファイルによるウイルス被害が発生しないようにするための対策』などをグループで話し合い発表をしました。
グループワーク
セキュリティ・キャンプ全国大会では毎年グループワークという取り組みがあり、何人かでグループを作り、調査対象のテーマを決めて取り組みます。テーマは次の4つのどれかを選べとのこと。
テーマ1 組織的犯行対策(事前、事後など)
テーマ2 ヒアリングマラソン:技術人材のゴール像とステップ構想
テーマ3 リサーチマラソン:セキュリティ情報収集の効果的な方法とアクション
テーマ4 技術ビジョン構想:セキュアなものづくりを実現するには
私自身はテーマ1を選びました。ここでそれぞれ選んだテーマごとにいくつかのグループを作りグループワークのメンバーが決定しました。
後で某チューターさんに話を聞くと、過去のグループワークは漠然と「セキュリティについて」くらいのテーマだったようで、今回は具体的なテーマ設定になっているから難しそうとのこと。実際取り組んで分かりましたが、テーマが絞られている分、題材選びでオリジナリティを出すのが難しくかなり苦労しました。
特別講義(1)
最初は『2020年を迎えるみなさんへ』という題で東京オリンピックパラリンピック競技大会組織委員会テクノロジーサービス局局長の方からのお話がありました。
現代のアスリート事情、スポーツとITの関わりなど興味深い内容でした。
スポーツは『ゲーム』であり、選手はもちろん見ている人を楽しませるのが本来の目的であり、そのためにITを活用するというのは確かになぁと思う部分がありました。しかし、伝統や文化を重んじる日本人ならではの「ここは変わってほしくない」みたいな人の気持ちも分かるので、どこまでITに依存させるかということも難しい問題なんだろうなぁと思いました。
次に、『東京2020までの取り組みとその後』という題で東京オリンピック・パラリンピック競技大会組織委員会警備局サイバー攻撃対処部の方からのお話がありました。
サイバー攻撃など東京オリンピックのセキュリティに直接関わっている方からのお話ということでとても貴重なお話でした。
過去のオリンピック・パラリンピックで起こったテロやサイバー攻撃について、年々増加している話や今後どのような方法でどの程度テロやサイバー攻撃が起こるのかという予測をして備えなければならない。ということで自分には関係ないから~なんて言わず積極的に考える必要がある!と思いました。
最後に、ボランティアとして東京オリンピック・パラリンピックに関与してほしいというお話がありました。(興味はあるけど何をするんだろう...)
特別講義(2)
警視庁サイバー攻撃特別捜査隊の担当の方からの講演がありました。このお話の内容は、とても重要かつ機微な内容なので、口外は×。ということでここには書きません。
チューター成果報告
チューターの中から代表して二人の方のプレゼンがありました。
まずは、@kitokayさんから「自動車にセキュリティを求めるのは間違っているのだろうか」という題で発表がありました。感想としては、なんか凄い!内容は難しくてよく分かりませんでした。CAN(Control Area Network)を初めて聞いたので新鮮&面白そうとは思いましたが、CAN-BusにDoS攻撃とか怖すぎる((( ;゜ Д ゜)))
怖い人だなぁと思いました。
次は、@ytn86さんから「「脆弱性をみつける」から「脆弱性をなくす」へ」という題での発表でした。「脆弱性を見つけること」の意義について「世の中を安全にするため」、「一般ユーザがより安全にサービスを使える世界にしたい」など。カッコいいなぁ...
私自身今のところ楽しいから技術を学んでいるという部分が大きくて、この話以外でもキャンプで特に思ったのは、最終的には人のため社会のために今学んでいる技術をどう使うかというのが重要だということ。これは当たり前のようであまり深く考えてこなかった部分でもありとても参考になりました。
専門講義(1-D):Linuxにおける脆弱性攻撃とその対策
1日目の最後に遂に待ちに待った最初の講義。内容は、GDBというデバッガの使い方やバッファオーバーフロー脆弱性を利用した攻撃について簡単に学んだあと、実際に脆弱性があるプログラムに対してバッファオーバーフローを起こしてその時のスタックの状態をGDBで確認してみる、シェルコードを書いてみるなどをしました。
事前課題などで勉強していたので、難しくて理解できなかったということにはならなくて良かったと思います。ただ、もう少し踏み込んだ内容だとなお嬉しかったとも思いました。
何はともあれ、事前課題でもとてもお世話になったももいろテクノロジーの執筆者である講師の@inaz2さんの講義を直接受けれたのはとても良かったです。(@inaz2さんとは別の日にもいろいろ話を聞いてもらったり貴重なことを教えていただいたり大変お世話になりました有り難うございましたm(__)m)
キャンプ2日目
そして2日目。 朝起きれないんじゃないかと3段階目覚ましにしましたが、目覚ましが鳴る前に起きれました。(私はやればできるということを知れました。ありがとうございます。)
専門講義(2・3-C):攻撃検知と機械学習
この講義では機械学習を扱うということで、興味はあったが知識はほぼ無いという状態での講義でした。
内容は、SQL Injectionの攻撃ログや、謎の攻撃ログから目やツールを使用してどういう特徴があるのかなどを見つけるというものでした。
統合機械学習環境Wekaを使ったり、統計解析向けの言語であるR言語を使っていろいろ特徴抽出とかの雰囲気を味わえました。
とても面白くて、これから機械学習について勉強してもっと触ってみようと思いました。
専門講義(4・5-C):遠隔操作マルウェアの検知および検知回避
この講義ではShinoBOTを使ってRATを体験しました。
終始スゲースゲー言ってた気がします。
その後、グループを作り、それぞれ役割を決めてRATをvbsで作成しました。(全く役に立てなかったので申し訳ない気持ち...)
ここで一つ言っておきたいのは
正当な理由がないのに、同意なしに他人のPC上で動作させる目的で、マルウェアを開発、提供、利用する(しようとする)と、3年以下の懲役または50万円以下の罰金が科せられる
違法にマルウェアを作るのはダメ!
セキュリティ・キャンプに参加すればマルウェア作成が体験できる(かも)。
怖いのでRATのコードは載せません。ぜひキャンプに参加して作ってみてください!
専門講義(6-B):一夜でできる?!PC用OS自作入門
この講義の目的は、すべてを理解することではない!
こんな簡単にOSって作れるんだよ。という規模感を感じてほしい!
とのこと。
結論から言うと、凄い。本当凄い。楽しい。夢が広がりました。
すべてを理解しなくても、「ここをいじったらここが変わりそうだなぁ。こっちはどうだ?」といろいろ改造してみてとりあえずやってみる、ということが大事だということが分かりました。
キャンプ3日目
あっという間にキャンプ3日目。ここからは怒涛の解析講義でした。
専門講義(7・8・9-D):脆弱性攻撃と対策
この講義ではWindowsでROP(Return-Oriented-Programming)によるDEP回避をするExploitを使って電卓を起動させるということをやりました。詳しくはももいろテクノロジーを読みましょう。
WindowsでReturn-oriented Programming(ROP)によるDEP回避をやってみる - ももいろテクノロジー
その後は、UPXのゼロデイを見つけようということでひたすら解析をしました。(この時間内では誰も見つけることができませんでした)
近いうちにいろいろ試して見つけてみたいですねー。(※期待はしないでください)
専門講義(10-D):コードから読み解くマルウェアの真実(マルウェア分析概論、静的分析基礎)
この講義は、マルウェアの研究をしようとしている私としてはとても楽しみにしていた講義の一つでした。内容はマルウェア分析について座学で学び、IDAの使い方を覚えるという感じでした。詳しくは専門講義(13・14-D)のとこで書きます。
(11・12):出張 CTF for ビギナーズ 2015 幕張 in セキュリティ・キャンプ
3日目の最後は出張 CTF for ビギナーズということでCTFをやりました。CTFは1か月前くらいに始めた(ksnctfを少々)ばかりですが思ってたより難しくて、簡単な10点問題しか解けなかったのが悔しかったです。
今後に期待!
キャンプ4日目
もう4日目。ここまで来ると、この日で講義が終わる寂しさとグループワークの進捗の無さで悲しみいっぱいでした。
専門講義(13・14-D):コードから読み解くマルウェアの真実(実践マルウェア分析)
この講義では、実際にいくつかのマルウェアをひたすらIDAで分析するという内容でした。難しかったけど、私にとって得るものが多くとても為になりました。
IDAを使ったマルウェア分析では、
“IDAのコメント量が分析力だ!”
なるほど...私はいったい今まで何をやっていたんだ...
これからは頑張ります...!
専門講義(15・16-D):仮想化技術を用いたマルウェア解析
早いもので最後の講義となってしまいました。
この講義では、DECAFというQEMUベースの解析プラットフォームを用いて、DECAFのプラグインを拡張し、サンプルプログラムの解析妨害機能を回避するということを体験しました。実際にプラグインを拡張するのは楽しかったのですが難しい...!
テイント解析やシンボリック実行といった近年の研究動向についても少し解説がありました。が...やはり難しかったです。
これから勉強していきたいと思いました。
キャンプ5日目
最終日は寝ていません。
グループワーク発表
キャンプ最終日です。この日はグループワークの発表などがありチョー緊張しました。夜中グループワークのメンバーを部屋に連れ込んでワイワイしているのは楽しかったけど、進捗は厳しい状態でした。
なんとか当日の朝にはスライドを完成させて一同一安心。発表しました。
発表後は緊張が解けて、他のグループの発表を聞きながらスゲースゲー言ってました。
結果、賞などは貰えませんでしたがとても良い経験になりました。
一緒にいろいろ考えて力を合わせてくれたグループワークメンバーに感謝!
インタビューに答えて頂いた講師・チューターの方々有り難うございました。m(__)m
成果報告会、閉講式と続き無事セキュリティ・キャンプ全行程終了!!
みなさんお疲れ様でした。
頂き物いっぱい pic.twitter.com/QKopSb6ggo
— セント (@sentoneibisu) 2015, 8月 17
書籍類 pic.twitter.com/GHxksTLQQ0
— セント (@sentoneibisu) 2015, 8月 17
いろいろ頂けてサイコー!!!
まとめ
・ごはんおいしい
・野菜いっぱい嬉しい
・仲間いっぱい嬉しい
・講師やチューターの方々が優しかった
・グループワーク大変
・普段朝5時に寝る生活を続けていても意外と起きれる(キャンプ中は早く寝ないと無理!)
来年のキャンプ参加を考えている方へ
・迷わず応募すべし
・間違いなく最高の夏になります
・こんな濃密な5日間は他にない!
・友達いっぱい増えます
・コミュ力的に不安がある方!問題ないです。講師もチューターもとても優しくてコミュ力の塊なので何も喋らなくても成立します。
・もちろん講義も楽しい
・やる気UP↑↑↑・モチベUP↑↑↑
謝辞
いろいろ教えて頂いたりアドバイスをくれた講師の皆様、サポートしてくれたチューターの皆様、陰で支えてくれた運営の皆様、実施協議会の皆様、心より感謝いたします。