taint analysis

DBI - pin & pintool

2017. 5. 22. 23:54



 PIN 에 대해서 공부한지는 조금 되었으나 적당히 기존 코드로만 붙여넣기 해서 사용했던 것이 사실이다. 최근 개인 프로젝트로 PIN 을 사용할 일이 생겨서 하는 김에 정리해 둔다.





PIN


 PIN 이란, Intel 에서 제작 및 관리중인 Dynamic Binary Instrumentation Framework 이다. BI 분야에서 실행을 하지 않고 조사하는 SBI 와 동적으로 실행중 코드를 조사하는 DBI 가 있는데, 그 중 PIN 은  DBI 를 위한 SDK(?) 정도로 볼 수 있다. 


Intel 이란 기업에서 관리하기 때문에 상당히 업데이트가 잘 되고 있으며 매뉴얼도 매우 충실하게 잘 되어 있다. 또한 수많은 예제코드가 들어 있어서 몇개의 코드만 분석해 보면 바로 사용방법을 알 수 있을 정도로 완성도가 높다. 


한가지 단점은 C++ 로 작성해서 DLL 로 컴파일 해야 하므로 스크립트 언어에 비해 수정&적용이 조금 오래 걸린다는 점이 있다. 하지만 이러한 단점은 장점에 비해 크지 않으므로 수년전부터 현재까지도 PIN 은 매우 인기 있는 DBI 프레임워크로 자리잡았다. 


PIN 은 그 자체로 pin.exe 로 독립된 바이너리이며, 실행 파일을 에뮬레이션 해준다. 에뮬레이션 하는 동안 PINTOOL 로 작성한 DLL 코드를 통해 다양하게 동적으로 코드를 수행할 수 있다.


 


PINTOOL


PINTOOL 은 PIN SDK 를 이용하여 개발한 라이브러리이다. pin.exe 실행 시 옵션으로(-t) 지정해주면 해당 PINTOOL 을 이용하여 타겟 바이너리를 실행시켜 준다.



Build PINTOOL


 다운로드 및 설치는 검색하면 많으니 타 자료를 참고바란다. 여러가지 방법이 있지만 개인적으로는 cygwin + make 가 편한 듯 하다. visual studio 로도 가능하지만 컴파일 프로그램 특성상 소스코드 수정, 컴파일 및 실행, 빌드된 파일 이동, 실행 등을 자주 해야 해서 차라리 make 로 배치 파일을 만드는 것이 편하다.


# make.bat

cd C:\Users\hyunmini\Desktop\pin-3.2-81205-msvc-windows\source\tools\MyPinTool

make 

copy /y obj-ia32\MyPinTool.dll c:\Users\FSI\Desktop\dbi\pin

cd c:\Users\hyunmini\Desktop\dbi\pin


 





Simple Example 1 - call tracer


#include "pin.H"
#include <asm/unistd.h>
#include <iostream>
#include <fstream>
#include <list>

UINT32 insCount = 0;    
UINT32 bblCount = 0;    
UINT32 threadCount = 0; 
UINT32 traceCount = 0;

std::ostream * out = &cerr;

KNOB<string> KnobTraceString(KNOB_MODE_WRITEONCE,  "pintool",
    "s", "", "trace string");

