Le module a été créé dans le cadre de ma thèse de master en 2010. Le thème de la thèse de master est Keylogging in Linux kernel . L'idée principale était de trouver un moyen d'intercepter les appels système pour le noyau Linux arch x64, en particulier pour le noyau 2.6.34.7-61.fc13.x86_64.
Présentation
Il y avait beaucoup d'articles différents sur l'interception d'appels système pour arch x32. Dans le cadre d'une recherche, j'ai été confronté à la question de savoir comment intercepter les appels système pour l'arc x86_64 via le module du noyau Linux.
Comment intercepter un appel système?
- Découvrez l'adresse de la table syscall.
- Remplacez l'appel système d'origine par le nouveau.
Adresse de la table Syscall
Le gestionnaire d' interruption et le code d'interruption de limites IDT ( D escription T escription T able). En mode protégé, IDT est un tableau de descripteurs stockés en mémoire. Chaque processeur possède un registre IDTR spécial. Le registre se compose d'une adresse physique IDT et d'une longueur IDT. La première hypothèse était d'obtenir l'adresse IDT du registre IDTR et ensuite de calculer l'adresse des tables syscall. Cependant, l'hypothèse était fausse, car, dans ce cas, nous avons obtenu l'adresse du gestionnaire x32.
La deuxième hypothèse était plus intéressante. Avant de continuer, je voudrais décrire MSR (enregistrement spécifique à Macodell). Un MSR est l'un des divers registres de contrôle du jeu d'instructions x86 utilisé pour le débogage, le suivi de l'exécution du programme, la surveillance des performances de l'ordinateur et le basculement de certaines fonctionnalités du processeur. Parlons de MSR_LSTAR
- 0xc0000082
(cible SYSCALL en mode long). Vous pouvez obtenir la liste complète sur /usr/include/asm/msr-index.h
.
MSR_LSTAR
stocke l'entrée d'appel système pour l'architecture x86-64. Vous pouvez obtenir l'adresse:
int i, lo, hi; asm volatile("rdmsr" : "=a" (lo), "=d" (hi) : "c" (MSR_LSTAR)); system_call = (void*)(((long)hi<<32) | lo);
Allons plus loin. J'avais obtenu l'adresse et recherchais \xff\x14\xc5
. \xff\x14\xc5
est un nombre magique. Si vous consultez le code 2.6.34.7-61.fc13.x86_64 du noyau, en particulier la fonction system_call
, vous découvrirez que les 4 octets suivants sont l'adresse syscall_table.
Nous connaissions l'adresse de la table syscall, cela signifiait que nous pouvions obtenir une adresse de gestionnaire syscall et la remplacer / l'intercepter.
Le code source:
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++; }
Interception d'appels système
J'ai fait face à un problème. Une erreur s'est produite en cas de modification d'une adresse dans la table des appels système. Heureusement, c'était simple comme bonjour:
- Désactivez la protection de la mémoire.
- Réécrivez une adresse de gestionnaire syscall.
- Activez la protection de la mémoire.
Si vous souhaitez désactiver la protection de la mémoire, vous devez savoir: le registre CR0
composé de drapeaux. Les drapeaux gèrent le comportement du processeur. Le drapeau WP est Write Protect
, c'est le 48ème bit à CR0
.
Désactivez la protection de la mémoire:
asm("pushq %rax"); asm("movq %cr0, %rax"); asm("andq $0xfffffffffffeffff, %rax"); asm("movq %rax, %cr0"); asm("popq %rax");
Activez la protection de la mémoire:
asm("pushq %rax"); asm("movq %cr0, %rax"); asm("xorq $0x0000000000001000, %rax"); asm("movq %rax, %cr0"); asm("popq %rax");
Conclusion
D'une part, cela devrait suffire pour gérer l'interception d'appels système, mais d'autre part, je ne suis pas sûr que rien n'a changé depuis 2010. Alors utilisez-le tel quel. Le code source se trouve sur github.com/ultral/linux-keylogger .
PS