程序动态完整性校验之指令分支记录

来源:互联网 发布:淘宝流量充值没有收到 编辑:程序博客网 时间:2024/06/10 20:06

目的:记录程序的分支跳转地址,比如:jump、call、ret等直接或间接、无条件或条件转移指令的跳转地址(从哪来,跳到哪去)

使用动态插装工具:PIN

分析:   

         首先,因为需要记录指令的地址,并且区分转移指令,因此需要对程序进行指令级插装。由PIN提供指令级插装API : INS_AddInstrumentFunction(func,0) 注册指令级插装回调函数func.    

         其次,并不是对全部指令进行插装,而是仅插装分支转移指令。故需要在插装例程中判断当前指令是否为分支转移指令或者Call指令(一般为函数调用)。PIN提供API:INS_IsBranchOrCall(ins),来判断当前指令ins是(true)否(false)为分支转移指令或者Call指令,并返回bool值。

         然后,在判断插装点之后,则调用分析例程插装,记录当前指令地址以及跳转的目标地址。由PIN提供API:INS_InsertCall(INS ins,IPOINT action,AFUNPTRfuncptr...)来条用分析例程funcptr函数。因为我们仅记录分支跳转且跳转成功的指令地址,所以调用funcptr函数的条件即:当前转移指令跳转成功。PIN提供API: IPOINT_TAKEN_BRANCH,来判断一个分支指令是否跳转成功。由于要记录跳转地址的源地址和目的地址,所以需要通过INS_InsertCall向分析例程funcptr传递当前分支指令地址和分支目的地址。分别由枚举类型的IARG_TYPE中的IARG_INST_PTR、IARG_BRANCH_TARGET_ADDR指定。

                   最后,在分析例程funcptr中记录分支跳转指令地址(源地址+目的地址)。

按照以上分析思路,编写分支记录pintool:branch.cpp,如下:

#include<iostream>

#include<fstream>

#include<stdlib.h>

#include"pin.H"

using namespace std;

ofstream OutFile;

//指定输出文件

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE,"pintool",

    "o", "branch.out","specify output file name");

//分析例程

void recording(VOID*ip,ADDRINT addr)

{

        OutFile<<hex<<"From:"<<ip<<"  To:"<<(void*)addr<<endl;

}

//插装回调函数

void instruction(INSins,VOID *v)

{

          //判断当前指令是否是转移指令或者Call调用指令

        if(INS_IsBranchOrCall(ins))

          {

                    INS_InsertCall(ins,IPOINT_TAKEN_BRANCH, (AFUNPTR)recording, IARG_INST_PTR,IARG_BRANCH_TARGET_ADDR,IARG_END);

          }

}

 

VOID Fini(INT32 code,VOID *v)

{

     OutFile.close();

}

 

int main(int argc,char * argv[])

{

    PIN_InitSymbols();

    PIN_Init(argc, argv);

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

    INS_AddInstrumentFunction(instruction,0);

    PIN_AddFiniFunction(Fini, 0);

    PIN_StartProgram();   

    return 0;

}




 

0 0