INT32 Usage()
{
    cerr << "This tool prints out the traced call with arguments." << endl;
    cerr << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

string invalid = "invalid_rtn";

const string *Target2String(ADDRINT target) {
    string name = RTN_FindNameByAddress(target);
    if (name == "") {
        return &invalid;
    } else if (name == ".text" || name == "unnamedImageEntryPoint") {
        return new string(StringFromAddrint(target));
    }
    else
        return new string(name);
}

string ReadCString(ADDRINT target){
    ADDRINT Buffer;
    PIN_SafeCopy(&Buffer, (ADDRINT *)(target), sizeof(ADDRINT));
    string cstring;
    while (1) {
        char c = 0;
        if (PIN_SafeCopy(&c, (ADDRINT *) Buffer, 1) != 1)
            break;
        if (c == 0)
            break;
        cstring += c;
        Buffer += 1;
    }
    return cstring;
}

VOID  do_call_args(ADDRINT ins,const string *s, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) {
    PIN_LockClient();
    string img_name = IMG_Name(IMG_FindByAddress(ins));
    PIN_UnlockClient();
    string base_img_name = img_name.substr(img_name.find_last_of("/\\") + 1);
    string argstr1 = ReadCString(esp);
    string argstr2 = ReadCString(esp+4);
    string argstr3 = ReadCString(esp+8);
    if( 
        argstr1.find(KnobTraceString.Value()) != string::npos || 
        argstr2.find(KnobTraceString.Value()) != string::npos || 
        argstr3.find(KnobTraceString.Value()) != string::npos
      ){
        *out << StringFromAddrint(ins) << " : " << base_img_name << "!" << *s << "(0x" << std::hex << arg0 << ", 0x" << arg1 << ", 0x" << arg2 << "...)" << endl;
        if(argstr1.length()>10){
            argstr1 = argstr1.substr(0,10);
            argstr1 += "...";
        }
        if(argstr2.length()>10){
            argstr2 = argstr2.substr(0,10);
            argstr2 += "...";
        }
        if(argstr3.length()>10){
            argstr3 = argstr3.substr(0,10);
            argstr3 += "...";
        }
        *out << "    arg1 : " << argstr1 << endl;
        *out << "    arg2 : " << argstr2 << endl;
        *out << "    arg3 : " << argstr3 << endl;
    }
}

VOID  do_call_args_indirect(ADDRINT ins, ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) {
    if( !taken ) return;
    const string *s = Target2String(target);
    do_call_args(ins, s, arg0, arg1, arg2, esp);
    if (s != &invalid)
        delete s;
}

/* ===================================================================== */

VOID Trace(TRACE trace, VOID *v)
{
    PIN_LockClient();
    IMG img = IMG_FindByAddress(TRACE_Address(trace));
    PIN_UnlockClient();

    if (IMG_Valid(img) && IMG_IsMainExecutable(img)){
        for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
        {
            INS tail = BBL_InsTail(bbl);
            if( INS_IsCall(tail) ) {
                if( INS_IsDirectBranchOrCall(tail) ) {
                    // direct call
                    const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail);
                    INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args),
                                                IARG_INST_PTR,
                                                IARG_PTR, Target2String(target), 
                                                IARG_FUNCARG_CALLSITE_VALUE, 0,
                                                IARG_FUNCARG_CALLSITE_VALUE, 1,
                                                IARG_FUNCARG_CALLSITE_VALUE, 2,
                                                IARG_REG_VALUE, REG_ESP,
                                                IARG_END);
                }
                else {
                    // indirect call
                    INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect),
                                    IARG_INST_PTR,
                                    IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN,  
                                    IARG_FUNCARG_CALLSITE_VALUE, 0,
                                    IARG_FUNCARG_CALLSITE_VALUE, 1,
                                    IARG_FUNCARG_CALLSITE_VALUE, 2,
                                    IARG_REG_VALUE, REG_ESP,
                                    IARG_END);
                }
            }
            else {
                RTN rtn = TRACE_Rtn(trace);
                if( RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail)) {
                    INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect),
                                    IARG_INST_PTR,
                                    IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN,  
                                    IARG_FUNCARG_CALLSITE_VALUE, 0,
                                    IARG_FUNCARG_CALLSITE_VALUE, 1,
                                    IARG_FUNCARG_CALLSITE_VALUE, 2,
                                    IARG_REG_VALUE, REG_ESP,
                                    IARG_END);       
                }
            }
        }
    }
}

int main(int argc, char *argv[])
{
    PIN_InitSymbols();
    if( PIN_Init(argc,argv) ){  return Usage(); }
    string fileName = "trace_result.txt";
    if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());}

    TRACE_AddInstrumentFunction(Trace, 0);

    PIN_StartProgram();
    return 0;
}



실행결과


x00489d99 : VUPlayer.exe!_mbscmp(0x3c34f3c, 0x3be35f8, 0x74aeac8...)
    arg1 : AAAAAAAAAA...
    arg2 : #VUPlayer ...
    arg3 : 
0x004552ac : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f140, 0x0...)
    arg1 : AAAAAAAAAA...
    arg2 : mod
    arg3 : 
