Solaris: Navegando en el /proc (III)

Kernel, OpenSolaris Dejar un comentario

Uno de los ficheros más interesante que podemos encontrar en el FS /proc, es sin duda /proc/< PID >/as, el cual contiene una imagen del espacio de direcciones de memoria del proceso. Para leer el contenido de este fichero no necesitamos ningún tipo de estructura de datos, ni está formado por arrays, sencillamente son datos, a los que se puede acceder mediante la dirección que ocupan en la memoria.


Si conocemos en qué posición de memoria se encuentra un dato, por ejemplo un entero, podemos abrir el fichero /proc/< PID >/as, mediante la llamada open() y desplazar el puntero hasta dicha posición y leer el dato. Esto nos permite muchas posibilidades, como son el poder ver el contenido de la pila de un proceso, o cual es el contenido de una zona de memoria anónima determinada.

Comprobando los permisos que tiene el fichero vamos a llevarnos una grata sorpresa y es que tiene permisos de escritura para el propietario, esto nos va a permitir poder escribir directamente en este fichero, lo que significa que podremos modificar zonas de memoria de un proceso, ESTO PUEDE SER BASTANTE PELIGROSO PARA NUESTRO SISTEMA, como root podemos modificar el contenido de cualquier espacio de direcciones, incluido el del kernel, pero esto lo veremos en otro momento.

Para conocer las posibilidades que nos ofrece el acceso en lectura/escritura al espacio de direcciones de cualquier proceso, vamos a realizar un sencillo ejercicio, en el que desarrollaremos 2 pequeños programas en C:

ejemplo1.c

Consiste en un programa que dispone de un contador, el cual se irá incrementando cada 5 segundos.

     1  #include < stdio.h >
     2
     3  void main()
     4  {
     5  int *cont;
     6
     7  cont=malloc(sizeof(int));
     8  *cont=0;
     9  printf("n Dir. Memoria de la varable cont: 0x%lx  %lun",cont,cont);
    10  for(;;)
    11          {
    12          printf("n Contador: %d",*cont);
    13          sleep(5);
    14          *cont=*cont+1;
    15          }
    16
    17  return;
    18  }

Una vez compilado, al ejecutar el programa, la salida será parecida a la siguiente:

(root@huelva)# ./ejemplo1

 Dir. Memoria de la varable cont: 0x209d8  133592

 Contador: 0
 Contador: 1
 Contador: 2
 Contador: 3
 Contador: 4
 Contador: 5
 Contador: 6
 Contador: 7
 Contador: 8^C
(root@huelva)#

Presenta la dirección de memoria de la variable cont, la cual como podemos ver en la línea 5 de ejemplo1.c es de tipo puntero a un entero. Cada 5 segundos se incrementará el contenido de la dirección donde apunta *cont. Podemos dejar corriendo ejemplo1.

proc_as_wr.c

Este programa aceptará como parámetros el PID de un proceso y una dirección de memoria, el PID lo utilizará para abrir el fichero del espacio de direcciones del proceso y la dirección de memoria, para, en primer lugar leer su contenido y posteriormente incremetar dicho contenido en 100.


     1  #include < stdio.h >
     2  #include < sys/types.h >
     3  #include < sys/stat.h >
     4  #include < fcntl.h >
     5
     6  #define _STRUCTURED_PROC 1
     7  #include < sys/procfs.h >
     8
     9  main(int argc, char **argv)
    10  {
    11
    12  long puntero,addr;
    13  int i_cont;
    14  int fd;
    15  char cadena[80];
    16  int pid;
    17
    18  if (argc<2)
    19          {printf("nn     Uso: %s < pid >  < addr >nn",argv[0]);return;}
    20
    21  pid=atoi(argv[1]);
    22  addr=atol(argv[2]);
    23
    24  printf("n PID:%d   Direccion de memoria:  0x%lx (%ld)n",pid,addr,addr);
    25
    26  sprintf(cadena,"/proc/%d/as",pid);
    27  fd=open(cadena,O_RDWR);
    28
    29  if (fd<0)
    30          {printf("n Error: Abriendo el fichero %sn",cadena);return;}
    31  printf("n Abriendo el fichero %sn",cadena);
    32
    33  if (lseek(fd,addr,SEEK_SET)<0)
    34          {printf("nError: Leyendo el fichero %sn",cadena);return;}
    35
    36  if(read(fd,&i_cont,sizeof(i_cont))<0)
    37          {printf("nError: Escribiendo el fichero %sn",cadena);return;}
    38
    39  printf("n La direccion de memoria 0x%lx (%ld) =  %dn",addr,addr,i_cont);
    40
    41  i_cont=i_cont+100;
    42
    43  if (lseek(fd,addr,SEEK_SET)<0)
    44          {printf("nError: Leyendo el fichero %sn",cadena);return;}
    45
    46  if (write(fd,&i_cont,sizeof(i_cont))<0)
    47          {printf("nError: Escribiendo el fichero %sn",cadena);return;}
    48
    49  printf("n Se ha escrito corretamente en la posicion  0x%lx (%ld)nn",addr,addr);
    50
    51  close(fd);
    52  }

Una vez que compilemos el programa podemos realizar la prueba de nuestro ejemplo, para ello ejecutaremos ejemplo1 en un terminal y lo dejaremos ejecutandose, tenemos que recordar la dirección de memoria del contador.

(root@huelva)# ./ejemplo1

 Dir. Memoria de la varable cont: 0x209d8  133592

 Contador: 0
 Contador: 1
 Contador: 2
 Contador: 3
...

Como vemos en la salida de ejemplo1 la dirección de memoria en hexadecimal 0x209d8 y en decimal 133592, abrimos otro terminal y ejecutamos el programa proc_as_wr con los siguientes parámetros, pero antes debemos saber cual es el PID con el que se está ejecutando ejemplo1.

(root@huelva)# ps -ef | grep ejemplo
    root 17783 25395  0 23:12:27 pts/1    0:00 grep ejemplo
    root 17397 25512  0 23:08:10 pts/3    0:00 ./ejemplo1
(root@huelva)#
(root@huelva)#
(root@huelva)#  ./proc_as_wr 17397 133592

 PID:17397   Direccion de memoria:  0x209d8 (133592)

 Abriendo el fichero /proc/17397/as

 La direccion de memoria 0x209d8 (133592) =  64

 Se ha escrito corretamente en la posicion  0x209d8 (133592)

(root@huelva)#

Si comprobamos el terminal donde se está ejecutando ejemplo1 comprobaremos que el contador se ha incrementado en 100.

Este es un sencillo ejemplo de como podemos hacer uso del fichero /proc/< PID >/as y sobre todo de lo sencillo que es modificar algo del espacio de direcciones de un proceso.

Navegando en el /proc (II)<< | >> Navegando en el /proc (IV)

Technorati Tag(s) :

Los comentarios están cerrados.

My name is null, /dev/null
Algunos derechos reservados. Licencia Creative Commons