本文介绍了intel引脚:分析例程检测到ah寄存器而不是rsp(REG_STACK_PTR)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几天前,我问了这个问题.

我想获得堆栈分配大小(在函数创建之后).答案建议这样做:

I wanted to get the stack allocation size (after the function creation). The answer suggests to do:

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)

从理论上讲这是正确的并且确实是有道理的.但是,它在实践中不起作用(如果我在这里错了,请纠正我).如果我删除REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR检查,它会很好地工作.为什么?因为当使用REG(INS_OperandReg(ins, 0))进行检测时,引脚不会检测到REG_STACK_PTR寄存器.相反,当我检查add rsp, 0xffffffffffffff80指令时(它每次给出:register: ah),它都会检测到ah(我认为是RAX),如下面的输出所示:

Which in theory is correct and does make sense. But, it doesn't work in practice (correct me if I'm wrong here). It works perfectly fine if I remove REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR check. Why? Because pin doesn't detect the REG_STACK_PTR register when REG(INS_OperandReg(ins, 0)) is used to detect it. rather, it detects ah (which I believe is RAX), when I do check against add rsp, 0xffffffffffffff80 instruction (so, every time it gives: register: ah), as can be seen in my output below:

in
register: rbp
40051e  push rbp
register: *invalid*
value: -128
40051f  mov rbp, rsp
register: ah
400522  add rsp, 0xffffffffffffff80
register: *invalid*
400526  mov dword ptr [rbp-0x28], 0x7
register: *invalid*
40052d  mov dword ptr [rbp-0x64], 0x9
register: eax
400534  mov eax, 0x0
register: *invalid*
400539  call 0x4004e6
register: rbp
4004e6  push rbp
register: *invalid*
value: 64
4004e7  mov rbp, rsp
register: ah
4004ea  sub rsp, 0x40
register: *invalid*
4004ee  mov dword ptr [rbp-0xc], 0x4
register: rax
4004f5  lea rax, ptr [rbp-0xc]
register: *invalid*
4004f9  mov qword ptr [rbp-0x8], rax
register: rax
4004fd  mov rax, qword ptr [rbp-0x8]
register: eax
400501  mov eax, dword ptr [rax]
register: *invalid*
400503  mov esi, eax
register: edi
400505  mov edi, 0x4005d0
register: eax
40050a  mov eax, 0x0
register: rdi
40050f  call 0x4003f0
register: rdi
4003f0  jmp qword ptr [rip+0x200c22]
register: *invalid*
4003f6  push 0x0
register: *invalid*
4003fb  jmp 0x4003e0
register: *invalid*
4003e0  push qword ptr [rip+0x200c22]
register: rdi
4003e6  jmp qword ptr [rip+0x200c24]
4
register: *invalid*
400514  mov dword ptr [rbp-0x3c], 0x3
40051b  nop
register: *invalid*
40051c  leave 
register: *invalid*
40051d  ret 
register: eax
40053e  mov eax, 0x0
register: *invalid*
400543  leave 
out

好吧,有趣的是,它每次出现rsp都会执行此操作(即它检测到ah而不是rsp).另外,它总是打印指令400522 add rsp, 0xffffffffffffff80,包括rsp(所以,为什么这里不打印ah?)