0x004552d2 : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f13c, 0x0...)
    arg1 : AAAAAAAAAA...
    arg2 : s3m
    arg3 : 
0x004552f8 : VUPlayer.exe!_mbsicmp(0x3c3408c, 0x51f138, 0x0...)
    arg1 : AAAAAAAAAA...
    arg2 : xm
    arg3 : 

0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...)
    arg1 : AAAAAAAAAA...
    arg2 : rb
    arg3 : dœP
0x004562a3 : VUPlayer.exe!0x004b9f68(0x0, 0x3c3408c, 0x0...)
    arg1 : 
    arg2 : AAAAAAAAAA...
    arg3 : 
0x004b9f68 : VUPlayer.exe!BASS_MusicLoad(0x4562a8, 0x0, 0x3c3408c...)
    arg1 : ‰Eüƒ}ü
    arg2 : 
    arg3 : AAAAAAAAAA...
0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...)
    arg1 : AAAAAAAAAA...
    arg2 : rb
    arg3 : dœP
0x00456191 : VUPlayer.exe!fopen(0x3c3408c, 0x51e098, 0x12d198...)
    arg1 : AAAAAAAAAA...
    arg2 : rb
    arg3 : dœP
0x00453313 : VUPlayer.exe!lstrcpyA(0x12cc44, 0x3c3408c, 0x12d3a8...)
    arg1 : 
    arg2 : AAAAAAAAAA...
    arg3 : 0ü¿4P
0x00453325 : VUPlayer.exe!fopen(0x12cc44, 0x51e098, 0x12d3a8...)
    arg1 : AAAAAAAAAA...
    arg2 : rb
    arg3 : AAAAAAAAAA...






Taint Analysis with PIN


taint analysis 는 이론부터 설명하면 매우 길기 때문에 더이상의 설명은 생략한다!(...)

