Interceptación de llamadas del sistema en el módulo del kernel de Linux

El módulo fue creado como parte de mi tesis de maestría en el año 2010. El tema de la tesis maestra es Keylogging en el kernel de Linux . La idea principal era encontrar una manera de interceptar las llamadas del sistema para x64 arch Linux kernel, especialmente para kernel 2.6.34.7-61.fc13.x86_64.


Introduccion


Hubo muchos artículos diferentes sobre la intercepción de llamadas del sistema para x32 arch. Como parte de una investigación, enfrenté el problema de cómo interceptar las llamadas del sistema para x86_64 arch a través del módulo Linux-kernel.


¿Cómo podemos interceptar una llamada al sistema?


  1. Descubra la dirección de la tabla syscall.
  2. Reemplace la llamada original del sistema por la nueva.

Dirección de la tabla de llamadas al sistema


IDT ( I ntrupt D escription Table) limita el controlador de interrupción y el código de interrupción . En modo protegido, IDT es una matriz de descriptores almacenados en la memoria. Cada procesador tiene un registro IDTR especial. El registro consta de dirección física IDT y longitud IDT. La primera suposición fue obtener la dirección IDT del registro IDTR y luego calcular la dirección de las tablas de syscall. Sin embargo, la suposición era incorrecta, porque, en ese caso, obtuvimos la dirección del controlador x32.


La segunda suposición fue más interesante. Antes de continuar, me gustaría describir MSR (Macodell Specific R egister). Un MSR es cualquiera de varios registros de control en el conjunto de instrucciones x86 utilizado para depurar, rastrear la ejecución del programa, monitorear el rendimiento de la computadora y alternar ciertas funciones de la CPU. Hablemos de MSR_LSTAR - 0xc0000082 (objetivo SYSCALL en modo largo). Puede obtener la lista completa en /usr/include/asm/msr-index.h .


El MSR_LSTAR almacena la entrada de llamadas del sistema para la arquitectura x86-64. Puedes obtener la dirección:


 int i, lo, hi; asm volatile("rdmsr" : "=a" (lo), "=d" (hi) : "c" (MSR_LSTAR)); system_call = (void*)(((long)hi<<32) | lo); 

Vamos más allá. Tenía la dirección y estaba buscando \xff\x14\xc5 . \xff\x14\xc5 es un número mágico. Si observa el código del núcleo 2.6.34.7-61.fc13.x86_64, especialmente la función system_call , descubrirá que los siguientes 4 bytes son la dirección syscall_table.


Conocíamos la dirección de la tabla syscall, significaba que podíamos obtener una dirección del manejador syscall y reemplazarla / interceptarla.


El código fuente:


 unsigned char *ptr; for (ptr=system_call, i=0; i<500; i++) { if (ptr[0] == 0xff && ptr[1] == 0x14 && ptr[2] == 0xc5) return (void*)(0xffffffff00000000 | *((unsigned int*)(ptr+3))); ptr++; } 

Sistema de intercepción de llamadas


Me enfrenté a un problema. Hubo un error en caso de cambiar una dirección en la tabla de llamadas del sistema. Afortunadamente, fue fácil como el pastel:


  • Deshabilitar la protección de memoria.
  • Reescriba una dirección de controlador syscall.
  • Habilitar la protección de la memoria.

Si desea deshabilitar la protección de memoria, debe saber: el registro CR0 consta de banderas. Las banderas gestionan el comportamiento del procesador. El indicador WP es Write Protect , es el 48 ° bit en CR0 .


Deshabilitar la protección de memoria:


 asm("pushq %rax"); asm("movq %cr0, %rax"); asm("andq $0xfffffffffffeffff, %rax"); asm("movq %rax, %cr0"); asm("popq %rax"); 

Activar protección de memoria:


 asm("pushq %rax"); asm("movq %cr0, %rax"); asm("xorq $0x0000000000001000, %rax"); asm("movq %rax, %cr0"); asm("popq %rax"); 

Conclusión



Por un lado, debería ser suficiente para lidiar con la intercepción de llamadas del sistema, pero por otro lado, no estoy seguro de que nada haya cambiado desde 2010. Así que úselo como está. El código fuente se encuentra en github.com/ultral/linux-keylogger .


PS


Source: https://habr.com/ru/post/437182/


All Articles