本文介绍了使用Intel Pin工具的堆栈分配大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下C代码:

#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;
}

我创建了以下PIN工具:

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;

}

它给了我以下输出:

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

main 函数的情况下,我想获取值0xffffffffffffff80;在函数 foo 的情况下,我要获取0x40值.简而言之,我想在函数创建后获取已分配的堆栈位置.因此,可以通过检测特定指令(在这种情况下为add/sub rsp),然后修整输出以获得特定字符串,来完成此操作.另一种方法是获取rbp或rsp的值(如果我在这里错了,请纠正我).

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

我在此处查看PIN API文档,还看到了这里,但仍然找不到获取特定字符串值的方法.

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.

推荐答案

source/tools/SimpleExamples/oper-imm.cpp中的示例pintool显示了如何获取立即操作数.看起来像这样:

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

在您的情况下,i为1,因为您需要检查第二个操作数是否为立即数.您还需要检查第一个操作数是否是显式的RSP寄存器,并且指令是ADD还是SUB.本质上,您需要找到第一个这样的指令.

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*.
}

某些编程语言或特定的实现可能允许在动态大小的堆栈上分配变量.例如,大多数C/C ++实现都提供alloca,它通常从堆栈中分配内存.作为另一个示例,C#语言提供了stackalloc关键字.因此,第二个操作数不一定总是立即数,并且可以有多个ADD/SUB指令将吞吐量分配给从堆栈分配/取消分配内存的功能.

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.

这篇关于使用Intel Pin工具的堆栈分配大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-16 06:40