결론은 쓸만하지만 오류 없이 쓰려면 훨~씬 세세한 컨트롤을 해줘야 함. 그러므로 여기까지만..


 * 코드 일부 생략.

 ** (http://shell-storm.org/blog/Taint-analysis-and-pattern-matching-with-Pin 코드를 아주 많이 참고 하였음을 밝힙니다)


#include "pin.H"

#include <asm/unistd.h>
#include <iostream>
#include <fstream>
#include <list>

UINT32 insCount = 0;    
UINT32 bblCount = 0;    
UINT32 threadCount = 0;
UINT32 traceCount = 0;
BOOL start_taint = false;

std::ostream * out = &cerr;
std::list<ADDRINT> addressTainted;
std::list<REG> regsTainted;

string invalid = "invalid_rtn";

////////////////////////
//  trace user input  //
////////////////////////

VOID fgetsBefore(ADDRINT arg0, ADDRINT arg1, ADDRINT arg2) {
    *out << "[Taint] fgets() : " << endl;
    *out << " buf : 0x" << std::hex << arg1 << endl;
    *out << " size : 0x" << arg2 << endl;
    int size = static_cast<ADDRINT>(arg2);
    start_taint = true;
    for (int i=0;i<size;i++){
        addressTainted.push_back(arg1+i);
    }
}

VOID recvBefore(ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT arg3) {
    *out << "[Taint] recv() : " << endl;
    *out << " buf : 0x" << std::hex << arg2 << endl;
    *out << " size : 0x" << arg3 << endl;
    int size = static_cast<ADDRINT>(arg3);
    start_taint = true;
    for (int i=0;i<size;i++){
        addressTainted.push_back(arg2+i);
    }
}

///////////////////////
/// taint analysis  ///
///////////////////////
bool IsRegTainted(REG reg){
    list<REG>::iterator i;

    for(i = regsTainted.begin(); i != regsTainted.end(); i++){
        if (*i == reg){
          return true;
        }
    }
    return false;
}

bool IsMemTainted(ADDRINT mem){
    list<ADDRINT>::iterator i;
    for(i = addressTainted.begin(); i != addressTainted.end(); i++){
        if (mem == *i){
            return true;
        }
    }
    return false;
}

bool removeRegTainted(REG reg){
  switch(reg){

    case REG_EAX:  regsTainted.remove(REG_EAX);
    case REG_AX:   regsTainted.remove(REG_AX);
    case REG_AH:   regsTainted.remove(REG_AH);
    case REG_AL:   regsTainted.remove(REG_AL);
         break;

    case REG_EBX:  regsTainted.remove(REG_EBX);
    case REG_BX:   regsTainted.remove(REG_BX);
    case REG_BH:   regsTainted.remove(REG_BH);
    case REG_BL:   regsTainted.remove(REG_BL);
         break;

    case REG_ECX:  regsTainted.remove(REG_ECX);
    case REG_CX:   regsTainted.remove(REG_CX);
    case REG_CH:   regsTainted.remove(REG_CH);
    case REG_CL:   regsTainted.remove(REG_CL);
         break;

    case REG_EDX:  regsTainted.remove(REG_EDX); 
    case REG_DX:   regsTainted.remove(REG_DX); 
    case REG_DH:   regsTainted.remove(REG_DH); 
    case REG_DL:   regsTainted.remove(REG_DL); 
         break;

    case REG_EDI:  regsTainted.remove(REG_EDI); 
    case REG_DI:   regsTainted.remove(REG_DI); 
         break;

    case REG_ESI:  regsTainted.remove(REG_ESI); 
    case REG_SI:   regsTainted.remove(REG_SI); 
         break;

    default:
      return false;
  }
  *out  << "\t\t\t" << REG_StringShort(reg) << " is now freed" << std::endl;
  return true;
}

bool taintReg(REG reg){
    if (IsRegTainted(reg)){
        * out << "\t\t\t" << REG_StringShort(reg) << " is already tainted" << std::endl;
        return false;
    }

    switch(reg){

        case REG_EAX:  regsTainted.push_front(REG_EAX); 
        case REG_AX:   regsTainted.push_front(REG_AX); 
        case REG_AH:   regsTainted.push_front(REG_AH); 
        case REG_AL:   regsTainted.push_front(REG_AL); 
            break;

        case REG_EBX:  regsTainted.push_front(REG_EBX);
        case REG_BX:   regsTainted.push_front(REG_BX);
        case REG_BH:   regsTainted.push_front(REG_BH);
        case REG_BL:   regsTainted.push_front(REG_BL);
            break;

        case REG_ECX:  regsTainted.push_front(REG_ECX);
        case REG_CX:   regsTainted.push_front(REG_CX);
        case REG_CH:   regsTainted.push_front(REG_CH);
        case REG_CL:   regsTainted.push_front(REG_CL);
            break;

        case REG_EDX:  regsTainted.push_front(REG_EDX); 
        case REG_DX:   regsTainted.push_front(REG_DX); 
        case REG_DH:   regsTainted.push_front(REG_DH); 
        case REG_DL:   regsTainted.push_front(REG_DL); 
            break;

        case REG_EDI:  regsTainted.push_front(REG_EDI); 
        case REG_DI:   regsTainted.push_front(REG_DI); 
            break;

        case REG_ESI:  regsTainted.push_front(REG_ESI); 
        case REG_SI:   regsTainted.push_front(REG_SI); 
            break;

        default:
            *out  << "\t\t\t" << REG_StringShort(reg) << " can't be tainted" << std::endl;
            return false;
  }
  *out << "\t\t\t" << REG_StringShort(reg) << " is now tainted" << std::endl;
  return true;
}

VOID ReadMem(INS ins, ADDRINT memOp){
    // memory -> reg
    list<ADDRINT>::iterator i;
    ADDRINT addr = memOp;
    REG read_reg;
  
    if (INS_OperandCount(ins) != 2)
        return;

    read_reg = INS_OperandReg(ins, 0);
    for(i = addressTainted.begin(); i != addressTainted.end(); i++){
        if (addr == *i){
            // tainted memory > register
            *out << "[Read][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl;
            taintReg(read_reg);
            return ;
        }
    }
    if (IsRegTainted(read_reg)){
        // untainted memory > tainted register => clear reg
        *out << "[Read][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl;
        removeRegTainted(read_reg);
    }
}

VOID WriteMem(INS ins, ADDRINT memOp){
    // reg -> memory
    list<ADDRINT>::iterator i;
    ADDRINT addr = memOp;
    REG read_reg;
  
    if (INS_OperandCount(ins) != 2)
        return;

    read_reg = INS_OperandReg(ins, 1);
    for(i = addressTainted.begin(); i != addressTainted.end(); i++){
        if (addr == *i){
            // tainted memory
            *out << "[Write][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl;
            if (!REG_valid(read_reg) || !IsRegTainted(read_reg)){
                // untainted register > tainted memory => clear memory
                addressTainted.remove(addr);
            }
            *out << std::hex << "\t\t\t0x" << addr << " is now freed" << std::endl;
            return;
        }
    }

    if (IsRegTainted(read_reg)) {
    // tainted reg > untainted memory => tainted
        addressTainted.push_back(addr);
        *out << std::hex << "\t\t\t0x" << addr << " is now tainted" << std::endl;
        return;
    }
}

VOID spreadReg(INS ins)
{
    REG reg_r, reg_w;

    if (INS_OperandCount(ins) != 2) return;

    reg_r = INS_RegR(ins, 0);  // src
    reg_w = INS_RegW(ins, 0);  // dest 

    if (REG_valid(reg_w)){
        // reg_w not const(address)
        if (IsRegTainted(reg_w) && (!REG_valid(reg_r) || !IsRegTainted(reg_r))){
            // untainted reg > tainted reg => clear reg
            *out  << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl;
            *out  << "\t\t\toutput: "<< REG_StringShort(reg_w) << " | input: " << (REG_valid(reg_r) ? REG_StringShort(reg_r) : "constant") << std::endl;
            removeRegTainted(reg_w);
    }
    else if (!IsRegTainted(reg_w) && IsRegTainted(reg_r)){
        // tainted reg > untainted reg => tainted
        *out  << "[SPREAD]\t\t" << INS_Address(ins) << ": " << INS_Disassemble(ins) << std::endl;
        *out  << "\t\t\toutput: " << REG_StringShort(reg_w) << " | input: "<< REG_StringShort(reg_r) << std::endl;
        taintReg(reg_w);
        }
    }
}

VOID Instruction(INS ins, VOID *v){
    if (IMG_IsMainExecutable(IMG_FindByAddress(INS_Address(ins)))){
        // callback for read instruction
        // memory -> reg
        if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsRead(ins, 0) && INS_OperandIsReg(ins, 0)){
            if (start_taint){
                  INS_InsertCall(
                    ins, IPOINT_BEFORE, (AFUNPTR)ReadMem,
                    IARG_PTR, ins,
                    IARG_MEMORYOP_EA, 0,
                    IARG_END);
            }
        }
        // callback for write instruction
        // reg -> memory
        else if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0)){
            if (start_taint){
                INS_InsertCall(
                    ins, IPOINT_BEFORE, (AFUNPTR)WriteMem,
                    IARG_PTR, ins,
                    IARG_MEMORYOP_EA, 0,
                    IARG_END);
            }
        }
        // callback for spread instruction
        // reg -> reg
        else if (INS_OperandCount(ins) > 1 && INS_OperandIsReg(ins, 0)){
            if (start_taint){
                //*out << "[Spread][0x" << std::hex << INS_Address(ins) <<"] : " << INS_Disassemble(ins) << endl;
                 INS_InsertCall(
                    ins, IPOINT_BEFORE, (AFUNPTR)spreadReg,
                    IARG_PTR, ins,
                    IARG_END);
            }
        }
    }
}

