Linux: Выполнение системного вызова через ptrace () - PullRequest
4 голосов
/ 31 марта 2011

Привет :) В настоящее время я занимаюсь разработкой библиотеки для установки памяти для Linux x86 / x64. Суть в том, что я пытаюсь реализовать какое-то удаленное выполнение системного вызова.

Вот мой код, который просто сбивает другой процесс, когда я пытаюсь выполнить действительный системный вызов.

(Все мои функции, используемые в коде, являются обертками вокруг ptrace) Вы можете найти полный код здесь: http://code.google.com/p/ethonmem/source/browse/

long Debugger::executeSyscall(
  unsigned long code, std::vector<unsigned long> const& args) const
{
  // Backup registers.
  Registers buRegs = getRegisters(buRegs);
  FpuRegisters buFregs = getFpuRegisters(buFregs);

  // Get register set to modify.
  Registers regs = buRegs;

  #if __WORDSIZE == 32

  // EAX stores the syscall code.
  regs.eax = code;

  // If less than 7 args exist, they are stored in registers.
  size_t argCount = args.size();
  if(argCount < 7)
  {
    while(argCount)
    {
      switch(argCount)
      {
      case 1:
        regs.ebx = args[0];
        break;

      case 2:
        regs.ecx = args[1];
        break;

      case 3:
        regs.edx = args[2];
        break;

      case 4:
        regs.esi = args[3];
        break;

      case 5:
        regs.edi = args[4];
        break;

      case 6:
        regs.ebp = args[5];
        break;
      }

      --argCount;
    }
  }

  // Otherwise we have to use memory.
  else
  {
    // Get stack space.
    regs.esp -= argCount * sizeof(unsigned long);

    // Write arguments to stack.
    for(size_t i = 0; i < argCount; ++i)
      writeWord(regs.esp + i * sizeof(unsigned long), args[i]);

    // EBX stores the address.
    regs.ebx = regs.esp;
  }

  // Write INT 0x80-instruction to current instruction pointer position.
  unsigned long const oldInstruction = readWord(regs.eip);

  uint8_t newInstruction[sizeof(long)] = { 0xCD, 0x80, 0xCC, 0xCC };
  writeWord(regs.eip, *reinterpret_cast<unsigned long*>(&newInstruction[0]));

  #elif __WORDSIZE == 64

  // RAX stores the syscall code.
  regs.rax = code;

  // If less than 7 args exist, they are stored in registers.
  size_t argCount = args.size();
  if(argCount < 7)
  {
    while(argCount)
    {
      switch(argCount)
      {
      case 1:
        regs.rdi = args[0];
        break;

      case 2:
        regs.rsi = args[1];
        break;

      case 3:
        regs.rdx = args[2];
        break;

      case 4:
        regs.r10 = args[3]; // Or RCX ???
        break;

      case 5:
        regs.r8 = args[4];
        break;

      case 6:
        regs.r9 = args[5];
        break;
      }

      --argCount;
    }
  }

  // Otherwise this fails.
  else
  {
    BOOST_THROW_EXCEPTION(EthonError() <<
      ErrorString("More than 6 arguments passed to a 64bit syscall"));
  }

  // Write SYSCALL-instruction to current instruction pointer position.
  unsigned long const oldInstruction = readWord(regs.rip);

  uint8_t newInstruction[sizeof(long)] =
    { 0x0F, 0x05, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC };
  writeWord(regs.rip, *reinterpret_cast<unsigned long*>(&newInstruction[0]));
  #endif

  // Apply new registers.
  setRegisters(regs);

  // Step to begin of syscall.
  stepSyscall();

  // Step to end of syscall.
  stepSyscall();

  // Fetch return value and restore patched word
  getRegisters(regs);

  long returnValue;
  #if __WORDSIZE == 32
    returnValue = regs.eax;
    writeWord(regs.eip, oldInstruction);
  #elif __WORDSIZE == 64
    returnValue = regs.rax;
    writeWord(regs.rip, oldInstruction);
  #endif

  // Restore registers.
  setRegisters(buRegs);
  setFpuRegisters(buFregs);

  return returnValue;
}

Кто-нибудь может обнаружить мою ошибку? Спасибо :) С Уважением, Florian

Ответы [ 2 ]

3 голосов
/ 01 сентября 2012

Знаете ли вы, был ли% rip увеличен до следующей инструкции, когда произойдет системный вызов?Обычно после e8 или e9 (call / jmp) и, возможно, после системного вызова 0f05,% rip указывает на адрес после вызова, а не на него напрямую.Использование% rip - 2 может исправить это.

0 голосов
/ 09 апреля 2011

Просто дикое предположение, вы уверены, что все адреса памяти, переданные в качестве аргумента syscall, действительны?

...