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?
- Descubra o endereço da tabela syscall.
- 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