VOID Image(IMG img, VOID *v){
    // fgets(&Buf, 2000, File);
    RTN fgetsRtn = RTN_FindByName(img, "fgets");
    if (RTN_Valid(fgetsRtn))
    {
        RTN_Open(fgetsRtn);
        RTN_InsertCall(fgetsRtn, IPOINT_BEFORE, (AFUNPTR)fgetsBefore,
                        IARG_FUNCARG_CALLSITE_VALUE, 0,
                        IARG_FUNCARG_CALLSITE_VALUE, 1,
                        IARG_FUNCARG_CALLSITE_VALUE, 2,
                        IARG_END);
        RTN_Close(fgetsRtn);
    }
    // recv(sock, &buf, 2000, 0);
    RTN recvRtn = RTN_FindByName(img, "recv");
    if (RTN_Valid(recvRtn))
    {
        RTN_Open(recvRtn);
        RTN_InsertCall(recvRtn, IPOINT_BEFORE, (AFUNPTR)recvBefore,
                        IARG_FUNCARG_CALLSITE_VALUE, 0,
                        IARG_FUNCARG_CALLSITE_VALUE, 1,
                        IARG_FUNCARG_CALLSITE_VALUE, 2,
                        IARG_FUNCARG_CALLSITE_VALUE, 3,
                        IARG_END);
        RTN_Close(recvRtn);
    }
}

