1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    février 2013
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : février 2013
    Messages : 17
    Points : 14
    Points
    14

    Par défaut [C, asm]executer de binaire en memoire executable

    Bonjour,

    je viens vers vous car je suis dans l'impasse sur un projet pédagogique.
    Je cherche à exécuter du binaire à la volée a l'aide d'une mémoire exécutable mmap en C et d'un code Assembleur.
    Le problème est que... je n'ai qu'une boucle infinie O.o... pas même un signal du type SIGSEGV ou une exception...
    J'ai beau lire toutes les docs trouvables du web, je reste bloqué... quelque chose semble m'échapper...

    Le main.c
    Code C : 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
     
    #include <sys/mman.h>
    #include <string.h>
     
    char shellcode[] =
      "\x31\xc0"
      "\x31\xdb"
      "\x31\xc9"
      "\x31\xd2"
      "\xeb\x0f"
      "\xb0\x04"
      "\xb3\x01"
      "\x59"
      "\xb2\x0d"
      "\xcd\x80"
      "\xb0\x01"
      "\x31\xdb"
      "\xcd\x80"
      "\xe8\xec\xff\xff\xff"
      "\x48\x65\x6c\x6c\x6f"
      "\x20\x77\x6f\x72\x6c"
      "\x64\x21\x0a";
     
    char *exec;
     
    int main()
    {
      exec = (char *)mmap(NULL, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
     
      memcpy(exec, shellcode, strlen(shellcode));
      (*(void(*)())exec)();
     
      return (0);
    }

    Le hello.asm
    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
     
    bits 32
            section .text
    	global _start
    _start:
                xor eax, eax
                xor ebx, ebx
                xor ecx, ecx
                xor edx, edx
     
                jmp helloworld_string
     
    helloworld_shellcode_next:
                mov al, 4
                mov bl, 1
                pop ecx
                mov dl, 13
                int 0x80
     
                mov al, 1
                xor ebx, ebx
                int 0x80
     
    helloworld_string:
                call helloworld_shellcode_next
                db `Hello world!\n`
    La compilation :
    gcc -o main main.c
    nasm -f elf64 hello.asm
    ld -s hello.o -o hello
    Le objdump -d hello :
    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
     
    hello2:     file format elf64-x86-64
     
     
    Disassembly of section .text:
     
    0000000000400080 <.text>:
      400080:	31 c0                	xor    %eax,%eax
      400082:	31 db                	xor    %ebx,%ebx
      400084:	31 c9                	xor    %ecx,%ecx
      400086:	31 d2                	xor    %edx,%edx
      400088:	eb 0f                	jmp    0x400099
      40008a:	b0 04                	mov    $0x4,%al
      40008c:	b3 01                	mov    $0x1,%bl
      40008e:	59                   	pop    %rcx
      40008f:	b2 0d                	mov    $0xd,%dl
      400091:	cd 80                	int    $0x80
      400093:	b0 01                	mov    $0x1,%al
      400095:	31 db                	xor    %ebx,%ebx
      400097:	cd 80                	int    $0x80
      400099:	e8 ec ff ff ff       	callq  0x40008a
      40009e:	48                   	rex.W
      40009f:	65                   	gs
      4000a0:	6c                   	insb   (%dx),%es:(%rdi)
      4000a1:	6c                   	insb   (%dx),%es:(%rdi)
      4000a2:	6f                   	outsl  %ds:(%rsi),(%dx)
      4000a3:	20 77 6f             	and    %dh,0x6f(%rdi)
      4000a6:	72 6c                	jb     0x400114
      4000a8:	64 21 0a             	and    %ecx,%fs:(%rdx)
    Le strace ./main :
    brk(0) = 0x123e000
    access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc7b49dc000
    access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=137143, ...}) = 0
    mmap(NULL, 137143, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fc7b49ba000
    close(3) = 0
    access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
    open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0
    mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc7b43f7000
    mprotect(0x7fc7b45b2000, 2093056, PROT_NONE) = 0
    mmap(0x7fc7b47b1000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7fc7b47b1000
    mmap(0x7fc7b47b7000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc7b47b7000
    close(3) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc7b49b9000
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc7b49b7000
    arch_prctl(ARCH_SET_FS, 0x7fc7b49b7740) = 0
    mprotect(0x7fc7b47b1000, 16384, PROT_READ) = 0
    mprotect(0x600000, 4096, PROT_READ) = 0
    mprotect(0x7fc7b49de000, 4096, PROT_READ) = 0
    munmap(0x7fc7b49ba000, 137143) = 0
    mmap(NULL, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc7b49db000
    stat("1\3001\3331\3111\322\353\17\260\4\263\1Y\262\r\315\200\260\0011\333\315\200\350\354\377\377\377Hello world!\n", 0x601060) = -1 EFAULT (Bad address)
    syscall_3221225217(0x7fc7b49db000, 0x601060, 0xd, 0, 0, 0) = -1 (errno 38)
    syscall_3221225220(0x7fc7b49db000, 0x601060, 0xd, 0, 0, 0) = -1 (errno 38)
    syscall_3221225217(0x7fc7b49db000, 0x601060, 0xd, 0, 0, 0) = -1 (errno 38)
    syscall_3221225220(0x7fc7b49db000, 0x601060, 0xd, 0, 0, 0) = -1 (errno 38)
    (boucle a l'infini)

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2011
    Messages
    8 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : août 2011
    Messages : 8 925
    Points : 19 792
    Points
    19 792

    Par défaut

    Tu compiles pour du 64 bits alors que ton code asm est adapté au 32 bits, en 64 bits en utilise par int 0x80 pour les appels systèmes mais sysenter et les registres à utiliser sont pas les mêmes.
    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/tutoriels/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Membre à l'essai
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    février 2013
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : février 2013
    Messages : 17
    Points : 14
    Points
    14

    Par défaut

    oui c'est vrai mais la retrocompatibillité ne le permet elle pas ?
    rax n'est en soi qu'une extension de eax et syscall une sorte de define de int 0x80
    cependant il est vrai que ld ne fonctionnais pas sans elf64...

    le code asm s'execute parfaitement en lancant le ./hello
    c'est vraiment au moment de l'executer via le code C que cela ne donne aucun resultat autre que la boucle infini avec strace ./main

    cependant j'ai tester plusieurs code asm sans plus de resultat je me dit donc qu'il doit y avoir quelque chose de plus profond qui m'aurais échapper.
    je vais tenter avec une ecriture pour x86-64 et je donnerais des nouvelles.

  4. #4
    Responsable Systèmes


    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2011
    Messages
    8 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : août 2011
    Messages : 8 925
    Points : 19 792
    Points
    19 792

    Par défaut

    Pour la rétro-compatibilité, je pense que ton OS 64 bits peut charger un ELF32 qui va utiliser int 0x80 pour les appels systèmes, tandis qu'un ELF64 utiise ra SYSCALL

    rax n'est en soi qu'une extension de eax et syscall une sorte de define de int 0x80
    Non, SYSCALL et int 0x80, c'est pas la même chose, même si le résultat vu de l’extérieur semble similaire.

    Et on utilise pas les mêmes registres
    en x86, les paramètres sont passés dans cet ordre :
    ebx,ecx, edx,esi, edi, ebp - eax contenant le numéro d'appel.
    en x86_64, c'est :
    rdi, rsi, rdx,r10,r8,r9 - rax contenant le numéro d'appel.
    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/tutoriels/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  5. #5
    Membre à l'essai
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    février 2013
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : février 2013
    Messages : 17
    Points : 14
    Points
    14

    Par défaut autre version asm

    voici une autre version de code asm pour 64 bit que j'ai aussi test et qui ne fonctionne pas plus.

    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
     
    global _start
        _start:
        jmp short string
     
        code:
        pop rsi
        xor rax, rax
        mov al, 1
        mov rdi, rax
        mov rdx, rdi
        add rdx, 14
        syscall
     
        xor rax, rax
        add rax, 60
        xor rdi, rdi
        syscall
     
        string:
        call code
        db  'Hello, world!',0x0A
    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
     
    (->)objdump -d hello3
     
    hello3:     file format elf64-x86-64
     
     
    Disassembly of section .text:
     
    0000000000400080 <.text>:
      400080:	eb 1e                	jmp    0x4000a0
      400082:	5e                   	pop    %rsi
      400083:	48 31 c0             	xor    %rax,%rax
      400086:	b0 01                	mov    $0x1,%al
      400088:	48 89 c7             	mov    %rax,%rdi
      40008b:	48 89 fa             	mov    %rdi,%rdx
      40008e:	48 83 c2 0e          	add    $0xe,%rdx
      400092:	0f 05                	syscall 
      400094:	48 31 c0             	xor    %rax,%rax
      400097:	48 83 c0 3c          	add    $0x3c,%rax
      40009b:	48 31 ff             	xor    %rdi,%rdi
      40009e:	0f 05                	syscall 
      4000a0:	e8 dd ff ff ff       	callq  0x400082
      4000a5:	48                   	rex.W
      4000a6:	65                   	gs
      4000a7:	6c                   	insb   (%dx),%es:(%rdi)
      4000a8:	6c                   	insb   (%dx),%es:(%rdi)
      4000a9:	6f                   	outsl  %ds:(%rsi),(%dx)
      4000aa:	2c 20                	sub    $0x20,%al
      4000ac:	77 6f                	ja     0x40011d
      4000ae:	72 6c                	jb     0x40011c
      4000b0:	64 21 0a             	and    %ecx,%fs:(%rdx)
    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
     
    #include <sys/mman.h>
    #include <string.h>
     
    char shellcode[] =
      "\xeb\x1e"
      "\x5e"
      "\x48\x89\xc7"
      "\x48\x89\xfa"
      "\x48\x83\xc2\x0e"
      "\x0f\x05"
      "\x48\x31\xc0"
      "\x48\x83\xc0\x3c"
      "\x48\x31\xff"
      "\x0f\x05"
      "\xe8\xdd\xff\xff\xff"
      "\x48"
      "\x65"
      "\x6c"
      "\x6c"
      "\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0a";
     
    char *exec;
     
    int main()
    {
      exec = (char *)mmap(NULL, 1024, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0);
     
      memcpy(exec, shellcode, strlen(shellcode));
      (*(void(*)())exec)();
     
      return (0);
    }

  6. #6
    Responsable Systèmes


    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2011
    Messages
    8 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : août 2011
    Messages : 8 925
    Points : 19 792
    Points
    19 792

    Par défaut

    Ton tableau de char shellcode est considéré comme des données, donc dans le segment de données normalement non exécutable.

    Ce que l'on appelle un shellcode est en général exécutable grâce à une faille système mais ne l'est pas normalement.

    Quel est le but final ? Qu'appeles tu exécution de binaire à la volée ?
    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/tutoriels/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  7. #7
    Membre à l'essai
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    février 2013
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : février 2013
    Messages : 17
    Points : 14
    Points
    14

    Par défaut

    merci pour ta reponse et dsl que la mienne soi si tardive,

    la memoire allouer par mmap est sencer etre executable avec le flag PROT_EXEC.
    il est vrai que je ne trouve rien disant explicitement que mmap alloue sur le tas...
    est il possible que suivant le flag ce soi allouer sur le segment text ? (PROT_EXEC)
    si oui il le mystere reste entier, si non...
    pourquoi allouer de la memoire executable sur la heap ?
    rien ne dit explicitement que la heap n'est pas executable...
    seul la stack est explicitement dite "non executable".

    Cependant il y a du lardon dans le pater...
    J'en suis donc venu a la meme conclusion sur le fait que la heap ne soi pas executable, (le man 2 mmap serais donc depleted dans ce cas).
    et que donc le seul moyen d'executer du binaire a la voler serais de l'ecrire directement dans le segment text...
    Je ne connais aucun moyen d'ecrire dans le segment text,
    mais je suspecte fortement cependant de pouvoir le faire grace au kernel space ou au registre CS.

    ce que j'entend par executer du binaire a la voler ?
    d'abord je me base en partie sur ce lien (asm->opcode) : https://gladir.com/CODER/ASM8086/referenceeopcode.htm

    donc ecrire (manuellement pour rigoler) ou recevoir du binaire (fichier, reseau, etc...) l'ecrire en memoire et pouvoir l'executer avec un pointeur de fonction.

  8. #8
    Responsable Systèmes


    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2011
    Messages
    8 925
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : août 2011
    Messages : 8 925
    Points : 19 792
    Points
    19 792
    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/tutoriels/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  9. #9
    Membre à l'essai
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    février 2013
    Messages
    17
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : février 2013
    Messages : 17
    Points : 14
    Points
    14

    Par défaut

    passionnant !
    merci beaucoup pour cette info.

    cependant je viens de comprendre quelque chose d'extremement important.
    mmap n'alloue pas sur un segment, il demande au noyau de mapper un fichier en dehors de la segmentation.
    le tas n'est donc pas concerner par plus que le segment text.
    cette memoire est donc normalement initialiser avec un NX BIT actif.
    car ce qui a ete allouer c'est quand meme une memoire executable au final...

Discussions similaires

  1. Réponses: 3
    Dernier message: 15/02/2010, 17h54
  2. execution de binaire et recuperation stderr
    Par oniric dans le forum Langage
    Réponses: 4
    Dernier message: 05/12/2007, 17h00
  3. executer un binaire dans un .jar
    Par yli_ren dans le forum Général Java
    Réponses: 5
    Dernier message: 25/06/2007, 16h20
  4. Cryptor , executer un exe en memoire
    Par Hitchigo dans le forum Delphi
    Réponses: 10
    Dernier message: 02/08/2006, 21h08
  5. [Exécutable]puis je creer un executable a partir de mon code ?
    Par youpileouf dans le forum Général Java
    Réponses: 3
    Dernier message: 17/06/2005, 09h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo