Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

Besoin d'aide pour l'implémentation de execve()


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre à l'essai
    Besoin d'aide pour l'implémentation de execve()
    Salut,

    Je viens vers vous car je bloque depuis des heures sur l'implémentation de execve("/bin/bash", ["/bin/bash", "-p", NULL],NULL) en assembleur. Je précise que je ne cherche pas à faire un shellcode Voici mon code :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    ;a-s.asm
     
    ;nasm a-s.asm -o a-s.o -f elf && ld -s a-s.o -o a-s -melf_i386
     
    segment .data
     
     shell_path db "/bin/bash"
     keep_uid db "/bin/bash0-p"
     
    segment .text
     
     global _start
     
      _start:
     
      mov eax,0
      mov ebx,0
      mov ecx,0
      mov edx,0
      mov ebx,shell_path
      mov [ebx+9],al
      mov ecx,keep_uid
      mov [ecx+9],al
      push ecx
      mov edx,esp
     
      ;push edx
      ;mov ecx,esp
     
      push 0
      push edx    ;ou ecx
      push ebx
      mov eax,11
      int 0x80


    Là, vous voyez une possibilité parmi les multiples que j'ai testées. En fait, je ne parviens pas à passer correctement les paramètres à execve(). J'ai essayé d'initialiser un tableau, mais je n'ai pas réussi. Avant qu'on me suggère telle ou telle piste à suivre, je précise que j'ai déjà codé la fonction en C pour regarder le résultat en assembleur. Je l'ai compris, cependant je n'arrive pas à le reproduire (notamment au niveau des déclarations des chaines qui, lorsque je les vois ne mémoire, ne me parlent pas trop).

    Merci par avance pour vos réponses'

  2. #2
    Responsable Systèmes

    ajoutes un 0 à la fin de shell_path directement, ce sera plus simple :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    shell_path db "/bin/bash",0

    ensuite test avec 0 dans ecx et edx (pas d'arguments, pas de variables d'environnement)
    pourquoi tu empiles des valeurs ?
    les appels systèmes attendent des valeurs dans les registres, pas sur la pile.

    D'autre part, tu es bien sur un OS 32 bits ? car en 64 bits on utilise pas int 0x80 mais l'opcode syscall
    et les dans ce cas les numéros d'appels système ne sont pas les mêmes et ne met pas les arguments dans ebx,ecx,edx etc
    mais dans rdi,rsi, rdx,rcx, r8,r9 (info à vérifier)
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur la création d'un système : http://chrtophe.developpez.com/tutor...s/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Membre à l'essai
    Salut, merci pour ta réponse.

    Bon, j'avais commencé à te répondre que si, que ça, mais en fait...

    "les appels systèmes attendent des valeurs dans les registres, pas sur la pile."

    Tu as tout à fait raison !! J'étais complètement à côté de la plaque, je pensais à des fonctions standards xD Du coup voici un programme simple qui fonctionne - volontairement non optimisé - :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    ;a-s.asm
     
    ;nasm a-s.asm -o a-s.o -f elf && ld -s a-s.o -o a-s -melf_i386
     
    segment .data
     
     shell_path db "/bin/bash",0
     keep_uid db "-p"
     
    segment .text
     
     global _start
     
      _start:
     
      mov eax,0
      mov eax,11
      mov ebx,0
      mov ecx,0
      mov edx,0
      mov ebx,shell_path
     
      mov ecx,keep_uid
      push 0
      push ecx
      push ebx
      mov ecx,esp
      int 0x80


    Sinon je suis sur un OS 64 bits mais - je ne sais pas pourquoi - j'ai commencé mon affaire sur des binaires compilés en 32 bits.

    En tout cas merci à toi, ta remarque était tout à fait logique mais je ne sais pas pourquoi, je n'y pensais vraiment plus !!

    Merci beaucoup'

  4. #4
    Responsable Systèmes

    Sur un système 64 bits, tu peux exécuter des applis 32 bits. Les appels systèmes ne se feront pas de la même façon. Le jour ou le support 32 bits sera retiré, les applis 32 bits ne pourront plus fonctionner.

    Tu empiles toujours des trucs inutilement juste avant l'appel à int 0x80, et surtout tu ne dépiles pas. Tu passes dans ecx l'adresse de la pile. Ca n'a pas de sens. Tu passes à execve l'adresse de la pile comme arguments. Tu n'as pas de dysfontionnement apparent car tu as empilé plusieurs 0 et que la liste des arguments de ton programme doit se terminer par 0, tu écrase le passage de keep_uid.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur la création d'un système : http://chrtophe.developpez.com/tutor...s/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  5. #5
    Membre à l'essai
    Hello,

    Ouaip je sais, mais sans trop réfléchir je suis parti sur du 32 bits, du coup je continue sur du 32 bits, mais dans l'absolu pour ce que je veux faire ça n'a pas grande importance, même si un jour on ne peut plus exécuter de programme 32 bits.

    Mmh...je ne comprends pas trop ce que tu veux me dire : moi je me base sur le fait que execve() attende en premier un pointeur sur le nom du programme à lancer, puis en deuxième un pointeur sur un tableau qui compote le nom du programme et le paramètre à passer au programme.

    Qu'entends-tu par dépiler ? Je veux dire, pourquoi dépiler ?

    Accessoirement je veux bien que tu me montres ce que toi tu aurais écrit

  6. #6
    Responsable Systèmes

    Code asm :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    ;a-s.asm
     
    ;nasm a-s.asm -o a-s.o -f elf && ld -s a-s.o -o a-s -melf_i386
     
    segment .data
     
     shell_path db "/bin/bash",0
     keep_uid db "-p",0
    
    tableau_arguments:
    dd keep_uid
    dd 0
     
    segment .text
     
     global _start
     
      _start:
     
      mov eax,0
      mov eax,11
      mov ebx,shell_path
      mov ecx,tableau_arguments
      xor edx,edx
      int 0x80


    attention, code non testé, fait de mémoire.

    la fonction execve attend en ecx une liste de pointeurs devant être terminé par 0 (null terminated), j'ai donc crée cette liste et passé en premier paramètre de celle-ci l’adresse de ton argument contenu dans keep_uuid
    c'est le même principe pour les chaines d'environnement en edx. Optionnel donc mis à 0 avec xor edx,edx équivalent à mov edx,0 mais plus rapide.
    j'ai enlevé les push qui servaient à empiler des valeurs pour rien. (empiler=placer des valeurs sur la pile, dépiler=l'inverse). Tout ce qui est empilé doit être dépilé car si ton code était dans une fonction appelée avec callet dont tu sors avec ret, tu aurais un crash par corruption de pile, ton ret sauterais à une adresse ne correspondant pas à celle attendue plus haut dans la pile car ce que tu y a ajouté n'a pas été dépilé.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur la création d'un système : http://chrtophe.developpez.com/tutor...s/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  7. #7
    Membre à l'essai
    Eh bien tu as bonne mémoire Le prompt de la nouvelle console a un tronche très étrange :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    dodo@dodosystem:~$ ./a-s
    -p-4.4$ whoami
    dodo
    -p-4.4$

    Mais comme tu peux le voir, les droits sont droppés (normalement je devrais passer root).

    Le dd c'est quoi ? J'avais essayé de créer un tableau, j'ai jamais réussi (avec dw, dq...j'ai eu des erreurs de tailles).

    D'ailleurs elles pourraient servir à quoi les chaînes d'environnement ? J'ai pas bien compris le but éventuel.

    C'est bizarre, quand je débuggue un programme je ne vois jamais de dépilement (pop ?). Sinon le ret, pourquoi sauterait-il n'importe où ? L'adresse de pile à laquelle serait inscrite l'adresse de retour ne devrait pas changer même en empilant un paquet de données...?

    PS : il à l'air intéressant ton article sur la création d'une mini-OS.

  8. #8
    Responsable Systèmes

    db, tu déclares des octets, dw des mots (16 bits), dd des doubles mots (32 bits)

    ecx attend une table devant contenir les adresses des arguments, je passe l'adresse de ton argument "-p" qui me semble non valable pour bash
    les variables d'environnements sont utiles, tu vas y trouver par exemple PS, qui va contenir la chaine de prompt (exemple ~/, ou #), SHELL pour le chemin du shell, PATH (une des variables les plus importantes), HOME pour le chemin du /home de l'utilisateur courant, etc.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur la création d'un système : http://chrtophe.developpez.com/tutor...s/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  9. #9
    Membre à l'essai
    Hello

    Je comprends pas trop ce que tu m'as dit concernant -p, car c'est un classique =/ Il fonctionne chez moi, j'ai toujours utilisé -p pour conserver les droits lors de l'obtention d'un shell.

    Comme je te l'ai dit, dans le man execve(), j'ai lu qu'il fallait en deuxième argument un tableau contenant les paramètres à passer au programme ainsi que, en première position, le nom du programme, par convention.

    Sinon oui je connais bien les variables d'environnement