I have following c code:
#include <stdio.h>
int foo()
{
int a = 4;
int *p = &a;
printf("%i\n", *p);
int b[10];
b[1] = 3;
}
int main(void)
{
int a[10], b[20];
a[2] = 7;
b[7] = 9;
foo();
return 0;
}
I created following PIN tool:
#include <fstream>
#include <iostream>
#include "pin.H"
// Additional library calls go here
/*********************/
// Output file object
ofstream OutFile;
//static uint64_t counter = 0;
uint32_t lock = 0;
uint32_t unlock = 1;
std::string rtin = "";
// Make this lock if you want to print from _start
uint32_t key = unlock;
void printmaindisas(uint64_t addr, std::string disassins)
{
std::stringstream tempstream;
tempstream << std::hex << addr;
std::string address = tempstream.str();
if (key)
return;
if (addr > 0x700000000000)
return;
std::cout<<address<<"\t"<<disassins<<std::endl;
}
void mutex_lock()
{
key = !lock;
std::cout<<"out\n";
}
void mutex_unlock()
{
key = lock;
std::cout<<"in\n";
}
void Instruction(INS ins, VOID *v)
{
// if (INS_IsStackWrite(ins) == true)
// {
// std::cout << "Stack write instruction: " << INS_Disassemble(ins) << '\n';
// }
// Insert a call to docount before every instruction, no arguments are passed
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printmaindisas, IARG_ADDRINT, INS_Address(ins),
IARG_PTR, new string(INS_Disassemble(ins)), IARG_END);
//std::cout<<INS_Disassemble(ins)<<std::endl;
}
void Routine(RTN rtn, VOID *V)
{
if (RTN_Name(rtn) == "main")
{
//std::cout<<"Loading: "<<RTN_Name(rtn) << endl;
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);
}
}
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "mytool.out", "specify output file name");
/*
VOID Fini(INT32 code, VOID *v)
{
// Write to a file since cout and cerr maybe closed by the application
OutFile.setf(ios::showbase);
OutFile << "Count " << count << endl;
OutFile.close();
}
*/
int32_t Usage()
{
cerr << "This is my custom tool" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
int main(int argc, char * argv[])
{
// It must be called for image instrumentation
// Initialize the symbol table
PIN_InitSymbols();
// Initialize pin
// PIN_Init must be called before PIN_StartProgram
// as mentioned in the documentation
if (PIN_Init(argc, argv)) return Usage();
// Open the output file to write
OutFile.open(KnobOutputFile.Value().c_str());
// Set instruction format as intel
// Not needed because my machine is intel
PIN_SetSyntaxIntel();
RTN_AddInstrumentFunction(Routine, 0);
//IMG_AddInstrumentFunction(Image, 0);
// Add an isntruction instrumentation
INS_AddInstrumentFunction(Instruction, 0);
//PIN_AddFiniFunction(Fini, 0);
// Start the program here
PIN_StartProgram();
return 0;
}
It gives me following output:
in
40051e push rbp
40051f mov rbp, rsp
400522 add rsp, 0xffffffffffffff80
400526 mov dword ptr [rbp-0x28], 0x7
40052d mov dword ptr [rbp-0x64], 0x9
400534 mov eax, 0x0
400539 call 0x4004e6
4004e6 push rbp
4004e7 mov rbp, rsp
4004ea sub rsp, 0x40
4004ee mov dword ptr [rbp-0xc], 0x4
4004f5 lea rax, ptr [rbp-0xc]
4004f9 mov qword ptr [rbp-0x8], rax
4004fd mov rax, qword ptr [rbp-0x8]
400501 mov eax, dword ptr [rax]
400503 mov esi, eax
400505 mov edi, 0x4005d0
40050a mov eax, 0x0
40050f call 0x4003f0
4003f0 jmp qword ptr [rip+0x200c22]
4003f6 push 0x0
4003fb jmp 0x4003e0
4003e0 push qword ptr [rip+0x200c22]
4003e6 jmp qword ptr [rip+0x200c24]
4
400514 mov dword ptr [rbp-0x3c], 0x3
40051b nop
40051c leave
40051d ret
40053e mov eax, 0x0
400543 leave
out
I want to get the value 0xffffffffffffff80
in the case of main function and 0x40
in case of function foo. In short I want to get the stack place which has been allocated, after function creation. So, one way this can be done is by detecting the particular instruction, say add/sub rsp in this case and then trimming the output to get the particular string. Another way would be by getting the value of rbp or rsp (correct me if I'm wrong here).
I check the pin api documentation here and also saw some examples given here, but still couldn't find the way to get the particular string values.
Following the documentation I tried this:
if (INS_RegR(ins, 0) == REG_RSP)
std::cout << "rsp: " << REG_Size(REG_RSP) << '\n';
But, still couldn't figure out how to get the values.
The sample pintool from source/tools/SimpleExamples/oper-imm.cpp
shows how to get immediate operands. It looks like this:
if (INS_OperandIsImmediate(ins, i))
{
// Get the value itself
ADDRINT value = INS_OperandImmediate(ins, i);
// Determine the size and the signedness of the immediate value.
}
In your case, i
is 1 because you need to check whether the second operand is an immediate value. You also need to check whether the first operand is an explicit RSP
register and that the instruction is ADD
or SUB
. Essentially, you need to find the first such instruction.
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))
{
// 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*.
}
Some programming languages or specific implementations may allow allocating variables on the stack of dynamic sizes. For example, most C/C++ implementations offer alloca
, which typically allocates memory from the stack. As another example, the C# language offers the stackalloc
keyword. Therefore, the second operand is not necessarily always immediate and there can be multiple ADD
/SUB
instructions spread throughput the function that allocate/deallocate memory from the stack.