问题描述
几天前,我问了这个问题.
我想获得堆栈分配大小(在函数创建之后).答案建议这样做:
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)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!