VOID Fini(INT32 code, VOID *v){
    /*
    list<ADDRINT>::iterator li;
    for(li=addressTainted.begin(); li!=addressTainted.end(); li++){
        * out << std::hex << *li << endl;
    }
    */
    *out << "[+] Finish!!" << endl;
}

/////////////////////////////
//////   call trace /////////
/////////////////////////////
const string *Target2String(ADDRINT target) {
    string name = RTN_FindNameByAddress(target);
    if (name == "") {
        return &invalid;
    } else if (name == ".text" || name == "unnamedImageEntryPoint") {
        return new string(StringFromAddrint(target));
    }
    else
        return new string(name);
}

string ReadCString(ADDRINT target){
    ADDRINT Buffer;
    PIN_SafeCopy(&Buffer, (ADDRINT *)(target), sizeof(ADDRINT));
    string cstring;
    while (1) {
        char c = 0;
        if (PIN_SafeCopy(&c, (ADDRINT *) Buffer, 1) != 1)
            break;
        if (c == 0)
            break;
        cstring += c;
        Buffer += 1;
    }
    return cstring;
}

VOID  do_call_args(ADDRINT ins,const string *s, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) {
    PIN_LockClient();
    string img_name = IMG_Name(IMG_FindByAddress(ins));
    PIN_UnlockClient();
    string base_img_name = img_name.substr(img_name.find_last_of("/\\") + 1);
    string argstr1 = ReadCString(esp);
    string argstr2 = ReadCString(esp+4);
    string argstr3 = ReadCString(esp+8);
    bool tainted_func = false;

    if ( IsMemTainted(arg0) ) {
        tainted_func = true;
    }
    if ( IsMemTainted(arg1) ) {
        tainted_func = true;
    }
    if ( IsMemTainted(arg2) ) {
        tainted_func = true;
    }
    
    if ( tainted_func ) {
        *out << "[tainted arg]" << StringFromAddrint(ins) << " : " << base_img_name << "!" << *s << "(0x" << std::hex << arg0 << ", 0x" << arg1 << ", 0x" << arg2 << "...)" << endl;

        if (argstr1.length()>10){
            argstr1 = argstr1.substr(0,10);
            argstr1 += "...";
        }
        if (argstr2.length()>10){
            argstr2 = argstr2.substr(0,10);
            argstr2 += "...";
        }
        if (argstr3.length()>10){
            argstr3 = argstr3.substr(0,10);
            argstr3 += "...";
        }
        *out << "    arg1 : " << argstr1 << endl;
        *out << "    arg2 : " << argstr2 << endl;
        *out << "    arg3 : " << argstr3 << endl;
    }
}

VOID  do_call_args_indirect(ADDRINT ins, ADDRINT target, BOOL taken, ADDRINT arg0, ADDRINT arg1, ADDRINT arg2, ADDRINT esp) {
    if ( !taken ) return;
    const string *s = Target2String(target);
    do_call_args(ins, s, arg0, arg1, arg2, esp);
    if (s != &invalid)
        delete s;
}

/* ===================================================================== */

