Interceptação de chamada do sistema no módulo Linux-kernel

O módulo foi criado como parte da minha tese de mestrado no ano de 2010. O tema da tese de mestrado é Keylogging no kernel do Linux . A idéia principal era descobrir uma maneira de interceptar chamadas do sistema para o kernel Linux x64 arch, especialmente para o kernel 2.6.34.7-61.fc13.x86_64.


1. Introdução


Havia muitos artigos diferentes sobre interceptação de chamadas do sistema para x32 arch. Como parte de uma pesquisa, enfrentei a questão de como interceptar chamadas do sistema para o arco x86_64 via módulo Linux-kernel.


Como podemos interceptar uma chamada do sistema?


  1. Descubra o endereço da tabela syscall.
  2. Substitua a chamada original do sistema pela nova.

Endereço da tabela Syscall


O IDT (Interromper a descrição) limita o manipulador de interrupções e o código de interrupção . No modo protegido, o IDT é uma matriz de descritores armazenados na memória. Cada processador possui um registro IDTR especial. O registro consiste no endereço físico e no tamanho do IDT. A primeira suposição foi obter o endereço IDT do registro IDTR e depois calcular o endereço das tabelas syscall. No entanto, a suposição estava errada, porque, nesse caso, obtivemos o endereço do manipulador x32.


A segunda suposição foi mais interessante. Antes de continuar, gostaria de descrever o MSR (Macodell Specific R egister). Um MSR é um dos vários registros de controle no conjunto de instruções x86 usado para depuração, rastreamento de execução de programa, monitoramento de desempenho do computador e alternância de certos recursos da CPU. Vamos falar sobre MSR_LSTAR - 0xc0000082 (destino SYSCALL no modo longo). Você pode obter a lista completa em /usr/include/asm/msr-index.h .


O MSR_LSTAR armazena a entrada de chamada do sistema para a arquitetura x86-64. Você pode obter o endereço:


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

Vamos mais longe. Eu tinha o endereço e estava pesquisando \xff\x14\xc5 . \xff\x14\xc5 é um número mágico. Se você examinar o código 2.6.34.7-61.fc13.x86_64 do kernel, especialmente a função system_call , descobrirá que os próximos 4 bytes são o endereço syscall_table.


Sabíamos o endereço da tabela syscall, isso significava que poderíamos obter um endereço de manipulador syscall e substituí-lo / interceptá-lo.


O código fonte:


 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++; } 

Interceptação de chamada do sistema


Eu enfrentei um problema. Ocorreu um erro no caso de alterar um endereço na tabela de chamadas do sistema. Felizmente, foi fácil como torta:


  • Desative a proteção de memória.
  • Reescreva um endereço de manipulador de syscall.
  • Ativar proteção de memória.

Se você deseja desativar a proteção de memória, você deve saber: o registro CR0 consiste em sinalizadores. Os sinalizadores gerenciam o comportamento do processador. O sinalizador WP é Write Protect , é o 48º bit em CR0 .


Desativar proteção de memória:


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

Ative a proteção de memória:


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

Conclusão



Por um lado, deve ser suficiente lidar com a interceptação de chamadas do sistema, mas, por outro lado, não tenho certeza de que nada tenha sido alterado desde 2010. Portanto, use-o como está. O código fonte localiza-se em github.com/ultral/linux-keylogger .


PS


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


All Articles