Cet article suppose que vous êtes familier avec Linux, android et le C. Il vous faudra un appareil android (j'utilise un Galaxy Nexus), avec une partition recovery modifiée pour pouvoir installer des fichiers zip. Pour ça, ClockWorkMod fait très bien l'affaire. Enfin, il vous faut l'utilitaire ADB installé sur votre ordinateur, pour pouvoir écrire sur la mémoire du téléphone.

Le fichier qui donne les droits : su.c

#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
 
#define PASSWD_SIZE 256
#define PASSWD "coucou"
 
int display_user_input(int show)
{
	struct termios term;
 
	if (tcgetattr(STDIN_FILENO, &term) == -1) {
		fprintf(stderr, "su: error with tcgetattr\n");
		return 1;
	}
 
	if (show)
		term.c_lflag |= (ECHO | ECHOE | ECHOK | ECHONL);
	else
		term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
 
	if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term) == -1) {
		fprintf(stderr, "su: error with tcsetattr\n");  
		return 1;
	}
 
	return 0;
} 
 
int check_passwd(const char *passwd)
{
	// Modify it yourself to make it more secure!
	if (strncmp(passwd, PASSWD, PASSWD_SIZE) == 0)
		return 0;
	return 1;
}
 
int main(int argc, char **argv)
{
	int uid = 0, gid = 0;
	char *exec_args[2] = {"sh", NULL};
	char user_passwd[PASSWD_SIZE];
	size_t len;
 
	// Read password given by the user
	printf("Password: ");
	display_user_input(0);
	if (fgets(user_passwd, PASSWD_SIZE - 1, stdin) == NULL) {
		display_user_input(1);
		printf("\n");
		fprintf(stderr, "su: error reading passwd\n");
		return 1;
	}
	display_user_input(1);
	printf("\n");
 
	// Strip the final \n
	len = strnlen(user_passwd, PASSWD_SIZE);
	if (user_passwd[len - 1] == '\n')
		user_passwd[len - 1] = '\0';
 
	// Check the password
	if (check_passwd(user_passwd) != 0) {
		fprintf(stderr, "su: wrong passwd\n");
		return 1;
	}
 
	// Run sh with root rights!
	if (setgid(gid) || setuid(uid)) {
		fprintf(stderr, "su: permission denied\n");
		return 1;
	}
	execv("/system/bin/sh", exec_args);
	fprintf(stderr, "su: error executing /system/bin/sh\n");
	return 1;
}

Il s'agit d'un fichier C assez simple, qui demande un mot de passe, désactive l'affichage sur la sortie standard (pour cacher le mot de passe que vous tapez), lit le mot de passe, réactive l'affichage sur la sortie standard. Ensuite, il compare le mot de passe avec celui écrit en dur dans le code (ligne #define PASSWD), et donne lance un shell en root si celui-ci est correct.

Vous remarquerez que la sécurité est faible puisque le mot de passe est stocké en dur dans le binaire su. Cette sécurité ne retiendra pas un pirate curieux et qui a du temps à perdre, mais bloquera à coup sûr les applications malveillantes et autres virus qui cherchent un moyen d'obtenir les droits root. Si vous voulez plus de sécurité, ce n'est pas très dur à implémenter. On peut imaginer, par exemple, remplacer le mot de passe en clair par son hachage SHA-1, et ré-appliquer cette fonction de hachage sur les mots de passe entrés par l'utilisateur. Pour ça, à vous de jouer !

La compilation pour android

Pour ça il vous faut un compilateur croisé, par exemple celui de GNU EABI. Sous Debian, j'utilise la commande arm-linux-gnueabi-gcc. Il faut lui indiquer le type de processeur sur lequel le programme va tourner (dans mon cas, pour le Galaxy Nexus : -mcpu=cortex-a9), et dire à l'éditeur de lien d'inclure la bibliothèque C standard de manière statique (-static). Ça donne :

$ arm-linux-gnueabi-gcc -Wall -mcpu=cortex-a9 -static -o su su.c

Le résultat est un beau fichier exécutable su, qu'il nous faut envoyer sur le téléphone !

L'installation sur le téléphone

Pour cela, on va créer une archive zip contenant notre nouveau binaire su, mettre cette archive dans la mémoire du téléphone (sur /sdcard) et rebooter en mode recovery pour que ClockWorkMod Recovery l'installe.

Vous pouvez télécharger mon archive qui contient déjà les fichiers nécessaires. Elle contient :

  • META-INF/com/google/android/updater-script, le script qui indiquera à ClockWorkMod Recovery comment installer notre binaire ;
  • META-INF/com/google/android/update-binary, le programme qui appellera ce script ;
  • system/xbin/su, à remplacer par votre propre su (avec votre propre mot de passe).

Si vous regardez le contenu de updater-script, vous verrez qu'il monte la partition système, copie le fichier su, et lui donne les droits nécessaires, notamment le fameux bit SetUID... C'est lui qui vous permet d'accéder aux droits root !

Lorsque votre archive est prête, copiez-la sur la mémoire du téléphone :

$ adb push update.zip /sdcard/

... puis éteignez votre appareil et redémarrez-le en mode recovery. Dans le menu de ClockWorkMod Recovery, choisissez install zip from sdcard, puis apply /sdcard/update.zip. Si vous obtenez une erreur du type "signature verification failed" dans ClockWorkMod Recovery, désactivez la vérification de la signature du zip avec l'option toggle signature verification, puis recommencez.

Redémarrez votre téléphone, prêt pour le test...

$ adb shell
/ $ su
Password: 
/ # id
uid=0 gid=0
/ #

... ça marche !