
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.