Sistema Linux: análisis de la llamada al sistema ptrace

Tabla de contenido

1. Introducción a ptrace

2. Explicación detallada de la función ptrace

3. Leer valor de registro de hilo


1. Introducción a ptrace

  Ptrace proporciona un proceso padre que puede controlar la ejecución del proceso hijo y puede comprobar y cambiar su imagen principal. Se utiliza principalmente para implementar la depuración de puntos de interrupción. Se está ejecutando un proceso de seguimiento hasta que se produce una señal. El proceso finaliza y se notifica a su proceso principal. En el estado de suspensión del proceso, el espacio de memoria del proceso se puede leer y escribir. El proceso padre también puede continuar la ejecución del proceso hijo y elegir si ignora la señal que causó la suspensión. Por supuesto, el proceso de seguimiento aquí no solo se limita al proceso hijo, sino también a cualquier otro proceso o subproceso.

2. Explicación detallada de la función ptrace

long ptrace(enum __ptrace_request request,pid_t pid,void *addr, void *data);
  • Solicitud de parámetro: la operación solicitada por ptrace
  • Parámetro pid: ID del proceso de destino
  • Dirección de parámetro: el valor de la dirección del proceso de destino
  • Datos de parámetros: la función varía según la solicitud. Si necesita escribir datos en el proceso de destino, los datos almacenan los datos que deben escribirse; si lee datos del proceso de destino, los datos almacenarán los datos devueltos.

El parámetro de solicitud determina el comportamiento de CODE y cómo se utilizan los parámetros posteriores. Los valores más utilizados de la solicitud de parámetro son los siguientes:

3. Leer valor de registro de hilo

La lectura de los registros de otros procesos o subprocesos también es un método de uso común, como obtener el rip y rbp del subproceso para el seguimiento de la pila.

Proceso / hilo de destino

#include <stdio.h>
#include <unistd.h> //for sleep
#include <stdlib.h> //for exit
#include <pthread.h>//for pthread
#include <errno.h>  //for errno
#include <sys/syscall.h> //for gettid
#define gettid() syscall(__NR_gettid)

void func_test(){
    int i = 0,sum = 0;
	while(1){
		i++;
		sum +=i;
		sleep(1);
	}
}
 
void *func(void *para){
    printf("child process tid: %u\n", gettid());
	func_test();
    return NULL;
}
 
int main(){ 
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, func, NULL);
    if(ret != 0)
    {   
        exit(errno);
    }   
    printf("\nparent process pid: %u\n", getpid());
 
    pthread_join(tid, NULL);
    return 0;
}

Leer operación:

#define _GNU_SOURCE
#include <sys/ptrace.h>
#include <stdlib.h>     // for atoi
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>  //for errno
#include <sys/user.h> /* For user_regs_struct */
#include <dlfcn.h>
#include <string.h>
#include <sys/syscall.h> //for gettid
#define gettid() syscall(__NR_gettid)

int main(int argc, char *argv[])
{ 
	if(argc != 2) {
		printf("Usage: %s <pid to be traced> ");
		exit(1);
	}   
	pid_t traced_process = atoi(argv[1]);
	struct user_regs_struct regs;   
	int ret = ptrace(PTRACE_ATTACH, traced_process, NULL, NULL);
	if(ret == -1){
		printf("attach failed,ret is %ld ,errno is %d,strerror(errno) is %s. \n", ret, errno, strerror(errno));
		return -1;
	}else{
		printf("attach ok...\n");
	}
	
	wait(NULL);
	
	ret = ptrace(PTRACE_GETREGS, traced_process,NULL, &regs);
	if(ret == -1){
		printf("get register failed,ret is %ld ,errno is %d,strerror(errno) is %s. \n", ret, errno, strerror(errno));
		return -1;
	}else{
	    printf("RIP: %lx,RBP: %lx\n", regs.rip, regs.rbp);
	}

	ret = ptrace(PTRACE_DETACH, traced_process, NULL, NULL);
	if(ret == -1){
		printf("detach failed,ret is %ld ,errno is %d,strerror(errno) is %s. \n", ret, errno, strerror(errno));
		return -1;
	}else{
		printf("detach ok...\n");
	}
	return 0;
}

Resultados de:

[root@localhost read_thread_regs]# gcc target_thread.c -o target_thread -lpthread
[root@localhost read_thread_regs]# ./target_thread &
[15] 27668
[root@localhost read_thread_regs]#
parent process pid: 27668
Hello world.
child process tid: 27669

[root@localhost read_thread_regs]# ./read_regs 27668
attach ok...
RIP: 31cf4082fd,RBP: 0
detach ok...
[root@localhost read_thread_regs]# ./read_regs 27669
attach ok...
RIP: 31ce8aca7d,RBP: 7f3afd481d40
detach ok...
[root@localhost read_thread_regs]#

Explicación:
1. Cuando se adjunta el proceso / subproceso de destino, el estado de la tarea se establecerá temporalmente en el estado T (parada). El estado se restaura cuando se ejecuta la desconexión.
2. Al adjuntar un subproceso o una tarea de proceso (tarea), las otras tareas del proceso no se ven afectadas y el estado permanece sin cambios.
3. La tarea de destino de adjuntar no puede ser el proceso en sí mismo o un subproceso secundario del proceso, el código de error errno es 1: operación no permitida

Supongo que te gusta

Origin blog.csdn.net/wangquan1992/article/details/108471212
Recomendado
Clasificación