0

I asked this question before. The answer explains I am working on the same Pin-tool. But, my question is rather broad.

If I have an instruction: mov eax, dword ptr [rbp-0x4] I can get the displacement(-0x4) using (pin api): INS_MemoryDisplacement(ins)

Which gives me:

std::cout << abs(INS_MemoryDisplacement(ins)) << '\n';

4

But, if I have the same instruction: mov eax, dword ptr [rbp-0x4]

Then:

std::cout << abs(INS_MemoryDisplacement(ins)) << '\n';

0

In short it doesn't give me the correct displacement, where it supposed to.

My PIN code:

#include <iostream>
#include <cstdlib>
#include <fstream>
#include "pin.H"
#include <unordered_map>
#include <stack>

// key to open the main Routine
static uint32_t key = 0;

// To save the malloc area
struct mallocArea
{
  UINT64  base;
  UINT64  size;
  BOOL    status;
};

// Main stack to store the stack size
struct Node
{
    // Total stack size allocated
    uint64_t value;
    // Upper limit
    uint64_t cu;
    // Lower limit
    uint64_t cl;
};

std::stack<Node> mainStack;

// Ins object mapping
class Insr
{
private:
  // Disassembled instruction
    string insDis;
  INS ins;

public:
    Insr(string insDis, INS ins) { this->insDis = insDis; this->ins = ins;}
    string get_insDis() { return insDis;}
  INS get_ins() { return ins;}
};

// Stack for the Insr structure
static std::unordered_map<ADDRINT, Insr*> insstack;

// This function is called before every instruction is executed
VOID protect(uint64_t addr)
{
  if (addr > 0x700000000000)
        return;
    if (!key)
        return;
  // Initialize the diassembled instruction
  string insdis = insstack[addr]->get_insDis();
  INS ins = insstack[addr]->get_ins();

    // If the function is returned then pop the value off the stack
    if (INS_Opcode(ins) == XED_ICLASS_LEAVE && mainStack.size() >= 2)
    {
        std::cout << hex << "Popping out: " << mainStack.top().value << '\n';
        mainStack.pop();
        std::cout << hex <<"stack top: " << mainStack.top().value << " as leaving" << '\n';
    }
    // instructions executed in the main routine
  std::cout << hex <<addr << "\t" << insdis << std::endl;
}

VOID protect_store(uint64_t addr)
{
  if (addr > 0x700000000000)
        return;
    if (!key)
        return;
  string insdis = insstack[addr]->get_insDis();
  INS ins = insstack[addr]->get_ins();

  // Check for array bounds

  if (INS_MemoryDisplacement(ins) >= 0
  && ((INS_OperandMemoryBaseReg(ins, 0) == REG_RBP)
  || (INS_OperandMemoryBaseReg(ins, 0) == REG_EBP)))
  {
      std::cout << "Access over allowed bounds detected!" << '\n';
  }
  else if (INS_MemoryDisplacement(ins) < 0
  && ((INS_OperandMemoryBaseReg(ins, 0) == REG_RSP)
  || (INS_OperandMemoryBaseReg(ins, 0) == REG_ESP)))
  {
      std::cout << "Access over allowed bounds detected!" << '\n';
  }
  else
  {
    std::cout << "@@@@@@@@@@@@@" << '\n';
    std::cout << "Store: " << abs(INS_MemoryDisplacement(ins)) << '\n';
    std::cout << hex <<addr << "\t" << insdis << std::endl;
    std::cout << "@@@@@@@@@@@@@" << '\n';
    if (abs(INS_MemoryDisplacement(ins)) >= static_cast<int64_t>(mainStack.top().value)){
      std::cout <<"Overflow detected: " <<abs(INS_OperandMemoryDisplacement(ins, 0)) << ":"
        << mainStack.top().value << "\t" << insdis  <<'\n';
    }
  }
}

