我尝试打印数组的内存位置(有效地址),我发现了以下内容:
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 *比例
它们之间有什么区别,实现这一目标的最佳方式是什么?
答案 0 :(得分:2)
问题有点复杂。
很难知道你是否正在索引数组,因为任何内存位置都可以被视为只有一个条目的数组(并且该指令只使用基数寄存器)。
除了检查是否存在基数,索引,比例和位移(我认为我们都可以想到在不使用SIB [scale,index,base]和一个指令中的位移的情况下将索引编入数组的各种设计方法),在哪种情况下我们知道几乎当然它是一个数组。
为了在合理的基础上保持问题,让我们说使用SIB(或SIB + disp)的所有指令都索引到一个数组中,而另一个指令则没有。
此外,你需要检查它是一个读(IARG_MEMORYREAD_EA)还是写(IARG_MEMORYWRITE_EA),你不会得到很好的细节(比如数组的基地址是什么,索引和比例值是多少,多少是位移)。
这就是我要做的事情(代码没有经过测试,只是一个基本的想法;适用于读写访问):
// 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函数)。