【发布时间】:2018-01-02 01:40:30
【问题描述】:
我写了一个pintool。它在执行指令时为程序实现堆栈。如果遇到调用指令,它将按顺序将下一条指令的地址压入堆栈。当被调用的过程完成并遇到返回指令时,它会验证 ret 指令中的目标地址是否等于栈顶并弹出栈顶。
通常调用指令的数量应该等于返回指令的数量。但是这个工具会监控大量的返回指令。这怎么可能?问题是什么?我该如何解决?
编辑 1:
pintool的代码
VOID f_jump(int a, int b)
{
s.push(b);
cout<<s.top()<<"\t";
icount1++;
}
VOID f_ret(int a, int b)
{
if (b==s.top())
{
cout<<s.top();
s.pop();
cout<<"\tOK"<<endl;
}
else
cout<<"Exploit\t"<<endl<<s.top()<<"\t"<<b<<endl;
icount2++;
}
VOID Instruction(INS ins, VOID *v)
{
if( INS_IsCall(ins) )
{
INS_InsertCall(ins,IPOINT_TAKEN_BRANCH,AFUNPTR(f_jump),
IARG_BRANCH_TARGET_ADDR,IARG_RETURN_IP, IARG_END);
}
if( INS_IsRet(ins) )
{
INS_InsertCall(ins,IPOINT_BEFORE,AFUNPTR(f_ret),
IARG_INST_PTR,IARG_BRANCH_TARGET_ADDR, IARG_END);
}
}
我在各种二进制文件和进程上运行它,但问题仍然存在。请帮忙。
【问题讨论】:
-
一个函数只能有一个入口点(调用的目标),但可以有多个出口点(ret指令)。
-
问:您是否尝试过生成程序集输出(例如
gcc -S)并检查程序集源?问:如果函数碰巧有多个“返回”退出,您的工具会“检测”多个“RET”调用吗?在我们推测之前,我们真的需要更多信息...... -
从技术上讲,编译器可以通过组合
pushs 和jmps 来解决没有calls 的问题。在某些情况下,这可能对性能有好处。不过,我不知道您的编译器是否适合这种黑客行为。关于您的评论,我认为其他人假设您在谈论分析程序集输出,而不是实际执行路径。 -
从技术上讲,编译器还可以使用
ret指令来生成跳转,例如如push <some address>, ret。如果需要动态跳转目标但没有可用于基于寄存器的跳转的可用寄存器,这会很方便。不过,这种情况非常罕见。 -
@Prof,您将不得不发布一些代码:pintool 的简短版本,以及您运行它的程序。
标签: c++ operating-system cpu-architecture intel-pin