问题有些复杂。
很难知道您是否正在对数组进行索引,因为任何内存位置都可以被视为只有 1 个条目的数组(并且该指令仅使用基本 reg)。
除了检查是否有基数、索引、比例和位移(我认为我们都可以想到各种人为的索引到数组中的方法,而无需在一条指令中使用 SIB [比例、索引、基数] 和位移),在这种情况下,我们几乎可以肯定它是一个数组。
为了使问题保持合理,假设所有使用 SIB(或 SIB + disp)的指令都索引到数组中,而另一个则没有。
- 您的第一种方法不会告诉您是否有 SIB 指令,它只会告诉您您有内存访问权限 [除非您随后检查指令是否有 SIB]。
此外,您需要检查它是读取 (IARG_MEMORYREAD_EA) 还是写入 (IARG_MEMORYWRITE_EA),并且您不会获得详细信息(例如数组的基地址是什么,索引和比例值是多少,位移是多少)。
- 第二种方式是正确的,我认为。从我的 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 函数)。