IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

 C++ Discussion :

Mettre de l'assembleur dans un code c++


Sujet :

C++

  1. #1
    Membre averti Avatar de uriotcea
    Homme Profil pro
    Ingénieur / physicien
    Inscrit en
    Septembre 2003
    Messages
    1 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur / physicien
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 301
    Points : 444
    Points
    444
    Par défaut Mettre de l'assembleur dans un code c++
    Bonjour,

    je voudrais inscérer l'instruction assembleur suivante : ".ascii \xEB\x01\xE8"
    dans mon code en C++ sous gcc et ca me génére une erreur du type: "error: junk at end of line"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #include <iostream>
     
    using namespace std;
     
    int main()
    {
      __asm volatile(".ascii \xEB\x01\xE8"	);
      cout << "Hello world!" << endl;
      return 0;
    }
    Je ne vois pas ou je fais une erreur, merci d'avance de vos lumiére

  2. #2
    Membre éprouvé

    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    533
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 533
    Points : 1 086
    Points
    1 086
    Par défaut
    Il doit manquer une paire de guillemets :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    __asm volatile( ".ascii \"\xEB\x01\xE8\"" );

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 395
    Points : 23 758
    Points
    23 758
    Par défaut
    Hello,

    Euh ! C'est très tordu ! Que cherches-tu à faire en particulier ?

    « .ascii » est une directive indiquant que ce qui suit est une chaîne de caractères qui doit être codée comme telle. Cette chaîne doit être entre guillemets. Or, comme ta directive d'assemblage est déjà elle-même entre guillemets, il faut ajouter les guillemets encadrant la chaîne proprement dite en les « échappant » avec un anti-slash « \ ».

    À part ça, les octets qui composent ta chaîne vont être insérés au milieu du code, à l'endroit exact où tu l'as déclarée, et être pris pour des codes opérations. C'est peut-être voulu puisque les codes en hexadécimal y ressemblent. Cela dit, ils semblent ne correspondre à rien. Où plutôt si : un JMP qui saute le dernier opcode. Ça a l'air d'être cohérent puisque le programme s'exécute chez moi sans planter.

    Enfin, n'oublie pas de compiler avec « g++ » et pas « gcc ».

  4. #4
    Membre averti Avatar de uriotcea
    Homme Profil pro
    Ingénieur / physicien
    Inscrit en
    Septembre 2003
    Messages
    1 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur / physicien
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 301
    Points : 444
    Points
    444
    Par défaut
    Merci, ca fonctionne maintenant, du moins ca compile.
    Pour la petite histoire ce bout de code assembleur est censé empécher le désassemblage du code en faisant perdre le fil au désassembleur. J'avoue que je ne comprend pas bien comment ca marche. Je ne sais même pas ce qu'est un « opcode » en fait.

  5. #5
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Euh ... Pourquoi ce bout de code bloquerait-il le désassemblage ?

    Désolé, je n'ai rien dit (après test).

    En effet, un désassemblage statique (via gdb et options par défaut, en tout cas) ne donne rien.

    Mais, étant donné qu'un CPU est capable de suivre le code, un désassembleur (ou processeur virtuel à la valgrind) est probablement à même de désassembler.

    La preuve par une session GDB :
    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    mp$ cat - > a.cpp
    #include <iostream>
     
    using namespace std;
     
    int main()
    {
      __asm volatile(".ascii \"\xEB\x01\xE8\"");
      cout << "Hello world!" << endl;
      return 0;
    }
    tmp$ g++ a.cpp 
    tmp$ gdb a.out 
    GNU gdb (GDB) 7.4
    Copyright (C) 2012 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-unknown-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /tmp/a.out...(no debugging symbols found)...done.
    (gdb) disas main
    Dump of assembler code for function main:
       0x0000000000400690 <+0>:     sub    $0x8,%rsp
       0x0000000000400694 <+4>:     jmp    0x400697 <main+7>
       0x0000000000400696 <+6>:     callq  0x4048c359
       0x000000000040069b <+11>:    add    %bh,0x600c40(%rdi)
       0x00000000004006a1 <+17>:    callq  0x400670 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
       0x00000000004006a6 <+22>:    mov    %rax,%rdi
       0x00000000004006a9 <+25>:    callq  0x400680 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@plt>
       0x00000000004006ae <+30>:    xor    %eax,%eax
       0x00000000004006b0 <+32>:    add    $0x8,%rsp
       0x00000000004006b4 <+36>:    retq   
    End of assembler dump.
    (gdb) disas main+7,main+37
    Dump of assembler code from 0x400697 to 0x4006b4:
       0x0000000000400697 <main+7>: mov    $0x4008bc,%esi
       0x000000000040069c <main+12>:        mov    $0x600c40,%edi
       0x00000000004006a1 <main+17>:        callq  0x400670 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
       0x00000000004006a6 <main+22>:        mov    %rax,%rdi
       0x00000000004006a9 <main+25>:        callq  0x400680 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@plt>
       0x00000000004006ae <main+30>:        xor    %eax,%eax
       0x00000000004006b0 <main+32>:        add    $0x8,%rsp
       0x00000000004006b4 <main+36>:        retq 
    End of assembler dump.
    En lisant main+4, on repère l'embrouille : on saute à une adresse qui n'est pas un opcode repéré par gdb.
    Donc on utilise la syntaxe alternative de disas : on désassemble de main+7 à main+37 (main+36 + 1 ; pour récupérer le retq).

    Ce qui nous ramène donc bien au code assembleur de base.

    Donc, certes, ça complique l'analyse, mais elle ne reste pas impossible pour autant.
    Et il est probable qu'il existe un outil le faisant tout seul, sans intervention de l'utilisateur, simplement en utilisant un processeur virtuel et en stockant les instructions ! (valgrind peut servir de couche de base pour ça)

  6. #6
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 395
    Points : 23 758
    Points
    23 758
    Par défaut
    Citation Envoyé par uriotcea Voir le message
    Merci, ca fonctionne maintenant, du moins ca compile.
    Pour la petite histoire ce bout de code assembleur est censé empécher le désassemblage du code en faisant perdre le fil au désassembleur. J'avoue que je ne comprend pas bien comment ca marche. Je ne sais même pas ce qu'est un « opcode » en fait.
    Ok. C'est ultra-classique, en effet, mais notoirement inefficace.

    Un « code opération », ou « code-op », ou encore « opcode » pour « operation code » en anglais, ce sont les briques du langage machine : chaque octet de ton programme en mémoire va contenir un code qui va correspondre à une opération du micro-processeur. Par exemple :

    Code asm : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    00000000 B8 00 4C    mov ax,4c00h
    00000003 CD 21       int 21h
    00000005 C3          ret

    On voit bien dans cet exemple que si ces instructions ont besoin d'opérandes, celles-ci sont placées à la suite du code opération et lues séquentiellement en mémoire. Une fois l'instruction interprétée et exécutée en entier, le micro-processeur passe à l'octet suivant et considère son contenu comme le code d'une nouvelle opération à mener à bien.

    Or « EB 01 » signifie « JMP PositionCourante + 1 octet », sachant que la position courante, pointée par EIP, est en fait l'adresse de la prochaine instruction et pas celle en cours d'exécution. Et « E8 » signifie « CALL », qui est en principe suivie de deux octets pour l'adresse de destination.

    Code ASM : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    00000000 EB 01              jmp   ici+1
    00000002 E8 00 00     ici:  call  0000

    Donc le JMP sert à passer par dessus le E8 introduit artificiellement. Le désassembleur, par contre, lira le JMP, le traitera comme une instruction tout-à-fait valide et passera à la suivante, « CALL », en prenant comme opérandes des codes qui appartiennent en fait à la suite du programme, désynchronisant ainsi la lecture.

    L'ennui, c'est que c'est extrêmement fréquent lors des désassemblages, même lorsque ce n'est pas volontaire. Par exemple, lorsque deux routines sont séparées par de vraies plages de données, ou par du vide. Ensuite, statistiquement, le désassembleur finira quand même par retomber sur ses pieds au bout d'une dizaine d'octets.

    Il ne faut donc qu'une minute maximum à un programmeur averti pour contourner le subterfuge.

  7. #7
    Membre averti Avatar de uriotcea
    Homme Profil pro
    Ingénieur / physicien
    Inscrit en
    Septembre 2003
    Messages
    1 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur / physicien
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 301
    Points : 444
    Points
    444
    Par défaut
    Ok merci pour vos explication détaillés.
    De maniére générale, les techniques anti cracker n'ont jamais pour objectif de l'empécher mais uniquement de le ralentir.
    La question est donc si vous n'aviez pas eu le code initial en C++, combien de temps vous aurait-ils fallu pour comprendre le subterfuge, 1 mn, 1 heures, ou plus?

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 395
    Points : 23 758
    Points
    23 758
    Par défaut
    Citation Envoyé par uriotcea Voir le message
    La question est donc si vous n'aviez pas eu le code initial en C++, combien de temps vous aurait-ils fallu pour comprendre le subterfuge, 1 mn, 1 heures, ou plus?
    Ça dépend réellement de la personne qui va faire l'exercice. Quiconque a fait de l'assembleur suffisamment sérieusement ne butera pas plus d'une minute dessus. Sinon, l'astuce a effectivement quoi rendre les gens perplexes un moment, mais surtout à cause du fait que l'on va chercher une raison légitime à l'existence de ces codes-opérations. Mais, en désespoir de cause, on va toujours finir pas suivre pas à pas le cheminement du processeur, et s'apercevoir que l'on fait un JMP un octet plus loin, que cela ait du sens où non. Au moment même ou l'utilisateur reprendra le désassemblage à partir de ce point, le programme se dévoilera comme par magie. Il faudrait vraiment en mettre partout (ce qui est possible) pour que cela rende le déssassemblage pénible mais, même à ce moment, il est toujours possible d'écrire un script pour les éliminer d'un coup.

    À noter que l'insertion de codes-opérations apparamment incohérents ne sert pas forcément à empêcher le désassemblage : c'était une technique relativement simple et efficace pour « masquer » une instruction. Par exemple, « 31 C0 » sert à faire un « XOR AX,AX », donc à mettre AX à zéro. Si l'on insère « B8 » juste avant, cela forme « MOV AX,0C031h ». La valeur en elle-même n'a pas beaucoup d'intérêt mais selon l'endroit où l'on saute, ça permet d'affecter à AX une valeur nulle ou non-nulle.

    C'était donc un moyen simple et peu coûteux (un seul octet !) d'annuler AX si une procédure avait été prématurément interrompue, par exemple, en faisant un JMP directement vers la sortie, et de lui donner une valeur non nulle si le programme s'est déroulé normalement jusqu'à la fin. C'était également très pratique car, en assembleur, il est difficile de conditionner plusieurs actions à une cause sans recourir aux sauts.

  9. #9
    Membre chevronné
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Points : 1 921
    Points
    1 921
    Par défaut
    Pour info, sous OllyDbg, l'astuce est éventé directement en déroulant le programme ne mode Trace.

Discussions similaires

  1. incomprehension de quelques lignes d'assembleur dans du code C
    Par ultimaroms dans le forum x86 32-bits / 64-bits
    Réponses: 1
    Dernier message: 06/10/2011, 19h31
  2. Intégration d'un code Assembleur dans un code en C
    Par ifdo7a dans le forum Assembleur
    Réponses: 2
    Dernier message: 30/12/2010, 13h15
  3. mettre un fichier telechargeable dans mon code HTML
    Par telecom85 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 09/01/2010, 22h28
  4. Mettre de l'ordre dans les codes mal arrangés !
    Par Ardely dans le forum Delphi
    Réponses: 3
    Dernier message: 24/01/2007, 13h13

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