b. Prototype et numéro des appels systèmes utiles
Numéro de l’appel système execve :
flo@kali:~$ cat /usr/include/i386-linux-gnu/asm/unistd_32.h | grep execve
#define __NR_execve 11
Prototype de l’appel système execve :
flo@kali:~$ strace ./shell | grep execve
execve("./shell", ["./shell"], [/* 29 vars */]) = 0 // Exécution du binaire ./shell
…
execve("/bin/sh", ["/bin/sh"], [/* 0 vars */]) = 0 // Exécution du script « /bin/sh »
…
Extrait de son man :
NAME
execve - execute program
SYNOPSIS
#include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
(En français : http://manpagesfr.free.fr/man/man2/execve.2.html )
L’appel système execve exécute le programme pointé par filename, qui est soit un binaire
exécutable, soit un script.
Il utilise 3 arguments :
Le 1er argument « char *filename », est l’adresse du programme à exécuter.
Le 2ème argument « char *argv[] » est un array d’arguments de type strings, passé au
nouveau programme. Par convention, le premier argument doit être le filename associé au
file exécuté.
Le 3ème argument « char *envp[] » ne nous sera pas utile ici. C’est un array de strings
passé au nouveau programme comme environnement (variable d’environnement PATH, etc.).
argv ainsi que envp doivent se terminer par un pointeur NULL.
Les arguments et l'environnement sont accessibles par le nouveau programme dans sa fonction
principale, lorsqu'elle est définie comme : int main(int argc, char *argv[], char *envp[]).
En cas de réussite, execve() ne revient pas à l'appelant, et les segments de texte, de données
(« data » et « bss »), ainsi que la pile du processus appelant sont remplacés par ceux du
programme chargé.
En cas d'échec il renvoie -1 et errno contient le code d'erreur.
Voyons tout cela avec gdb :
ATTENTION : Ce qui nous intéresse est le code assembleur de l’appel système execve, et non celui de la fonction
wrapper execve ! Nous exécuterons donc le programme jusqu’à l’interruption « int $0x80 » de execve, et non
jusqu’à « call 0x804f770 <execve> » du main.
[-------------------------------------code-------------------------------------]
=> 0x804f782 <execve+18>: int $0x80
[----------------------------------registers-----------------------------------]
EAX: 0xb ('\x0b')
EBX: 0x80aafe8 ("/bin/sh")
ECX: 0xbffff4f8 --> 0x80aafe8 ("/bin/sh")
EDX: 0x0
EAX contient le numéro de l’appel système « 0xb » i.e. « 11 »
EBX contient le premier argument de execve, soit « addr /bin/sh »
ECX contient l’adresse vers l’array des arguments { addr /bin/sh , NULL},
EDX contient NULL.