Intel Pin入門以前

はじめに

Intel Pinというのが楽しいから遊んで欲しいというだけの話。

Instrumentation

Instrumentation(計装)という概念がある。耳馴染みのない言葉だが、Wikipedia(en)にはしっかり記事がある。

一般に計装とは制御装置による測定を指す曖昧な概念だが、プログラミングの文脈におけるInstrumentationは「プログラムにコードを挿入することで実行時の情報を取得・操作する」技術を指す用語だ。
その及ぶ範囲はパフォーマンスの測定やエラー検出、CPUキャッシュの分析や未定義命令のエミュレーションなど多岐に渡る。
Instrumentationはその手法によって二種類に大別される。

  • Source Code Instrumentation(SCI)
  • Binary Instrumentation(BI)
    • 実行ファイルに直接instrumentする。

また、BIは更に二種類に分類される。

  • Static Binary Instrumentation
    • 実行前にinstrumentする。実行ファイルは変更される。
  • Dynamic Binary Instrumentation
    • 実行時にinstrumentする。実行ファイルは変更されない。

例えば、QEMUは異なるアーキテクチャのコードを実行するためにTCG(Tiny Code Generator)という機構を備えている。これはDynamic Binary Translation(DBT)と呼ばれる手法によるものだが、DBTはBIの一種であると言える。QEMUのDBTについては以前紹介した。

さて、Intel Pinはその名の通りIntelが開発したInstrumentation Toolだ。用いられる手法はDynamic Binary Instrumentationにあたるが、これを用いる利点としては以下が挙げられる。

  • 言語から独立している
  • 古いソフトウェアに対しても適用できる
  • コンパイルの必要がない
  • 動的に生成されるコードを扱うことができる
  • 実行中のプロセスにアタッチできる

C++のconstepxrなんかはとても楽しいが、しかし人類は実行時から逃れられない。

Intel Pinの概要

Intel PinはマルチプラットフォームなInstrumentation Toolで、動的リンクライブラリと解析対象を引数に与えて実行する。Intel PinのSDKを用いたツールを自作する場合、ユーザーは動的リンクライブラリを作成することになる。

pin -t pintool.dll - application

実行中のプロセスにアタッチする場合はPIDを指定する。

pin -t pintool.dll -pid 1234

Intel Pinのサンプル

ユーザーガイドの最初に登場するサンプル、inscountを紹介する。

#include <iostream>
#include <fstream>
#include "pin.H"

ofstream OutFile;

// The running count of instructions is kept here
// make it static to help the compiler optimize docount
static UINT64 icount = 0;

// This function is called before every instruction is executed
VOID docount() { icount++; }
    
// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
    // Insert a call to docount before every instruction, no arguments are passed
    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)docount, IARG_END);
}

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
    "o", "inscount.out", "specify output file name");

// This function is called when the application exits
VOID Fini(INT32 code, VOID *v)
{
    // Write to a file since cout and cerr maybe closed by the application
    OutFile.setf(ios::showbase);
    OutFile << "Count " << icount << endl;
    OutFile.close();
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage()
{
    cerr << "This tool counts the number of dynamic instructions executed" << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main                                                                  */
/* ===================================================================== */
/*   argc, argv are the entire command line: pin -t <toolname> -- ...    */
/* ===================================================================== */

int main(int argc, char * argv[])
{
    // Initialize pin
    if (PIN_Init(argc, argv)) return Usage();

    OutFile.open(KnobOutputFile.Value().c_str());

    // Register Instruction to be called to instrument instructions
    INS_AddInstrumentFunction(Instruction, 0);

    // Register Fini to be called when the application exits
    PIN_AddFiniFunction(Fini, 0);
    
    // Start the program, never returns
    PIN_StartProgram();
    
    return 0;
}

あれこれAPIが呼ばれているが、注目すべき点は少ない。VOID Instruction(INS ins, VOID *v)で解析ルーチンであるVOID docount()をinstrumentしているだけだ。解析対象であるアプリケーションとIntel Pinとそれぞれ別々のスタックを持つため、実行状態が壊れるということはない。基本このような感じで、適当にmoduleを叩いていくだけでそれなりのことができるので楽しい。特にSymbol Objectがいい感じだった。

Intel Pinのアーキテクチャ

DLLを与えていることから分かるように、Intel Pinの本質はコードインジェクションだ。先述のinscountを読み込む場合、アプリケーションの内部はこのようになる。
f:id:ntddk:20140708042032p:plain
元々のコードとinstrumentされたコードが組み合わさって実行される。アプリケーション内部にVMを埋め込む発想が面白い。
アーキテクチャの細部については公式のドキュメントを参照されたい。

とりわけ、CGO 2012/ISPASS 2012の資料は非常に充実している。

Intel Pinを取り巻く環境

Intel Pinは国内ではほぼ無名の存在だが、ダウンロード数は30,000を越え、被引用数は700を越えているキラープロダクトだ。
例えば、下記のグループでは日夜Intel Pinの質問が飛び交っている。

IDA Pro(商用版)と連携するためのSDKが公開されていることからも、その需要の高さを読み取ることができるだろう。

先日開催されたRecon 2014でもIntel Pinが用いられた発表があった。

CTFに関して言うと、例えばSMT SolverであるZ3やSageは徐々に広まりつつあるが、Intel Pinなどinstrumentation toolについても検討する必要があるかもしれない。どちらもConcolic Testing(Symbolic Execution)の同一線上に置かれる技術だ。
そしてもちろん、Taint AnalysisにおいてもIntel Pinは絶大な威力を持つだろう。


また、CTFtimeランク2位、PPPの母体であるCMUが開発しているBAPにもIntel Pinは利用されている。

おわりに

紹介にすらなっていないが、個人的にIntel Pinはかなりアツい。今後カーネルVM探検隊やセキュリティ・キャンプの方面で広めていきたい。
いま自分がIntel Pinでやりたいのは、Taint-analysis-basedなアンパッカーとASan(AddressSanitizer)の再実装だ。