1

I am writing a Pin tool with the following functionality:

  1. It has to record instructions with arguments. (works well)
  2. It has to record memory access operations associated with instructions. (works well)
  3. It has to record a name of a function that is being called (if the name is available from external library). This functionality is based on calltrace.cpp from examples provided with Intel Pin. (Partially works well)
  4. It has to record where a return instruction has landed (a function name, or, a main module of an instrumented executable). E.g. funcA is called, then funcB is called from funcA, then return from funcB lands in funcA. Recording of rets to functions partially works well, however I have no idea how to record return to the main module.

Before providing a source code let me describe what (as I think) is wrong with the output of a tool that I get.

  1. Recording begins with a set of instructions that ends with return to a function that has not been called (or at least my PinTool didn't record it).

[mov esp, esi]

[pop ebx]

R

[pop edi]

R

[pop esi]

R

[pop ebp]

R

[ret 0x10]

R

InDirect RETURN to[RtlAnsiCharToUnicodeChar]

  1. Sometimes it records names of the functions that are called without corresponding call instruction:

[push 0x77736e7c]

W

[push dword ptr [ebp-0x110]]

RW

[call 0x7779a490]

W

[LdrGetProcedureAddress]

[LdrGetProcedureAddressForCaller]

[RtlAcquireSRWLockExclusive]

  1. Similar is for rets. Even more sometimes it records return to the same function twice in a row (but it should not).

[call 0x777a8b60]

W

[RtlRetrieveNtUserPfn]

InDirect RETURN to[RtlDeactivateActivationContextUnsafeFast]

////OR////

[mov ecx, dword ptr [edi]]

R

[call 0x7777e531]

W

[RtlAddAccessAllowedAce]

[RtlAcquireSRWLockExclusive]

InDirect RETURN to[RtlAddAccessAllowedAce]

[RtlReleaseSRWLockExclusive]

InDirect RETURN to[RtlAddAccessAllowedAce]

InDirect RETURN to[RtlAddAccessAllowedAce]

[mov esi, eax]

I feel like there is something fundamentally wrong in the way I handle these calls and rets "decoding". Can someone point me to where am I exactly wrong? Also two secondary questions.

1) How to record return to the main module of an executable based on the instruction?

2) Is there a way to get values of IARG_BRANCH_TARGET_ADDR and IARG_BRANCH_TAKEN outside of INS_InsertCall (or similar) functions?

Thank you.

The source code is below.

#include <stdio.h>
//#include <chrono>
#include "pin.H"
#include <string>
#include <exception>

FILE * ftrace;
long long icount=0;
long long ilimit=1000000;
BOOL print_args=false;


string invalid = "invalid_rtn";
const string *Target2String(ADDRINT target)
{
    string name = RTN_FindNameByAddress(target);
    if (name == "")
        return &invalid;
    else
        return new string(name);
}

VOID  do_call_args(const string *s, ADDRINT arg0)
{
    fprintf(ftrace, "\n[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
    fflush(ftrace);
}

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

VOID  do_call_args_indirect(ADDRINT target, BOOL taken, ADDRINT arg0)
{
    if (!taken) return;

    const string *s = Target2String(target);
    do_call_args(s, arg0);

    if (s != &invalid)
        delete s;
}

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

VOID  do_call(const string *s)
{
    fprintf(ftrace, "\n[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
    fflush(ftrace);
}

VOID  do_ret(const string *s)
{
    fprintf(ftrace, "\nDirect RETURN to[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
    fflush(ftrace);
}

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

VOID  do_call_indirect(ADDRINT target, BOOL taken)
{
    if (!taken) return;

    const string *s = Target2String(target);
    do_call(s);

    if (s != &invalid)
        delete s;
}

VOID  do_ret_indirect(ADDRINT target, BOOL taken)
{
    if (!taken) return;

    const string *s = Target2String(target);
    fprintf(ftrace, "\nInDirect RETURN to[%s]\n", (*s).c_str()); //(INS_Disassemble(ins)).c_str()
    fflush(ftrace);

    if (s != &invalid)
        delete s;
}


VOID Instruction(INS ins, VOID *v)
{

    //start = std::chrono::high_resolution_clock::now();
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    fprintf(ftrace, "\n[%s]\n", (INS_Disassemble(ins)).c_str()); //(INS_Disassemble(ins)).c_str()
    fflush(ftrace);
    if (INS_IsCall(ins))
    {
        if (INS_IsDirectBranchOrCall(ins))
        {
            const ADDRINT target = INS_DirectBranchOrCallTargetAddress(ins);


            INS_InsertPredicatedCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_args),
                IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_END);

        }
        else
        {
            INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_indirect),
                IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_END);
        }
    }
    else
    {
        if (INS_IsRet(ins))
        {
            if (INS_IsDirectBranchOrCall(ins))
            {
                const ADDRINT target = INS_DirectBranchOrCallTargetAddress(ins);


                INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_ret),
                    IARG_PTR, Target2String(target), IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_END);

            }
            else
            {
                INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_ret_indirect),
                    IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_END);
            }
        }
        else
        {
            // sometimes code is not in an image
            RTN rtn = INS_Rtn(ins);

            // also track stup jumps into share libraries
            if (RTN_Valid(rtn) && !INS_IsDirectBranchOrCall(ins) && ".plt" == SEC_Name(RTN_Sec(rtn)))
            {
                if (print_args)
                {
                    INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_args_indirect),
                        IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_FUNCARG_CALLSITE_VALUE, 0, IARG_END);
                }
                else
                {
                    INS_InsertCall(ins, IPOINT_BEFORE, AFUNPTR(do_call_indirect),
                        IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_END);

                }
            }
        }
    }



        for (UINT32 memOp = 0; memOp < memOperands; memOp++)
        {

            if (INS_MemoryOperandIsRead(ins, memOp))
            {
                fprintf(ftrace, "R");
                icount++;

            }

            if (INS_MemoryOperandIsWritten(ins, memOp))
            {

                fprintf(ftrace, "W");
                icount++;

            }
        }

}
VOID Fini(INT32 code, VOID *v)
{    fprintf(ftrace, "\n");
    fclose(ftrace);
}
INT32 Usage()
{
    PIN_ERROR( "This Pintool prints a trace of memory addresses\n"
              + KNOB_BASE::StringKnobSummary() + "\n");
    return -1;
}
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
    "o", "pinatrace2.out", "specify output file name");

KNOB<long long> KnobInsLimit(KNOB_MODE_WRITEONCE, "pintool",
    "i", "1000", "specify instruction limit");

KNOB<BOOL>   KnobPrintArgs(KNOB_MODE_WRITEONCE, "pintool", "a", "0", "print call arguments ");

int main(int argc, char *argv[])
{
    PIN_InitSymbols();
    if (PIN_Init(argc, argv)) return Usage();   
    ilimit=KnobInsLimit.Value();   
    ftrace = fopen(KnobOutputFile.Value().c_str(), "w");
    print_args = KnobPrintArgs.Value();
    INS_AddInstrumentFunction(Instruction, 0);
    //TRACE_AddInstrumentFunction(Trace, 0);
    PIN_AddFiniFunction(Fini, 0);   
    PIN_StartProgram();

    return 0;
}
  • A partial solution to my question one could be the following: RTN insRoutine = INS_Rtn(ins); SEC insSection = RTN_Sec(insRoutine); IMG insImage = SEC_Img(insSection); Then apply filtering (or marking) with IMG_IsMainExecutable(insImage) – aGGeRReS Feb 7 at 9:51

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.