c-英特尔引脚:如何替换/跳过系统调用



我想在64位linux 4.4.0-33上运行的静态二进制文件中替换/模拟系统调用,最好使用Intel Pin

文档中有PIN_AddSyscallEntryFunction(...)https://software.intel.com/sites/landingpage/pintool/docs/98484/Pin/html/group__SYSCALL.html

但它似乎无法跳过真正的系统调用,我是不是遗漏了什么?谷歌没有这么做:(

我可以尝试在syscall入口回调中用无效的id替换syscall,并在syscall出口回调中修补retval,但我不想做这些

似乎还有其他较低级别的功能(例如。https://software.intel.com/sites/landingpage/pintool/docs/98484/Pin/html/group__INS__REF.html)但我想先尝试更高级别的功能,以提高可读性,并充分利用Pin的潜力,熟悉工具

--背景--

我已经使用LD_PRELOAD实现了一个(HDFS的(虚拟文件系统,让任何程序都可以使用特殊路径/hdfs/...访问HDFS,但它不适用于静态链接的二进制文件,而且它有太多的拦截点(open和open64、seek和fseek、fputs等(

以下是我考虑过的方法,如果有更好的方法,请提出建议:

  1. LD_PRELOAD替换打开/读取/写入/…//不适用于静态链接的二进制文件,所以我在这里尝试Pin
  2. ptrace/SYSEMU//它看起来太复杂,可能存在性能问题
  3. nfs/fuse/…//太复杂,需要适应太多协议,只能用于vfs,以后需要时无法扩展到支持其他技术(例如挂钩套接字操作(
  4. sysenter/syscall替换为int3//是否应与Pin相同?SIGTRAP会更慢

除了Pin还有其他选择吗?https://github.com/pmem/syscall_intercept也依赖于LD_PRELOAD,所以没有运气

Pin允许在使用INS_InsertCall()的指令之前添加函数调用。您可以在syscall指令之前添加函数的调用。此函数将检查syscall参数,并在必要时模拟系统调用。系统调用的参数仅通过寄存器传递,因此有必要将CONTEXT对象传递给函数。这个对象保持处理器的状态,并允许获取寄存器值。此外,此对象可以传递给PIN_ExecuteAt()以跳过syscall指令:

#include "pin.H"
#include <sys/syscall.h>
VOID syscall_handler(CONTEXT* ctx) {
bool skip_orig_sycall = true;
switch (PIN_GetContextReg(ctx, REG_RAX)) {
case SYS_write:
// emulate the syscall here or
// just notify the app that somthing went wrong with write() call
PIN_SetContextReg(ctx, REG_RAX, static_cast<ADDRINT>(-1));
break;
default:
skip_orig_sycall = false;
break;
}
if (skip_orig_sycall) {
const ADDRINT syscall_ins_size = 2;
const ADDRINT cur_ip = PIN_GetContextReg(ctx, REG_RIP);
PIN_SetContextReg(ctx, REG_RIP, cur_ip + syscall_ins_size);
PIN_ExecuteAt(ctx); // continue execution after syscall instruction
}
}
VOID image_load(IMG img, VOID* v) {
if(!IMG_IsMainExecutable(img)) {
return;
}
for (SEC sec = IMG_SecHead(img); SEC_Valid(sec); sec = SEC_Next(sec)) {
for (RTN rtn = SEC_RtnHead(sec); RTN_Valid(rtn); rtn = RTN_Next(rtn)) {
RTN_Open(rtn);
for (INS ins = RTN_InsHead(rtn); INS_Valid(ins); ins = INS_Next(ins)) {
if (INS_IsSyscall(ins)) {
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)syscall_handler,
IARG_CONTEXT, IARG_END);
}
}
RTN_Close(rtn);
}
}
}
int main(int argc, char* argv[]) {
if (PIN_Init(argc, argv)) {
PIN_ERROR("Cannot initialize Pin");
return EXIT_FAILURE;
}
PIN_InitSymbols();
IMG_AddInstrumentFunction(image_load, 0);
PIN_StartProgram();
return EXIT_SUCCESS;
}

最新更新