2

現在、このブログ投稿に基づいて、Linux アプリケーションからの初期化されていない読み取りを検出する Pin ツールを作成しています。
作者のコードはブログからも見ることができます。

これはWindows用なので、Linux対応のものを作ってみました。しかし、アプリケーションでピン ツールを実行すると、セグメンテーション エラーが発生します。奇妙なのは、関数が呼び出されたときにエラーが発生することです (ピン ツールが関数taint_get内の関数を呼び出しているときにエラーが発生しtaint_defineます)。初期化されていないヒープ ポインターへのアクセスや、一般的なセグメンテーション エラーのようなポイントが原因ではありません。

セグメンテーション違反のポイントは次のようになります。

VOID Instruction(INS ins, VOID *v)
{
   Uninit_Instruction(ins, v);
}

void Uninit_Instruction(INS ins, void* v)
{
   // check if the stack pointer is altered (i.e. memory is allocated on the
   // stack by subtracting an immediate from the stack pointer)
   if(INS_Opcode(ins) == XED_ICLASS_SUB &&
      INS_OperandReg(ins, 0) == REG_STACK_PTR &&
      INS_OperandIsImmediate(ins, 1)) 
   {
      // insert call after, so we can pass the stack pointer directly
      INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)taint_undefined,
             IARG_REG_VALUE, 
             REG_STACK_PTR, 
             IARG_ADDRINT, (UINT32) INS_OperandImmediate(ins, 1),
             IARG_END);
   }

   UINT32 memOperands = INS_MemoryOperandCount(ins);

   for (UINT32 memOp = 0; memOp < memOperands; memOp++)
   {
      if (INS_MemoryOperandIsRead(ins, memOp))
      {
     INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)taint_check,
            IARG_INST_PTR,
            IARG_MEMORYOP_EA, memOp,
            IARG_MEMORYREAD_SIZE,
            IARG_END);
      }

      if (INS_MemoryOperandIsWritten(ins, memOp))
      {
     INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)taint_define,
            IARG_MEMORYOP_EA, memOp,
            IARG_MEMORYWRITE_SIZE,
            IARG_END);
      }
   }

}

コールバック関数は次のようになります。

// Taint this address as written
void taint_define(ADDRINT addr, UINT32 size)
{
   // Debug purpose
   TraceFile << "taint_define: " << addr << ", " << size << endl;

   // taint the addresses as defined, pretty slow, but easiest to implement
   for (UINT32 i = 0; i < size; i++) 
   {
      //TraceFile << "taint_define_loop size: " << size << endl;
      UINT32 *t = taint_get(addr + i);
      TraceFile << "after taint_get" << endl;
      UINT32 index = (addr + i) % 0x20000;

      // define this bit
      t[index / 32] |= 1 << (index % 32);
   }
}


inline UINT32* taint_get(ADDRINT addr)
{
   // Debug purpose
   TraceFile << "taint_get: " << addr;

   // allocate memory to taint these memory pages
   if(taint[addr / 0x20000] == NULL) {
      // we need an 16kb page to track 128k of memory
      /*
        taint[addr / 0x20000] = (UINT32 *) W::VirtualAlloc(NULL, 0x20000 / 8,
    MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
      */
      taint[addr / 0x20000] = (UINT32*)malloc(0x20000/8);
   }

   return taint[addr / 0x20000];
}

出力は次のようになります。

C:Tool (or Pin) caused signal 11 at PC 0x7fcf475e08a4
segmentation fault (core dumped)

ログはここにあります。

Watched Image count: 0x1
WatchedImage: unread_3vars
Uninit_Image
Uninit_Image
Thread start
taint_define: 0x7fff06930d58, 0x8

現在、Fedora コア 17 x86-64、gcc 4.7.2、およびピン 2.12-58423 に取り組んでいます。
そして、私のピンツールコードはここに添付されています

4

2 に答える 2

0

readb4write は 32 ビットのみです。どのようにコンパイルしているのかわかりませんが、-m32 を追加しても動作しない可能性があります。これは私の場合に起こったことですが、Windowsで実行しています。
たとえば、コメントを見るだけで、それが 32 ビットであることが
わかります。x64では、taint_get メソッドで48 ビット アドレス
に 対応する必要があります。これはまだ単純な実装ですが、他のすべてもそうです

typedef UINT64 * TTaint[0x80000];
TTaint *taintTable[0x10000] = { 0 };


inline UINT64 *taint_get(ADDRINT addr)
{
   UINT64 chunkAddress = addr / 0x20000; //get number address of 128kb chunk. 

   UINT64 firstLevAddr = chunkAddress / 0x10000;
   UINT64 secondLevelAddr = chunkAddress % 0x10000;

   TTaint *taint = NULL;
   if (taintTable[firstLevAddr] == NULL){
       taintTable[firstLevAddr] = (TTaint*)W::VirtualAlloc(NULL, sizeof(TTaint),
        MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    }
   taint = taintTable[firstLevAddr];

   // allocate memory to taint these memory pages
   if ((*taint)[secondLevelAddr ] == NULL) {
      // we need an 16kb page to track 128k of memory
        (*taint)[secondLevelAddr] = (UINT64 *)W::VirtualAlloc(NULL, 0x20000 / 8,
            MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
   }
   return (*taint)[secondLevelAddr];
}

また、ほとんどの (すべてではないにしても) 変数は、UINT32 ではなく UINT64 である必要があります。32 を 64 に変更する必要が

あります。まだ解決していない別の問題があります。初期化されていないメモリにアクセスする命令がチェック対象のプログラムに属しているかどうかを検出する行があります。x64 でまだ有効である可能性は低いです:
(ip & 0xfff00000) == 0x00400000)
何とか機能させることができれば、コードを github で公開します。

于 2015-06-27T11:00:44.593 に答える
0

現在、このブログ投稿に基づいて、Linux アプリケーションからの初期化されていない読み取りを検出する Pin ツールを作成しています。

これは実際にはあなたの質問に答えるものではなく、ピン ツールを学習する別の理由があるかもしれませんが...

ピンベースのツールは、おもちゃではないプログラムを計測するには不十分であることがわかりました。目標が初期化されていないメモリ読み取りを検出することである場合は、Memory Sanitizerの使用を検討してください。

于 2013-11-10T16:05:35.073 に答える