C - Ошибка сегментации с ptrace и waitpid - PullRequest
0 голосов
/ 17 октября 2018

Для лабораторной школы в C мы должны закодировать процесс (мы будем называть его A), которому нужно присоединиться к другому процессу (B) и поместить ловушку в функцию (инструкция ловушки - 0xCC), поэтому мысделал это, но когда B входит в эту функцию, у нас есть ошибка сегментации

Так что это процесс A, который присоединяется к другим процессам

#include <stdio.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char *argv[]) {

pid_t pidTargetProgram;
FILE *file;
int buf;
char path[50];
long long int address;


if (argc == 2) {
   fprintf(stderr, "Argument waited !\n");
   exit(1);
 }

// The second argument is the PID of the program 
pidTargetProgram = atoi(argv[1]);

// The third argument is the address of the function where we are going to put a trap
address = strtoll(argv[2], NULL, 16);

// We put the path to the file mem of the program 
sprintf(path, "/proc/%s/mem", argv[1]);

// We attach to the other program
if(ptrace(PTRACE_ATTACH, pidTargetProgram, NULL, NULL) < 0) {
  perror("Error with ptrace_attach !");
  exit(1);
}

// We wait it to be synchronize
if (waitpid(pidTargetProgram, NULL, WUNTRACED) < 0) {
  perror("Error with waitpid !\n");
  exit(0);
  }



// We open the file mem in read and write mode
  if ((file = fopen(path, "r+")) == NULL) {
    perror("Error during the opening of mem file from process !");
    exit(1);
  }



// We place our cursor on the address of the function
  fseek(file, address, SEEK_SET);

  char trap[] = {0xCC, 0x00, 0x00, 0x00};

  // We put the trap in the foo function
  if (fwrite(trap, 1, 5, file) < 1) {
    perror("Error to write !");
    exit(1);
    }

  int counter = 0;

  fseek(file, address, SEEK_SET);

  // We print the other function's memory
  while (fread(&buf, 4, 1, file) > 0) {
    printf("Line n°%d : 0x%x\n", counter++, buf);
    }

  // We close the file
  if (fclose(file) != 0) {
    perror("Error during the closing !");
    exit(1);
  }

  // We said to continue to the other program
  if (ptrace(PTRACE_CONT, pidTargetProgram, NULL, NULL) < 0) {
    perror("Error during ptrace_cont !\n");
    exit(1);
    }

  printf("continued !\n");

  // We wait the other program stop
  if (waitpid(pidTargetProgram, NULL, WUNTRACED) < 0) {
    perror("Error with waitpid !\n");
    exit(0);
    }

  printf("Trace declenched !\n");

  // We detach 
  if (ptrace(PTRACE_DETACH, pidTargetProgram, NULL, NULL) < 0) {
    perror("Error during ptrace_detach !");
    exit(1);
    }

  printf("detach success ! \n");

  return 0;
}

И это процесс B:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

// Function to execute to take the trap
void foo(){
  int i = 0;
  printf("foo :::: %d", i);
}

int main(int argc, char *argv[]) {

  char text[10];
  pid_t pidProgram;

  // We get the PID
  pidProgram = getpid();

  // We print the PID
  fprintf(stdout, "PID's program : %d\n", pidProgram);

  // We print the address of foo()
  fprintf(stdout, "foo address : %p\n", &(foo));

  // We stop the program to lunch the other program
  fgets(text, 10, stdin);

  int i;
  for(i = 0 ; i < 100 ; i++){
    foo(i);
  }

  return 0;
}

Чтобы выполнить это, мы сначала запускаем B, поэтому он дает нам PID и адрес и делает паузу на fgets.Итак, после этого мы запускаем программу A и даем ей PID и адрес, это остановка на втором waitpid.После этого мы продолжаем B и что-то пишем, и у нас возникает ошибка сегментации, и мы останавливаемся.Мы не понимаем, почему, потому что в памяти мы можем ясно видеть ловушку (0xCC), и она не работает. Но в программе A трассировка отключена!Успех!

Так что нет ошибки на A, но B имеет ошибку сегментации

Есть ли у вас идеи для этого?Мы используем Centos в качестве операционной системы.Извините за мой английский.

Спасибо

Жюльен

1 Ответ

0 голосов
/ 17 октября 2018

Программа работает должным образом:

Сначала вы меняете образ запущенного процесса на 0xcc в начале функции foo, которая вызывает точку останова / прерывание.

Затем вы вызываете эту функцию, пока процесс отслеживается процессом a.Так что этот звонок

waitpid(pidTargetProgram, NULL, WUNTRACED) < 0) // Process a

возвращается.Теперь вы отсоединяетесь от процесса b с помощью

ptrace(PTRACE_DETACH, pidTargetProgram, NULL, NULL);

, однако ранее не восстанавливали перезаписанные инструкции в процессе!Таким образом, следующие инструкции будут повреждены и приведут к появлению ошибки, которую вы наблюдаете.Кроме того, процесс перезапускается на следующей инструкции PC + 1 (сразу после 0xcc), поэтому вам необходимо вернуть ПК обратно на один байт, используя PTRACE_GETREGS/PTRACE_SETREGS

Btw.более элегантно использовать интерфейс ptrace для установки и сброса инструкции точки останова с помощью PTRACE_POKETEXT вместо использования способа /proc/pid/mem.

TL; DR: сначала необходимо восстановить исходные инструкции и сброситьПК до перезапуска процесса b, тогда он должен работать как вы ожидаете.

...