Intel Pinを使ってみる

Dynamic Binary Instrumentation(DBI)は実行時にバイナリの内容を書き換えることにより、CPU命令の単位でプログラム実行のトレースなどを行う手法である。 ここでは、x86/x64用のDBIツールであるIntel Pinを使ってみる。

環境

Ubuntu 14.04.4 LTS 64bit版

$ uname -a
Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.4 LTS
Release:        14.04
Codename:       trusty

$ gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4

なお、Intel Pinの実行ファイルが32 bit用バイナリであるため、ここでは「64 bitのUbuntu Linuxで32 bitの実行ファイルを動かす方法のメモ」に書いた方法で32 bit用バイナリも実行できるようにしてある。

Intel Pinのダウンロード

ダウンロードページからLinux用のCompiler Kitをダウンロードして展開する。

$ wget http://software.intel.com/sites/landingpage/pintool/downloads/pin-2.14-71313-gcc.4.4.7-linux.tar.gz
$ tar xvf pin-2.14-71313-gcc.4.4.7-linux.tar.gz
$ cd pin-2.14-71313-gcc.4.4.7-linux/

付属のコードを使ってみる

Intel Pinには、Pinを利用したさまざまなコードが最初から付属している。 ここではマニュアルを参考に、inscount0、itrace、pinatraceの三つのコードを使ってみる。

まずは、マニュアルで説明されているコード一式をコンパイルする。

$ cd source/tools/ManualExamples/

$ ls
buffer_linux.cpp          emudiv.cpp             fork_jit_tool.cpp  invocation.cpp   malloc_mt.cpp         safecopy.cpp                             staticcount.cpp
buffer_windows.cpp        fibonacci.cpp          imageload.cpp      isampling.cpp    malloctrace.cpp       stack-debugger.cpp                       strace.cpp
countreps.cpp             follow_child_app1.cpp  inscount0.cpp      itrace.cpp       nonstatica.cpp        stack-debugger-tutorial.sln              thread_unix.c
detach.cpp                follow_child_app2.cpp  inscount1.cpp      little_malloc.c  pinatrace.cpp         stack-debugger-tutorial.vcxproj          thread_win.c
divide_by_zero_linux.c    follow_child_tool.cpp  inscount2.cpp      makefile         proccount.cpp         stack-debugger-tutorial.vcxproj.filters  w_malloctrace.cpp
divide_by_zero_windows.c  fork_app.cpp           inscount_tls.cpp   makefile.rules   replacesigprobed.cpp  statica.cpp

$ make all TARGET=intel64

使おうとした際に次のようなエラーが出た場合は、指示に従ってカーネルオプションを変更しておく。

$ ../../../pin -t obj-intel64/inscount0.so -- /bin/ls
E: Attach to pid 2301 failed.
E:   The Operating System configuration prevents Pin from using the default (parent) injection mode.
E:   To resolve this, either execute the following (as root):
E:   $ echo 0 > /proc/sys/kernel/yama/ptrace_scope
E:   Or use the "-injection child" option.
E:   For more information, regarding child injection, see Injection section in the Pin User Manual.
E:
Killed

$ sudo sh -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"

inscount0は、プログラム全体を通して実行された命令数をカウントする。

$ ../../../pin -t obj-intel64/inscount0.so -- /bin/ls
buffer_linux.cpp          emudiv.cpp             fork_jit_tool.cpp  inscount_tls.cpp  makefile.rules   pin.log                      stack-debugger-tutorial.vcxproj          thread_win.c
buffer_windows.cpp        fibonacci.cpp          imageload.cpp      invocation.cpp    malloc_mt.cpp    proccount.cpp                stack-debugger-tutorial.vcxproj.filters  w_malloctrace.cpp
countreps.cpp             follow_child_app1.cpp  inscount0.cpp      isampling.cpp     malloctrace.cpp  replacesigprobed.cpp         statica.cpp
detach.cpp                follow_child_app2.cpp  inscount1.cpp      itrace.cpp        nonstatica.cpp   safecopy.cpp                 staticcount.cpp
divide_by_zero_linux.c    follow_child_tool.cpp  inscount2.cpp      little_malloc.c   obj-intel64      stack-debugger.cpp           strace.cpp
divide_by_zero_windows.c  fork_app.cpp           inscount.out       makefile          pinatrace.cpp    stack-debugger-tutorial.sln  thread_unix.c

