2008-09-16 13 views
11

Además del truco LD_PRELOAD, y los módulos del kernel de Linux que reemplazan una llamada del sistema con una proporcionada por usted, existe la posibilidad de interceptar un syscall (abrir, por ejemplo), para que primero pase por su función, antes de llegar al real abierto ?¿cómo podría interceptar llamadas de linux sys?

+1

La pregunta necesita aclararse, es demasiado vaga. ¿Por qué LD_PRELOAD no es suficiente? – Arafangion

+7

@Arafangion - LD_PRELOAD le permite interceptar llamadas de la biblioteca. Pero las llamadas al núcleo son algo diferente. –

Respuesta

1

si realmente necesita una solución que podría estar interesado en el rootkit DR que lleva a cabo sólo por esta, http://www.immunityinc.com/downloads/linux_rootkit_source.tbz2 el artículo sobre el tema es que aquí http://www.theregister.co.uk/2008/09/04/linux_rootkit_released/

+3

¿Por qué sugerir un método oscuro cuando existen otras alternativas mucho más convencionales? LD_PRELOAD es el más común. – Arafangion

+0

porque no estaba buscando los más convencionales, o al menos eso es lo que reuní de su pregunta original – sztanpet

15

¿Por qué no puede/no quiere utilizar el truco LD_PRELOAD?

Código de ejemplo aquí:

/* 
* File: soft_atimes.c 
* Author: D.J. Capelis 
* 
* Compile: 
* gcc -fPIC -c -o soft_atimes.o soft_atimes.c 
* gcc -shared -o soft_atimes.so soft_atimes.o -ldl 
* 
* Use: 
* LD_PRELOAD="./soft_atimes.so" command 
* 
* Copyright 2007 Regents of the University of California 
*/ 

#define _GNU_SOURCE 
#include <dlfcn.h> 
#define _FCNTL_H 
#include <bits/fcntl.h> 

extern int errorno; 

int (*_open)(const char * pathname, int flags, ...); 
int (*_open64)(const char * pathname, int flags, ...); 

int open(const char * pathname, int flags, mode_t mode) 
{ 
    _open = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open"); 
    if(flags & O_CREAT) 
     return _open(pathname, flags | O_NOATIME, mode); 
    else 
     return _open(pathname, flags | O_NOATIME, 0); 
} 

int open64(const char * pathname, int flags, mode_t mode) 
{ 
    _open64 = (int (*)(const char * pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64"); 
    if(flags & O_CREAT) 
     return _open64(pathname, flags | O_NOATIME, mode); 
    else 
     return _open64(pathname, flags | O_NOATIME, 0); 
} 

Por lo que entiendo ... es más o menos el truco LD_PRELOAD o un módulo del núcleo. No hay mucho terreno intermedio a menos que desee ejecutarlo en un emulador que pueda atrapar su función o reescribir el código en el binario real para atrapar su función.

Suponiendo que no puede modificar el programa y no puede (o no quiere) modificar el kernel, el enfoque LD_PRELOAD es el mejor, suponiendo que su aplicación es bastante estándar y no es realmente maliciosamente tratando de pasar su intercepción. (En cuyo caso se necesita una de las otras técnicas.)

+5

Es completamente opcional que un programa reconozca LD_PRELOAD. No todos los programas enlazan con libc. – vipw

+0

@vipw ¿puedes dar más detalles? ¿Cómo es que un programa puede eludir LD_PRELOAD? Cada programa que no enlaza con libc no tiene nada que ver con el hecho de que el enlazador cargará una biblioteca dada antes que las otras al cargar un ejecutable, si se especifica con LD_PRELOAD. Si esa biblioteca tiene una función llamada por el ejecutable, el programa mira primero a la biblioteca cargada LD_PRELOAD. No importa que las bibliotecas posteriores también hayan implementado la función. – acib708

+2

@ acib708 Lo que quiero decir es que un programa puede hacer llamadas al sistema sin usar libc. Entonces, la biblioteca que se está cargando en realidad no importa ya que no se llaman símbolos desde ella. En cambio, una pequeña pieza de ensamblaje para configurar los registros y crear una interrupción puede hacer la llamada. – vipw

2

I no tiene la sintaxis para hacer esto correctamente con un LKM, pero este artículo proporciona una buena visión general de lo que necesitaría hacer: http://www.linuxjournal.com/article/4378

También podría parchar la función sys_open. Comienza en la línea 1084 de file/open.c a partir de linux-2.6.26.

También puede ver si no puede usar inotify, systemtap o SELinux para hacer todo este registro sin tener que construir un nuevo sistema.

+0

Este enlace es antiguo ahora y no funciona en 2.6.X – zengr

7

Valgrind se puede utilizar para interceptar cualquier llamada de función. Si necesita interceptar una llamada al sistema en su producto terminado, entonces esto no servirá. Sin embargo, si intentas interceptar durante el desarrollo, puede ser muy útil. Frecuentemente he usado esta técnica para interceptar las funciones de hash para poder controlar el hash devuelto con fines de prueba.

En caso de que no lo sepa, Valgrind se usa principalmente para encontrar fugas de memoria y otros errores relacionados con la memoria. Pero la tecnología subyacente es básicamente un emulador x86. Emula tu programa e intercepta llamadas a malloc/free etc. Lo bueno es que no necesitas volver a compilar para usarlo.

Valgrind tiene una función que denominan Ajuste de funciones, que se utiliza para controlar la interceptación de funciones. Vea la sección 3.2 del Valgrind manual para más detalles. Puede configurar el ajuste de funciones para cualquier función que desee. Una vez que se intercepta la llamada, se invoca la función alternativa que usted proporciona.

3

Si solo quieres mira lo que está abierto, quieres ver la función ptrace(), o el código fuente de la herramienta de línea de comando. Si realmente desea interceptar la llamada, para hacer que haga otra cosa, creo que las opciones que enumeró - LD_PRELOAD o un módulo kernel - son sus únicas opciones.

2

Si solo desea hacerlo para fines de depuración, mire en strace, que está integrado en la parte superior de la llamada al sistema ptrace (2) que le permite conectar el código cuando se realiza una llamada al sistema.Consulte la parte PTRACE_SYSCALL de la página man.

4

Algunas aplicaciones pueden engañar strace/ptrace no correr, por lo que la única opción real que he tenido es el uso de systemtap

Systemtap puede interceptar un montón de llamadas al sistema si es necesario debido a su juego de comodín. Systemtap no es C, sino un lenguaje separado. En modo básico, el systemtap debería evitar que hagas cosas estúpidas, pero también se puede ejecutar en el "modo experto" que permite que un desarrollador use C si es necesario.

No es necesario que parchee el kernel (o al menos no debería), y una vez que se ha compilado un módulo, puede copiarlo de un cuadro de prueba/desarrollo e insertarlo (a través de insmod) en una producción sistema.

Todavía tengo que encontrar una aplicación de Linux que haya encontrado una forma de evitar el problema/evitar ser atrapado por systemtap.

1

Parece que necesita auditd.

Auditd permite el seguimiento global de todas las llamadas de syscalls o accesos a archivos, con el registro. Puede establecer claves para eventos específicos que le interesen.

Cuestiones relacionadas