3

I am using Intel Pin in order trace memory activity of an executable on Windows. What I have found, that most of the memory operands (Read or Write) operates with 2 or 4 bytes. So I decided to modify original Pin's pinatrace example, in order to see which Assembly opcodes produces which memory activity.

VOID Instruction(INS ins, VOID *v)
{

        UINT32 memOperands = INS_MemoryOperandCount(ins);
        fprintf(trace,"\n[%s]\n",(INS_Disassemble(ins)).c_str()); 
        for (UINT32 memOp = 0; memOp < memOperands; memOp++)
        { 
             .....

What it basically does (I hope), is just writes disassembled opcode BEFORE the memory operands it produces. But then I looked in the file (W is for write, R is for read):

[test edx, 0x800000]

[jnz 0x77708557]

[mov dword ptr [ebp-0x4], edi]

[test dl, 0x1]

[jnz 0x77703136] RWWRWW

[lea edi, ptr [ebx+0xcc]]

[push dword ptr [edi]]

[call 0x77702520] RWW

[mov edi, edi]

[push ebp]

[mov ebp, esp]

[mov eax, dword ptr [ebp+0x8]]

[mov ecx, dword ptr fs:[0x18]]

[lea edx, ptr [eax+0x4]]

[lock btr dword ptr [edx], 0x0]

[jnb 0x777041dc]

[mov ecx, dword ptr [ecx+0x24]]

[mov dword ptr [eax+0xc], ecx]

[mov dword ptr [eax+0x8], 0x1]

[mov eax, 0x1]

[pop ebp]

[ret 0x4] WRRRWRWWRR

As we can see, opcodes that are supposed to work with memory (e.g. mov) do not produce memory operands. While memory traces are connected as blocks after ret/call/jnz etc.

Question: What kind of memory operands does Intel Pin trace? Is it about calls to virtual memory/RAM/CPU registers? Could it be possible, that memory activity goes in blocks due to CPU's pipeline?

2 Answers 2

1

So, finally I came up with the solution that works how I want and results seem to be valid according to this reference of instruction tables

fprintf(trace,"\n[%s]\n",(INS_Disassemble(ins)).c_str()); //(INS_Disassemble(ins)).c_str()
fflush(trace);
   
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
    if (INS_MemoryOperandIsRead(ins, memOp))
    {
        fprintf(trace,"R");
        icount++;
    }

    if (INS_MemoryOperandIsWritten(ins, memOp))
    {
        fprintf(trace,"W");
        icount++;
    }
}

And it produces the following output:

[mov eax, dword ptr [ebp+0x10]]
R
[mov byte ptr [ebx+0x2], 0x0]
W
[mov byte ptr [ebx+0x7], 0x0]
W

I cannot be sure that it is the true sequence of executable under analysis because I do output in the instrumentation phase, but the code can probably be modified it the way to write opcode inside another INS_InsertPredicatedCall, so it will be recorded when it will be executed.

0

If you want to limit your print-out to just memory read/write instructions, your fprintf() needs to be inside the if (INS_MemoryOperandIsRead(ins, memOp)) { ... } block and inside the if (INS_MemoryOperandIsWritten(ins, memOp)) { ... } block (and you'll need to include some logic to not print the same instruction more than once).

For example:

// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v)
{
    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP 
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    BOOL printed = FALSE;

    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++)
    {
        if (INS_MemoryOperandIsRead(ins, memOp))
        {
            if (!printed)
            {
                fprintf(trace,"\n[%s]\n",(INS_Disassemble(ins)).c_str()); 
                printed = TRUE;
            }

            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
        // Note that in some architectures a single memory operand can be 
        // both read and written (for instance incl (%eax) on IA-32)
        // In that case we instrument it once for read and once for write.
        if (INS_MemoryOperandIsWritten(ins, memOp))
        {
            if (!printed)
            {
                fprintf(trace,"\n[%s]\n",(INS_Disassemble(ins)).c_str()); 
                printed = TRUE;
            }

            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
    }
}
4
  • This is an interesting suggestion. But when I tried I received the following: > [pop ebx] > > [pop edi] > > [pop esi] > > [pop ebp] > > [ret 0x10] > > RRRRR > > [mov byte ptr [ebp-0x19], al] > > [mov dword ptr [ebp-0x4], ebx] > > [call 0x7770c290] > > WWW > > [call 0x776f2165] > > W > > [push ebp] > > [mov eax, dword ptr fs:[0x18]]
    – aGGeRReS
    Apr 7, 2016 at 14:14
  • Well, comment formatting doesn't work well, but as you can see - there are still opcodes with no memory operations. Do you exactly know what kind of memory operations (to what kind of memory) Pin traces?
    – aGGeRReS
    Apr 7, 2016 at 14:15
  • Every instruction you printed above does indeed involve a memory read or write. pops and rets read from the stack memory, the movs write to memory, the calls read from memory, and the push writes to the stack memory. Apr 7, 2016 at 14:47
  • Allright, thank you. But they all work with data stored in RAM (not taking CPU's cache into account, since pages are synchronized), am I right? And why there is no read operations after calls so far?
    – aGGeRReS
    Apr 7, 2016 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.