VOID Trace(TRACE trace, VOID *v)
{
    PIN_LockClient();
    IMG img = IMG_FindByAddress(TRACE_Address(trace));
    PIN_UnlockClient();

//    if (IMG_Valid(img) && IMG_IsMainExecutable(img)){
    if (IMG_Valid(img) && IMG_IsMainExecutable(img)){   
        for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
        {
            INS tail = BBL_InsTail(bbl);
            if ( INS_IsCall(tail) ) {
                if ( INS_IsDirectBranchOrCall(tail) ) {
                    // direct call
                    const ADDRINT target = INS_DirectBranchOrCallTargetAddress(tail);
                    INS_InsertPredicatedCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args),
                                                IARG_INST_PTR,
                                                IARG_PTR, Target2String(target), 
                                                IARG_FUNCARG_CALLSITE_VALUE, 0,
                                                IARG_FUNCARG_CALLSITE_VALUE, 1,
                                                IARG_FUNCARG_CALLSITE_VALUE, 2,
                                                IARG_REG_VALUE, REG_ESP,
                                                IARG_END);
                }
                else {
                    // indirect call
                    INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect),
                                    IARG_INST_PTR,
                                    IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN,  
                                    IARG_FUNCARG_CALLSITE_VALUE, 0,
                                    IARG_FUNCARG_CALLSITE_VALUE, 1,
                                    IARG_FUNCARG_CALLSITE_VALUE, 2,
                                    IARG_REG_VALUE, REG_ESP,
                                    IARG_END);
                }
            }
            else {
                RTN rtn = TRACE_Rtn(trace);
                if ( RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(tail)) {
                    INS_InsertCall(tail, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect),
                                    IARG_INST_PTR,
                                    IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN,  
                                    IARG_FUNCARG_CALLSITE_VALUE, 0,
                                    IARG_FUNCARG_CALLSITE_VALUE, 1,
                                    IARG_FUNCARG_CALLSITE_VALUE, 2,
                                    IARG_REG_VALUE, REG_ESP,
                                    IARG_END);       
                }
            }
        }
    }
}
/////////////////////////////////////////////////
////////////// call trace end ///////////////////
/////////////////////////////////////////////////

int main(int argc, char *argv[]){
    PIN_InitSymbols();
    if ( PIN_Init(argc,argv) ){ return -1; }
    string fileName = "taint_analysis_result.txt";
    if (!fileName.empty()) { out = new std::ofstream(fileName.c_str());}

    IMG_AddInstrumentFunction(Image, 0);
    INS_AddInstrumentFunction(Instruction, 0);
    TRACE_AddInstrumentFunction(Trace, 0);
    PIN_AddFiniFunction(Fini, 0);

    PIN_StartProgram();
    return 0;
}




실행결과


[Taint] fgets() : 
 buf : 0x12f76c
 size : 0x7d0
[tainted arg]0x0040113e : reader_taint.exe!myreadfile(0x12f76c, 0x61616161, 0x61616161...)
    arg1 : aaaaaaaaaa...
    arg2 : 
    arg3 : 
[Read][0x401029] : mov dl, byte ptr [ecx+0x5]
            dl is now tainted
            0x12f55f is now tainted
[Read][0x401035] : mov cl, byte ptr [eax+0x6]
            cl is now tainted
            0x12f55d is now tainted
[Read][0x401041] : mov al, byte ptr [edx+0x8]
            al is now tainted
            0x12f55e is now tainted
[Write][0x40104d] : mov byte ptr [ecx+0x2], 0x66
            0x12f76e is now freed
[Write][0x401054] : mov byte ptr [edx+0x4], 0x67
            0x12f770 is now freed
[Write][0x40105b] : mov byte ptr [eax+0xb], 0x68
            0x12f777 is now freed
[Write][0x401062] : mov byte ptr [ecx+0x15], 0x6d
            0x12f781 is now freed
[tainted arg]0x00401071 : reader_taint.exe!strcpy(0x12f560, 0x12f76c, 0x61616101...)
    arg1 : 
    arg2 : aafagaaaaa...
    arg3 : 
[tainted arg]0x004010a0 : reader_taint.exe!main(0x401143, 0x12f76c, 0x61666161...)
    arg1 : ƒÄëë3À‹...
    arg2 : aafagaaaaa...
    arg3 : 
[+] Finish!!


한줄 요약 : PIN 은 위대하다. 그러나 정말 제대로 활용하려면 어렵다..


'Reversing' 카테고리의 다른 글

암호학 정리(for CTF)  (0) 2018.04.05
WinDBG 고급 명령어들  (0) 2017.06.07
DBI - Frida 를 이용한 DBI  (3) 2016.09.07
Embedded 기기 리버싱 - 펌웨어 리버싱  (1) 2016.07.14
Windbg 기본 - (3) 분석시 유용한 명령어들  (2) 2016.03.01

+ Recent posts