k-net Blog - Mot-clé - ARM2015-11-15T15:34:00+01:00k-neturn:md5:e5c272cf6a58da1cb2a6987fa30797a5DotclearRoot android : créez votre propre binaire su, avec mot de passeurn:md5:2105c7559d689b83f2f061adcf0810fd2013-03-12T05:32:00+01:002013-03-13T22:15:31+01:00k-netMes créationsandroidARMC<p><img src="http://www.k-netweb.net/blog/datas/2013-03-12/galaxy-nexus-root.jpg" alt="Galaxy Nexus: root" width="500" height="214" /></p>
<p><em>Rooter</em> un téléphone android donne les pleins pouvoirs sur son appareil : accès à tout le système de fichiers, possibilité de sauvegarde de ses fichiers importants (SMS, fichiers de configuration)... mais il donne aussi la possibilité à une application malveillante ou à un pirate exploitant une faille d'avoir les droits root pour faire ce qu'il veut !
Les outils de <em>rootage</em> classiques créent un binaire <code>su</code> dans <code>/system/xbin</code>, qui permet de passer root sans aucune protection.</p>
<p>Nous vous proposons ici de créer votre propre exécutable <code>su</code>, avec une protection par mot de passe.</p> <p>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 <em>recovery</em> 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.</p>
<h3>Le fichier qui donne les droits : su.c</h3>
<pre class="c" style="font-family:monospace;tab-size:4;"><span style="color: #339933;">#include <stdio.h></span>
<span style="color: #339933;">#include <string.h></span>
<span style="color: #339933;">#include <termios.h></span>
<span style="color: #339933;">#include <unistd.h></span>
<span style="color: #339933;">#define PASSWD_SIZE 256</span>
<span style="color: #339933;">#define PASSWD "coucou"</span>
<span style="color: #993333;">int</span> display_user_input<span style="color: #009900;">(</span><span style="color: #993333;">int</span> show<span style="color: #009900;">)</span>
<span style="color: #009900;">{</span>
<span style="color: #993333;">struct</span> termios term<span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>tcgetattr<span style="color: #009900;">(</span>STDIN_FILENO<span style="color: #339933;">,</span> <span style="color: #339933;">&</span>term<span style="color: #009900;">)</span> <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
fprintf<span style="color: #009900;">(</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">"su: error with tcgetattr<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>show<span style="color: #009900;">)</span>
term.<span style="color: #202020;">c_lflag</span> <span style="color: #339933;">|=</span> <span style="color: #009900;">(</span>ECHO <span style="color: #339933;">|</span> ECHOE <span style="color: #339933;">|</span> ECHOK <span style="color: #339933;">|</span> ECHONL<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">else</span>
term.<span style="color: #202020;">c_lflag</span> <span style="color: #339933;">&=</span> ~<span style="color: #009900;">(</span>ECHO <span style="color: #339933;">|</span> ECHOE <span style="color: #339933;">|</span> ECHOK <span style="color: #339933;">|</span> ECHONL<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>tcsetattr<span style="color: #009900;">(</span>STDIN_FILENO<span style="color: #339933;">,</span> TCSAFLUSH<span style="color: #339933;">,</span> <span style="color: #339933;">&</span>term<span style="color: #009900;">)</span> <span style="color: #339933;">==</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
fprintf<span style="color: #009900;">(</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">"su: error with tcsetattr<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
<span style="color: #993333;">int</span> check_passwd<span style="color: #009900;">(</span><span style="color: #993333;">const</span> <span style="color: #993333;">char</span> <span style="color: #339933;">*</span>passwd<span style="color: #009900;">)</span>
<span style="color: #009900;">{</span>
<span style="color: #666666; font-style: italic;">// Modify it yourself to make it more secure!</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>strncmp<span style="color: #009900;">(</span>passwd<span style="color: #339933;">,</span> PASSWD<span style="color: #339933;">,</span> PASSWD_SIZE<span style="color: #009900;">)</span> <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">)</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
<span style="color: #993333;">int</span> main<span style="color: #009900;">(</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">)</span>
<span style="color: #009900;">{</span>
<span style="color: #993333;">int</span> uid <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> gid <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> <span style="color: #339933;">*</span>exec_args<span style="color: #009900;">[</span><span style="color: #0000dd;">2</span><span style="color: #009900;">]</span> <span style="color: #339933;">=</span> <span style="color: #009900;">{</span><span style="color: #ff0000;">"sh"</span><span style="color: #339933;">,</span> NULL<span style="color: #009900;">}</span><span style="color: #339933;">;</span>
<span style="color: #993333;">char</span> user_passwd<span style="color: #009900;">[</span>PASSWD_SIZE<span style="color: #009900;">]</span><span style="color: #339933;">;</span>
size_t len<span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Read password given by the user</span>
<span style="color: #000066;">printf</span><span style="color: #009900;">(</span><span style="color: #ff0000;">"Password: "</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
display_user_input<span style="color: #009900;">(</span><span style="color: #0000dd;">0</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>fgets<span style="color: #009900;">(</span>user_passwd<span style="color: #339933;">,</span> PASSWD_SIZE <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> stdin<span style="color: #009900;">)</span> <span style="color: #339933;">==</span> NULL<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
display_user_input<span style="color: #009900;">(</span><span style="color: #0000dd;">1</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #000066;">printf</span><span style="color: #009900;">(</span><span style="color: #ff0000;">"<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
fprintf<span style="color: #009900;">(</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">"su: error reading passwd<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
display_user_input<span style="color: #009900;">(</span><span style="color: #0000dd;">1</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #000066;">printf</span><span style="color: #009900;">(</span><span style="color: #ff0000;">"<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Strip the final \n</span>
len <span style="color: #339933;">=</span> strnlen<span style="color: #009900;">(</span>user_passwd<span style="color: #339933;">,</span> PASSWD_SIZE<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>user_passwd<span style="color: #009900;">[</span>len <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">]</span> <span style="color: #339933;">==</span> <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: #009900;">)</span>
user_passwd<span style="color: #009900;">[</span>len <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">]</span> <span style="color: #339933;">=</span> <span style="color: #ff0000;">'<span style="color: #006699; font-weight: bold;">\0</span>'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// Check the password</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>check_passwd<span style="color: #009900;">(</span>user_passwd<span style="color: #009900;">)</span> <span style="color: #339933;">!=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
fprintf<span style="color: #009900;">(</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">"su: wrong passwd<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
<span style="color: #666666; font-style: italic;">// Run sh with root rights!</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">(</span>setgid<span style="color: #009900;">(</span>gid<span style="color: #009900;">)</span> <span style="color: #339933;">||</span> setuid<span style="color: #009900;">(</span>uid<span style="color: #009900;">)</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
fprintf<span style="color: #009900;">(</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">"su: permission denied<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>
execv<span style="color: #009900;">(</span><span style="color: #ff0000;">"/system/bin/sh"</span><span style="color: #339933;">,</span> exec_args<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
fprintf<span style="color: #009900;">(</span>stderr<span style="color: #339933;">,</span> <span style="color: #ff0000;">"su: error executing /system/bin/sh<span style="color: #000099; font-weight: bold;">\n</span>"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span></pre>
<p>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 <code>#define PASSWD</code>), et donne lance un shell en root si celui-ci est correct.</p>
<p>Vous remarquerez que la sécurité est faible puisque le mot de passe est stocké en dur dans le binaire <code>su</code>.
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 !</p>
<h3>La compilation pour android</h3>
<p>Pour ça il vous faut un compilateur croisé, par exemple celui de GNU EABI.
Sous Debian, j'utilise la commande <code>arm-linux-gnueabi-gcc</code>.
Il faut lui indiquer le type de processeur sur lequel le programme va tourner (dans mon cas, pour le Galaxy Nexus : <code>-mcpu=cortex-a9</code>), et dire à l'éditeur de lien d'inclure la bibliothèque C standard de manière statique (<code>-static</code>). Ça donne :</p>
<pre>$ arm-linux-gnueabi-gcc -Wall -mcpu=cortex-a9 -static -o su su.c</pre>
<p>Le résultat est un beau fichier exécutable <code>su</code>, qu'il nous faut envoyer sur le téléphone !</p>
<h3>L'installation sur le téléphone</h3>
<p>Pour cela, on va créer une archive zip contenant notre nouveau binaire <code>su</code>, mettre cette archive dans la mémoire du téléphone (sur <code>/sdcard</code>) et rebooter en mode <em>recovery</em> pour que ClockWorkMod Recovery l'installe.</p>
<p>Vous pouvez télécharger <a href="http://www.k-netweb.net/blog/datas/2013-03-12/update.zip">mon archive qui contient déjà les fichiers nécessaires</a>.
Elle contient :</p>
<ul>
<li><code>META-INF/com/google/android/updater-script</code>, le script qui indiquera à ClockWorkMod Recovery comment installer notre binaire ;</li>
<li><code>META-INF/com/google/android/update-binary</code>, le programme qui appellera ce script ;</li>
<li><code>system/xbin/su</code>, à remplacer par votre propre <code>su</code> (avec votre propre mot de passe).</li>
</ul>
<p>Si vous regardez le contenu de <code>updater-script</code>, vous verrez qu'il monte la partition système, copie le fichier <code>su</code>, et lui donne les droits nécessaires, notamment le fameux bit SetUID... C'est lui qui vous permet d'accéder aux droits root !</p>
<p>Lorsque votre archive est prête, copiez-la sur la mémoire du téléphone :</p>
<pre>$ adb push update.zip /sdcard/</pre>
<p>... puis éteignez votre appareil et redémarrez-le en mode <em>recovery</em>.
Dans le menu de ClockWorkMod Recovery, choisissez <em>install zip from sdcard</em>, puis <em>apply /sdcard/update.zip</em>.
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 <em>toggle signature verification</em>, puis recommencez.</p>
<p>Redémarrez votre téléphone, prêt pour le test...</p>
<pre>$ adb shell
/ $ su
Password:
/ # id
uid=0 gid=0
/ #
</pre>
<p>... ça marche !</p>