1

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

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)

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

有效地址 = Displacement + BaseReg + IndexReg * Scale

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

4

1 回答 1

2

问题有些复杂。

很难知道您是否正在对数组进行索引,因为任何内存位置都可以被视为只有 1 个条目的数组(并且该指令仅使用基本 reg)。

除了检查是否有基数、索引、比例和位移(我认为我们都可以想到各种人为的索引到数组中的方法,而无需在一条指令中使用 SIB [比例、索引、基数] 和位移),在这种情况下,我们几乎可以肯定它是一个数组。

为了使问题保持​​合理,假设所有使用 SIB(或 SIB + disp)的指令都索引到数组中,而另一个则没有。

  1. 您的第一种方法不会告诉您是否有 SIB 指令,它只会告诉您您有内存访问权限 [除非您随后检查指令是否有 SIB]。

此外,您需要检查它是读取 (IARG_MEMORYREAD_EA) 还是写入 (IARG_MEMORYWRITE_EA),并且您不会获得详细信息(例如数组的基地址是什么,索引和比例值是多少,位移是多少)。

  1. 第二种方式是正确的,我认为。从我的 POV 来看,不一定更简单但更详尽(请注意,您可以混合使用这两种方法)。

这是我要做的(代码未经测试,只是一个基本想法;适用于读写访问):

// 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 函数)。

于 2015-11-18T18:24:47.027 回答