VOID protect_load(uint64_t addr)
{

  if (addr > 0x700000000000)
        return;
    if (!key)
        return;

  string insdis = insstack[addr]->get_insDis();
  INS ins = insstack[addr]->get_ins();

  if (INS_OperandCount(ins) < 2)
  {
    std::cout << hex <<addr << "\t" << insdis << "!!!!" << std::endl;
    std::cout << "oprand count: " << INS_OperandCount(ins) << '\n';
    return;
  }
  // Check for array bounds
  if (INS_MemoryDisplacement(ins) >= 0
  && ((INS_OperandMemoryBaseReg(ins, 1) == REG_RBP)
  || (INS_OperandMemoryBaseReg(ins, 1) == REG_EBP)))
  {
      std::cout << "Access over allowed bounds detected!" << '\n';
      //std::cout << hex <<addr << "\t" << insdis << std::endl;
  }
  else if (INS_MemoryDisplacement(ins) < 0
  && ((INS_OperandMemoryBaseReg(ins, 1) == REG_RSP)
  || (INS_OperandMemoryBaseReg(ins, 1) == REG_ESP)))
  {
      std::cout << "Access over allowed bounds detected!" << '\n';
      //std::cout << hex <<addr << "\t" << insdis << std::endl;
  }
  else
  {
    std::cout << "##########" << '\n';
    std::cout << "Load: " << abs(INS_MemoryDisplacement(ins)) << '\n';
    std::cout << hex <<addr << "\t" << insdis << std::endl;
    std::cout << "##########" << '\n';
    if (abs(INS_MemoryDisplacement(ins)) >= static_cast<int64_t>(mainStack.top().value))
      std::cout << hex<<"Overflow detected: " << INS_MemoryDisplacement(ins) << ":"
      << mainStack.top().value << "\t" << insdis <<'\n';
  }
}

VOID stack_size(uint64_t addr, CONTEXT * ctxt)
{
    if (addr > 0x700000000000)
        return;
    if (!key)
        return;
    // Get the corresponsing instruction to print
    string insdis = insstack[addr]->get_insDis();
    // Print stack and base pointer registers
    std::cout << hex << "Reg::" << PIN_GetContextReg(ctxt, REG_RSP) << '\n';
    std::cout << hex << "Reg::" << PIN_GetContextReg(ctxt, REG_RBP) << '\n';

    // MPX mpx takes the total size size as a upper bound for the last allocated array
    // We don't know the individual array bounds
    // We will define rsp as lower bound and rbp as the upper bound
    // Total stack size
    uint64_t value = PIN_GetContextReg(ctxt, REG_RBP) - PIN_GetContextReg(ctxt, REG_RSP);
    Node node{value, PIN_GetContextReg(ctxt, REG_RBP), PIN_GetContextReg(ctxt, REG_RSP)};
    mainStack.push(node);
    std::cout << hex << "Pushed the value: " << dec << node.value << " on the stack" << '\n';

    // Print the disassembly
    //std::cout << insdis << '\n';
}

// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
        // if (INS_Address(ins) > 0x700000000000)
        // return;
    insstack.insert(std::make_pair(INS_Address(ins), new Insr(string(INS_Disassemble(ins)),
    ins)));
    // if (REG_valid_for_iarg_reg_value(INS_MemoryIndexReg(ins)))
    //   std::cout << "true" << '\n';
        if((INS_Opcode(ins) == XED_ICLASS_ADD || INS_Opcode(ins) == XED_ICLASS_SUB) &&
           REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR && INS_OperandIsImmediate(ins, 1))
        {
            INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)stack_size, IARG_ADDRINT, INS_Address(ins),
            IARG_CONTEXT,
      IARG_END);
          // Obtain the immediate operand information as shown above.
          // You can obtain the RSP register value before or after the instruction by
          // passing IARG_REG_VALUE, REG_STACK_PTR to INS_Insert*.
        }
//##########################################################
    if ((INS_Opcode(ins) == XED_ICLASS_MOV) && INS_OperandIsMemory(ins, 0)
      && ((INS_OperandWidth(ins, 0) == 32)
          || (INS_OperandWidth(ins, 0) == 64))
      && ((INS_OperandMemoryBaseReg(ins, 0) == REG_RBP)
      || (INS_OperandMemoryBaseReg(ins, 0) == REG_EBP)
      || (INS_OperandMemoryBaseReg(ins, 0) == REG_RSP)
      || (INS_OperandMemoryBaseReg(ins, 0) == REG_ESP)))
      INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)protect_store, IARG_ADDRINT, INS_Address(ins),
    IARG_END);

    if ((INS_Opcode(ins) == XED_ICLASS_MOV) && INS_OperandIsMemory(ins, 1)
        && ((INS_OperandWidth(ins, 1) == 32)
                || (INS_OperandWidth(ins, 1) == 64))
        && ((INS_OperandMemoryBaseReg(ins, 1) == REG_RBP)
        || (INS_OperandMemoryBaseReg(ins, 1) == REG_EBP)
        || (INS_OperandMemoryBaseReg(ins, 1) == REG_RSP)
        || (INS_OperandMemoryBaseReg(ins, 1) == REG_ESP)))
      {
        if (INS_Address(ins) > 0x700000000000)
            return;
        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)protect_load, IARG_ADDRINT, INS_Address(ins),
        IARG_END);
      }
