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.)