Well, interestingly it does this for every occurrences of rsp (i.e. it detects ah instead of rsp). Also, it always prints the instruction 400522 add rsp, 0xffffffffffffff80, including rsp (So, why it doesn't print ah here?)

如果ah以某种方式表示rsp,那么我始终可以使用REG(INS_OperandReg(ins, 0)) == REG_AH检测到ah.但是,我想了解这里发生的事情.

If ah represents rsp in some way, then I can always detect ah using: REG(INS_OperandReg(ins, 0)) == REG_AH. But, I want to understand what is going on here.

我的代码:

#include <iostream>
#include <fstream>
#include "pin.H"
#include <unordered_map>

// key to open the main Routine
static uint32_t key = 0;

// Ins object mapping
class Insr
{
private:
  // Disassembled instruction
    string insDis;
  INS ins;

public:
    Insr(string insDis, INS ins) { this->insDis = insDis; this->ins = ins;}
    string get_insDis() { return insDis;}
  INS get_ins() { return ins;}
};

// Stack for the Insr structure
static std::unordered_map<ADDRINT, Insr*> insstack;

// This function is called before every instruction is executed
VOID protect(uint64_t addr)
{
  if (addr > 0x700000000000)
        return;
    if (!key)
        return;
  // Initialize the diassembled instruction
  string insdis = insstack[addr]->get_insDis();
  INS ins = insstack[addr]->get_ins();
    if (INS_OperandCount(ins) > 0)
    {
        if (REG(INS_OperandReg(ins, 0)) == REG_AH)
            std::cout << "register: " << REG_StringShort(REG(INS_OperandReg(ins, 0))) << '\n';
    }

  if((INS_Opcode(ins) == XED_ICLASS_ADD || INS_Opcode(ins) == XED_ICLASS_SUB) &&
   INS_OperandIsImmediate(ins, 1))
    {
      int value = INS_OperandImmediate(ins, 1);
        std::cout << "value: " << dec<<value << '\n';
    }
  std::cout << hex <<addr << "\t" << insdis << std::endl;
}

// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v)
{
        if (INS_Address(ins) > 0x700000000000)
        return;

    insstack.insert(std::make_pair(INS_Address(ins), new Insr(string(INS_Disassemble(ins)),
    ins)));
    // if (REG_valid_for_iarg_reg_value(INS_MemoryIndexReg(ins)))
    //   std::cout << "true" << '\n';
    // Insert a call to docount before every instruction, no arguments are passed
    INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)protect, IARG_ADDRINT, INS_Address(ins),
  IARG_END);
}

// Lock Routine
void mutex_lock()
{
key = 0;
std::cout<<"out\n";
}
void mutex_unlock()
{
    key = 1;
    std::cout<<"in\n";
}

void Routine(RTN rtn, VOID *V)
{
    if (RTN_Name(rtn) == "main")
    {
        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);
    }
}

INT32 Usage()
{
    cerr << "This tool counts the number of dynamic instructions executed" << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

int main(int argc, char * argv[])
{
    // Initialize the symbol table
    PIN_InitSymbols();

    // Initialize pin
    if (PIN_Init(argc, argv)) return Usage();

    PIN_SetSyntaxIntel();

    // Routine instrumentation
    RTN_AddInstrumentFunction(Routine, 0);

    // Register Instruction to be called to instrument instructions
    INS_AddInstrumentFunction(Instruction, 0);

    // Start the program, never returns
    PIN_StartProgram();

    return 0;
}

对此我几乎没有疑问.

能否请您帮助我了解这种行为?如果我想如何检测rsp?最后,指令如何打印rsp,但REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR无法检测到它?预先感谢.

Could you please help me understanding such a behavior? And how can I detect rsp if I want to? Lastly, how does the instruction prints rsp, but REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR can not detect it? Thanks in advance.

推荐答案

INS对象仅在检测例程(例如您的Instruction例程)内部有效. INS类型只不过是用于标识指令的32位整数. Pin运行时在内部维护一个表,该表将这些32位整数映射到特定的静态指令.每当要调用检测例程时,它都会创建一个这样的表.当检测例程返回时,不能保证这些标识符中的任何一个都映射到相同的静态指令,甚至可能无效.因此,当您在以下代码行中保存INS对象的副本时:

The INS objects are only valid inside instrumentation routines, such as your Instruction routine. The INS type is nothing but a 32-bit integer that identifies an instruction. The Pin runtime internally maintains a table that maps these 32-bit integers to specific static instructions. It creates such a table whenever it's about to call an instrumentation routine. When the instrumentation routine returns, there is no guarantee that any of these identifiers map to the same static instructions and they may not even be valid. So when you save a copy of an INS object in the following line of code:

insstack.insert(std::make_pair(INS_Address(ins), new Insr(string(INS_Disassemble(ins)),
    ins)));

该副本仅在Instruction例程的同一实例中有用.下次调用Instruction例程(或任何其他检测例程)时,指令标识符可能会被其他指令重用.

that copy is only useful in the same instance of the Instruction routine. The next time the Instruction routine is called (or any other instrumentation routine), an instruction identifier might be reused for other instructions.

如果您真的想将指令传递给分析例程,则有两种选择:

If you really want to pass an instruction to an analysis routine, you have two options:

  • 将指令的实际字节复制到缓冲区中,并传递缓冲区的地址,然后使用XED API对其进行解码.
  • 传递指令的地址,然后使用XED API对其进行解码.如果保证以后可以在同一位置使用该说明,则可以使用此方法.

这篇关于intel引脚:分析例程检测到ah寄存器而不是rsp(REG_STACK_PTR)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-16 06:40