//##########################################################
        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)protect, IARG_ADDRINT, INS_Address(ins),
    IARG_END);
    // Insert a call to docount before every instruction, no arguments are passed
}

// Lock Routine
void mutex_lock()
{
key = 0;
std::cout<<"out\n";
}
void mutex_unlock()
{
    key = 1;
    std::cout<<"in\n";
}

VOID malloc_before(CHAR * name, ADDRINT size)
{
    if (!key)
        return;
    std::cout << name << "(" << size << ")" << '\n';
}

VOID malloc_after(ADDRINT ret)
{
    if (!key)
        return;
    std::cout << "\treturns " << ret << '\n';
}

void Routine(RTN rtn, VOID *V)
{
    if (RTN_Name(rtn) == "main")
    {
        RTN_Open(rtn);
        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)mutex_unlock, IARG_END);
        RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)mutex_lock, IARG_END);
        RTN_Close(rtn);
    }
}

void Image(IMG img, VOID *v)
{
    // Find the malloc function
    RTN mallocRtn = RTN_FindByName(img, "malloc");
    // Find the free() function.
    RTN freeRtn = RTN_FindByName(img, "free");

    if (RTN_Valid(mallocRtn))
    {
        RTN_Open(mallocRtn);

        // Instrument malloc() to print the input argument value and the return value.
        RTN_InsertCall(mallocRtn, IPOINT_BEFORE, (AFUNPTR)malloc_before,
                       IARG_ADDRINT, "malloc",
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                       IARG_END);
        RTN_InsertCall(mallocRtn, IPOINT_AFTER, (AFUNPTR)malloc_after,
                       IARG_FUNCRET_EXITPOINT_VALUE, IARG_END);

        RTN_Close(mallocRtn);
    }

    if (RTN_Valid(freeRtn))
    {
        RTN_Open(freeRtn);
        // Instrument free() to print the input argument value.
        RTN_InsertCall(freeRtn, IPOINT_BEFORE, (AFUNPTR)malloc_before,
                       IARG_ADDRINT, "free",
                       IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
                       IARG_END);
        RTN_Close(freeRtn);
    }
}