$ cat inscount.out
Count 776214

itraceは、実行された命令のアドレスを順に出力する。

$ ../../../pin -t obj-intel64/itrace.so -- /bin/ls
buffer_linux.cpp          emudiv.cpp             fork_jit_tool.cpp  inscount_tls.cpp  makefile         pinatrace.cpp         stack-debugger-tutorial.sln              thread_unix.c
buffer_windows.cpp        fibonacci.cpp          imageload.cpp      invocation.cpp    makefile.rules   pin.log               stack-debugger-tutorial.vcxproj          thread_win.c
countreps.cpp             follow_child_app1.cpp  inscount0.cpp      isampling.cpp     malloc_mt.cpp    proccount.cpp         stack-debugger-tutorial.vcxproj.filters  w_malloctrace.cpp
detach.cpp                follow_child_app2.cpp  inscount1.cpp      itrace.cpp        malloctrace.cpp  replacesigprobed.cpp  statica.cpp
divide_by_zero_linux.c    follow_child_tool.cpp  inscount2.cpp      itrace.out        nonstatica.cpp   safecopy.cpp          staticcount.cpp
divide_by_zero_windows.c  fork_app.cpp           inscount.out       little_malloc.c   obj-intel64      stack-debugger.cpp    strace.cpp

$ wc -l itrace.out
783915 itrace.out

$ head itrace.out
0x7f49c3a802d0
0x7f49c3a802d3
0x7f49c3a83a70
0x7f49c3a83a71
0x7f49c3a83a74
0x7f49c3a83a76
0x7f49c3a83a78
0x7f49c3a83a7a
0x7f49c3a83a7c
0x7f49c3a83a7d

pinatraceは、プログラム全体を通して読み書きされたメモリのアドレスを出力する。

$ ../../../pin -t obj-intel64/pinatrace.so -- /bin/ls
buffer_linux.cpp          emudiv.cpp             fork_jit_tool.cpp  inscount_tls.cpp  makefile         pinatrace.cpp         stack-debugger.cpp                       strace.cpp
buffer_windows.cpp        fibonacci.cpp          imageload.cpp      invocation.cpp    makefile.rules   pinatrace.out         stack-debugger-tutorial.sln              thread_unix.c
countreps.cpp             follow_child_app1.cpp  inscount0.cpp      isampling.cpp     malloc_mt.cpp    pin.log               stack-debugger-tutorial.vcxproj          thread_win.c
detach.cpp                follow_child_app2.cpp  inscount1.cpp      itrace.cpp        malloctrace.cpp  proccount.cpp         stack-debugger-tutorial.vcxproj.filters  w_malloctrace.cpp
divide_by_zero_linux.c    follow_child_tool.cpp  inscount2.cpp      itrace.out        nonstatica.cpp   replacesigprobed.cpp  statica.cpp
divide_by_zero_windows.c  fork_app.cpp           inscount.out       little_malloc.c   obj-intel64      safecopy.cpp          staticcount.cpp

$ wc -l pinatrace.out
308464 pinatrace.out

$ head pinatrace.out
0x7f18a59b92d3: W 0x7ffd5acedde8
0x7f18a59bca70: W 0x7ffd5acedde0
0x7f18a59bca74: W 0x7ffd5aceddd8
0x7f18a59bca76: W 0x7ffd5aceddd0
0x7f18a59bca78: W 0x7ffd5aceddc8
0x7f18a59bca7a: W 0x7ffd5aceddc0
0x7f18a59bca7c: W 0x7ffd5aceddb8
0x7f18a59bca8f: R 0x7f18a5bdae70
0x7f18a59bca96: W 0x7f18a5bdac98
0x7f18a59bcaa7: R 0x7f18a5bdb000

関連リンク