如何在pintool中获得内存有效的数组地址?

时间:2015-11-17 22:27:35

标签: intel-pin

我尝试打印数组的内存位置(有效地址),我发现了以下内容:

1-第一种方式:通过使用(以读取操作为例)
IARG_MEMORYREAD_EA
作为分析函数的参数并在此函数中打印此值,(内存读取的有效地址,仅在INS_IsMemoryRead为真且在IPOINT_BEFORE时有效。)

2-第二种方式:通过插入回叫:

INS_OperandMemoryDisplacement(INS ins,UINT32 n)
INS_OperandMemoryBaseReg(INS ins,UINT32 n)
INS_OperandMemoryIndexReg(INS ins,UINT32 n)
INS_OperandMemoryScale(INS ins,UINT32 n)

返回用于在内存操作数中寻址的位移,基址寄存器,索引寄存器和比例值,并通过以下等式计算有效地址:

有效地址=置换+ BaseReg + IndexReg *比例

它们之间有什么区别,实现这一目标的最佳方式是什么?

1 个答案:

答案 0 :(得分:2)

问题有点复杂。

很难知道你是否正在索引数组,因为任何内存位置都可以被视为只有一个条目的数组(并且该指令只使用基数寄存器)。

除了检查是否存在基数,索引,比例和位移(我认为我们都可以想到在不使用SIB [scale,index,base]和一个指令中的位移的情况下将索引编入数组的各种设计方法),在哪种情况下我们知道几乎当然它是一个数组。

为了在合理的基础上保持问题,让我们说使用SIB(或SIB + disp)的所有指令都索引到一个数组中,而另一个指令则没有。

  1. 你的第一种方式不会告诉你是否有SIB指令,只是告诉你你有内存访问权[除非你检查指令是否有SIB]。
  2. 此外,你需要检查它是一个读(IARG_MEMORYREAD_EA)还是写(IARG_MEMORYWRITE_EA),你不会得到很好的细节(比如数组的基地址是什么,索引和比例值是多少,多少是位移)。

    1. 我认为第二种方式是合适的方式。从我的POV(注意你可以混合两种方法)不一定更简单但更详尽。
    2. 这就是我要做的事情(代码没有经过测试,只是一个基本的想法;适用于读写访问):

      // we need at least one op
      UINT32 op_count = INS_OperandCount(ins);
      if(op_count == 0) {
          return;
      }
      
      // search for the operand which could be a memory operand
      UINT32 current_op;
      BOOL found_mem_op = FALSE;
      for(current_op = 0; current_op < op_count; ++current_op) {
          // operand generates an address (LEA) or operand is directly a mem op
          if(INS_OperandIsAddressGenerator(ins, current_op) || INS_OperandIsMemory(ins, current_op)) {
              found_mem_op = TRUE;
              break;
          }
      }
      
      // check if we could find a memory operand
      if(!found_mem_op) {
          return;
      }
      
      // get base, index, scale and displacement
      REG reg_base = INS_OperandMemoryBaseReg(ins, current_op);
      REG reg_index = INS_OperandMemoryIndexReg(ins, current_op);
      UINT32 scale = INS_OperandMemoryScale(ins, current_op);
      ADDRDELTA disp = INS_OperandMemoryDisplacement(ins, current_op);
      
      // both base and index must be valid to proceed
      if(REG_valid(reg_base) && REG_valid(reg_index)) {
      
          // get base register value
          INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)GetRegVal, 
                  IARG_REG_VALUE,
                  reg_base,
                  IARG_END);
      
          ADDRINT reg_base_value = value_reg; //value_reg is obtained by GetRegVal() 
      
          // get index register value
          INS_InsertCall(ins, IPOINT_AFTER, (AFUNPTR)GetRegVal, 
                  IARG_REG_VALUE,
                  reg_index,
                  IARG_END);
      
          ADDRINT reg_index_value = value_reg;
      
          ADDRINT final_address = reg_base_value + (reg_index_value * scale) + disp;   
      }
      

      source/tools/Tests/ea_verifier.cpp中的PIN测试套件中也有一个有趣的例子(参见IntrumentAccess函数)。