INT32 Usage()
{
    cerr << "This tool counts the number of dynamic instructions executed" << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

int main(int argc, char * argv[])
{
    // Initialize the symbol table
    PIN_InitSymbols();

    // Initialize pin
    if (PIN_Init(argc, argv)) return Usage();

    PIN_SetSyntaxIntel();

    // Routine instrumentation
    RTN_AddInstrumentFunction(Routine, 0);

    // Image instrumentation
    IMG_AddInstrumentFunction(Image, 0);

    // Register Instruction to be called to instrument instructions
    INS_AddInstrumentFunction(Instruction, 0);

    // Start the program, never returns
    PIN_StartProgram();

    return 0;
}

And my (partial) output:

##########
Load: 4
4006d9  mov eax, dword ptr [rbp-0x4]
##########
4006d9  mov eax, dword ptr [rbp-0x4]
4006dc  movsxd rdx, eax
##########
Load: 18
4006df  mov rax, qword ptr [rbp-0x18]
##########
4006df  mov rax, qword ptr [rbp-0x18]
4006e3  add rax, rdx
4006e6  mov edx, ecx
4006e8  mov byte ptr [rax], dl
4006ea  add dword ptr [rbp-0x4], 0x1
4006ee  cmp dword ptr [rbp-0x4], 0x9
4006f2  jle 0x4006ae
4006ae  call 0x400510
400510  jmp qword ptr [rip+0x200b22]
4006b3  mov ecx, eax
4006b5  mov edx, 0xb21642c9
4006ba  mov eax, ecx
4006bc  imul edx
4006be  lea eax, ptr [rdx+rcx*1]
4006c1  sar eax, 0x4
4006c4  mov edx, eax
4006c6  mov eax, ecx
4006c8  sar eax, 0x1f
4006cb  sub edx, eax
4006cd  mov eax, edx
4006cf  imul eax, eax, 0x17
4006d2  sub ecx, eax
4006d4  mov eax, ecx
4006d6  lea ecx, ptr [rax+0x61]
##########
Load: 4
4006d9  mov eax, dword ptr [rbp-0x4]
##########
4006d9  mov eax, dword ptr [rbp-0x4]
4006dc  movsxd rdx, eax
##########
Load: 18
4006df  mov rax, qword ptr [rbp-0x18]
##########
4006df  mov rax, qword ptr [rbp-0x18]
4006e3  add rax, rdx
4006e6  mov edx, ecx
4006e8  mov byte ptr [rax], dl
4006ea  add dword ptr [rbp-0x4], 0x1
4006ee  cmp dword ptr [rbp-0x4], 0x9
4006f2  jle 0x4006ae
4006ae  call 0x400510
400510  jmp qword ptr [rip+0x200b22]
4006b3  mov ecx, eax
4006b5  mov edx, 0xb21642c9
4006ba  mov eax, ecx
4006bc  imul edx
4006be  lea eax, ptr [rdx+rcx*1]
4006c1  sar eax, 0x4
4006c4  mov edx, eax
4006c6  mov eax, ecx
4006c8  sar eax, 0x1f
4006cb  sub edx, eax
4006cd  mov eax, edx
4006cf  imul eax, eax, 0x17
4006d2  sub ecx, eax
4006d4  mov eax, ecx
4006d6  lea ecx, ptr [rax+0x61]
##########
Load: 4
4006d9  mov eax, dword ptr [rbp-0x4]
##########
4006d9  mov eax, dword ptr [rbp-0x4]
4006dc  movsxd rdx, eax
##########
Load: 18
4006df  mov rax, qword ptr [rbp-0x18]
##########
4006df  mov rax, qword ptr [rbp-0x18]
4006e3  add rax, rdx
4006e6  mov edx, ecx
4006e8  mov byte ptr [rax], dl
4006ea  add dword ptr [rbp-0x4], 0x1
4006ee  cmp dword ptr [rbp-0x4], 0x9
4006f2  jle 0x4006ae
4006ae  call 0x400510
400510  jmp qword ptr [rip+0x200b22]
4006b3  mov ecx, eax
4006b5  mov edx, 0xb21642c9
4006ba  mov eax, ecx
4006bc  imul edx
4006be  lea eax, ptr [rdx+rcx*1]
4006c1  sar eax, 0x4
4006c4  mov edx, eax
4006c6  mov eax, ecx
4006c8  sar eax, 0x1f
4006cb  sub edx, eax
4006cd  mov eax, edx
4006cf  imul eax, eax, 0x17
4006d2  sub ecx, eax
4006d4  mov eax, ecx
4006d6  lea ecx, ptr [rax+0x61]
##########
Load: 4
4006d9  mov eax, dword ptr [rbp-0x4]
##########
4006d9  mov eax, dword ptr [rbp-0x4]
4006dc  movsxd rdx, eax
##########
Load: 18
4006df  mov rax, qword ptr [rbp-0x18]
##########
4006df  mov rax, qword ptr [rbp-0x18]
4006e3  add rax, rdx
4006e6  mov edx, ecx
4006e8  mov byte ptr [rax], dl
4006ea  add dword ptr [rbp-0x4], 0x1
4006ee  cmp dword ptr [rbp-0x4], 0x9
4006f2  jle 0x4006ae
##########
Load: 0
4006f4  mov eax, dword ptr [rbp-0x4]
##########
4006f4  mov eax, dword ptr [rbp-0x4]
4006f7  movsxd rdx, eax
4006fa  mov rax, qword ptr [rbp-0x18]!!!!
oprand count: 1
4006fa  mov rax, qword ptr [rbp-0x18]
4006fe  add rax, rdx
400701  mov byte ptr [rax], 0x0
##########
Load: 0
400704  mov eax, dword ptr [rbp-0x4]
##########
400704  mov eax, dword ptr [rbp-0x4]
400707  movsxd rdx, eax
##########
Load: 0
40070a  mov rax, qword ptr [rbp-0x10]
##########
40070a  mov rax, qword ptr [rbp-0x10]
40070e  add rax, rdx
400711  mov byte ptr [rax], 0x0
##########
Load: 0
400714  mov rax, qword ptr [rbp-0x10]
##########
400714  mov rax, qword ptr [rbp-0x10]
400718  mov rdi, rax
40071b  call 0x4004e0
4004e0  jmp qword ptr [rip+0x200b3a]
4004e6  push 0x1
4004eb  jmp 0x4004c0
4004c0  push qword ptr [rip+0x200b42]
4004c6  jmp qword ptr [rip+0x200b44]
malloc(400)
    returns 23392b0
lagcgaoblb
##########
Load: 18
400720  mov rax, qword ptr [rbp-0x18]
##########
400720  mov rax, qword ptr [rbp-0x18]
400724  mov rdi, rax
400727  call 0x4004e0
4004e0  jmp qword ptr [rip+0x200b3a]
rqgrjrpkim
##########
Load: 10
40072c  mov rax, qword ptr [rbp-0x10]
##########
40072c  mov rax, qword ptr [rbp-0x10]
400730  mov rdi, rax
400733  call 0x4004d0
4004d0  jmp qword ptr [rip+0x200b42]
4004d6  push 0x0
4004db  jmp 0x4004c0
4004c0  push qword ptr [rip+0x200b42]
4004c6  jmp qword ptr [rip+0x200b44]
free(2339260)
##########
Load: 18
400738  mov rax, qword ptr [rbp-0x18]
##########
400738  mov rax, qword ptr [rbp-0x18]
40073c  mov rdi, rax
40073f  call 0x4004d0
4004d0  jmp qword ptr [rip+0x200b42]
free(2339280)
400744  mov eax, 0x0
400749  call 0x400606
400606  push rbp
400607  mov rbp, rsp
40060a  sub rsp, 0x10
Reg::7ffc01478c70
Reg::7ffc01478c80
Pushed the value: 16 on the stack
@@@@@@@@@@@@@
Store: 4
40060e  mov dword ptr [rbp-0x4], 0x2
@@@@@@@@@@@@@
40060e  mov dword ptr [rbp-0x4], 0x2
##########
Load: 4
400615  mov eax, dword ptr [rbp-0x4]
##########
400615  mov eax, dword ptr [rbp-0x4]
@@@@@@@@@@@@@
Store: 8
400618  mov dword ptr [rbp-0x8], eax
@@@@@@@@@@@@@
400618  mov dword ptr [rbp-0x8], eax
##########
Load: 8
40061b  mov eax, dword ptr [rbp-0x8]
##########
40061b  mov eax, dword ptr [rbp-0x8]
40061e  mov esi, eax
400620  mov edi, 0x4007e0
400625  mov eax, 0x0
40062a  call 0x4004f0
4004f0  jmp qword ptr [rip+0x200b32]
4004f6  push 0x2
4004fb  jmp 0x4004c0
4004c0  push qword ptr [rip+0x200b42]
4004c6  jmp qword ptr [rip+0x200b44]
2
40062f  nop
Popping out: 10
stack top: 20 as leaving
400630  leave 
400631  ret 
40074e  mov eax, 0x0
400753  leave 
out

My c code:

#include <stdio.h>
#include <stdlib.h>

void foo()
{

  int a = 2;
  int val;
  val = a;
  printf("%i\n", val);

}

int main()
{
  int i;
  char *str;
  str = (char*)malloc(15);
  char * xx = (char*)malloc(30);

  for (i = 0; i < 10; ++i)
  {
    str[i] = rand()%23+'a';
  }
  for (i = 0; i < 10; ++i)
  {
    xx[i] = rand()%23+'a';
  }
  xx[i] = '\0';
  str[i] = '\0';

  printf("%s\n", str);
  printf("%s\n", xx);
  free(str);
  free(xx);
  foo();
  return 0;

}

Does this behavior happen because of malloc call? (Correct me if I'm wrong here.)

halfer
  • 19,824
  • 17
  • 99
  • 186
R4444
  • 2,016
  • 2
  • 19
  • 30
  • 1
    `INS_MemoryDisplacement` sometimes returns 4 and sometimes 0 for `mov eax, dword ptr [rbp-0x4]`? – Hadi Brais Apr 07 '19 at 19:26
  • Yes. And not only in case of dword, but it sometimes happens in case of qword (as given in my output). – R4444 Apr 07 '19 at 19:27
  • 1
    The instruction trace you have shown does not seem to be from the Pin tool you have shown. For example, I don't see where the Pin tool prints `Load: 10` or `Load: 4`. Also what does the number after the colon mean? – Hadi Brais Apr 07 '19 at 19:32
  • Sorry Hadi my bad. I mistakenly posted another code. Now I have posted the correct code. The number means displacement. Sorry about that. – R4444 Apr 07 '19 at 19:38
  • 1
    Well, you've made the same mistake as in your previous [question](https://stackoverflow.com/questions/55382659/intel-pin-analysis-routine-detects-ah-register-instead-of-rsp-reg-stack-ptr) and the answer is the same. The `ins` object is only guaranteed to be valid in the instrumentation routine for which it was created. It cannot be reliably used in analysis routines. That's exactly why sometimes it works and sometimes doesn't. – Hadi Brais Apr 07 '19 at 19:49
  • I think I should I have thought that before asking here. Okay my mistake. But, thanks again for your comment. – R4444 Apr 07 '19 at 19:52

0 Answers0