Partage
  • Partager sur Facebook
  • Partager sur Twitter

[NASM Win64] Bug Hello World

Sujet résolu
    6 janvier 2018 à 15:06:51

    Bonjour,

    Je suis actuellement en train d'essayer d’apprendre l'assembleur 64bits avec NASM, je dispose de la version 2.13. Et j'ai ce code que j'ai trouvé sur Internet :

    org 100h
    
    mov dx,msg
    mov ah,9
    
    int 21h
    
    mov ah,4Ch
    
    int 21h
    
    msg db 'Hello, World!',0Dh,0Ah,'$'


    Et je compile comme ça :

    nasm -f win64 hello.asm 
    golink /console /entry start hello.obj C:\Windows\System32\kernel32.dll C:\Windows\System32\user32.dll C:\Windows\System32\gdi32.dll C:\Windows\System32\msvcrt.dll C:\Windows\System32\winmm.dll 
    

    Mais j'ai cette erreur : "hello.asm:1: error: parser: instruction expected"

    Comment faire ?

    Cordialement et Merci d'avance !

    -
    Edité par Jupiter41 7 janvier 2018 à 9:07:51

    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      7 janvier 2018 à 9:58:07

      C'est normal, tu compiles pour Win64 mais ton code c'est de l'assembleur 16 bit !

      Pour exécuter de l'assembleur 16 bit tu peux utiliser un emulateur tel que DosBox ou qemu, et surtout il faut compiler avec une autre option...

      http://esauvage.developpez.com/tutoriels/asm/assembleur-intel-avec-nasm/?page=page_1

      -
      Edité par Anonyme 7 janvier 2018 à 9:59:12

      • Partager sur Facebook
      • Partager sur Twitter
        7 janvier 2018 à 10:26:16

        J'ai pourtant cherché un code Windows 64bits ... Je n'en ai trouvé aucun autre :( Auriez-vous un bon tutoriel ou/et un exemple d'Hello World en NASM 64bits (ou 32) ? (sans utiliser de fonction externe comme printf)

        -
        Edité par Jupiter41 7 janvier 2018 à 10:29:02

        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          7 janvier 2018 à 11:46:48

          Si tu veux afficher "Hello World" avec Windows tu es obligé de passer par des fonctions, au moins celles de l'API.

          Voici un code "Hello World" pour Windows 64 (fait avec amour) :

          main.asm

          extern GetStdHandle
          extern WriteFile
          extern Sleep
          extern ExitProcess
          
          %define STD_OUTPUT_HANDLE (-11)
          
          section .data
          hello_str db "Hello World", 13, 10
          hello_size equ ($ - hello_str)
          
          output_handle dq 0
          
          section .text
          
          global main
          main:
          	;Aligne la pile
          	and rsp, 0xFFFF_FFFF_FFFF_FFF0
          	mov rbp, rsp
          
          	;Récupère l'output standart
          	mov ecx, STD_OUTPUT_HANDLE
          	call GetStdHandle
          	mov [output_handle], rax
          	
          	;Affiche le message
          	;Shadow Space
          	sub rsp, 48
          	mov rcx, [output_handle]
          	mov rdx, hello_str
          	mov r8d, hello_size
          	mov r9, 0
          	mov QWORD [rsp + 32], 0
          	call WriteFile
          	;Détruit l'espace de pile alloué pour les paramètres de la fonction
          	add rsp, 48
          	
          	;Pause de 1000 millisecondes pour donner le temps de voir
          	;Shadow Space
          	sub rsp, 0x20
          	mov ecx, 1000
          	call Sleep
          	
          	;Quitte
          	xor rcx, rcx
          	call ExitProcess



          make.bat:

          @echo off
          
          nasm.exe -fwin64 main.asm -o Obj/main.o
          gpp.exe -s -m64 Obj/main.o -o hello.exe C:\Windows\System32\kernel32.dll
          
          pause

          Il faut noter que je link avec g++, mais je pense que tu sauras adapter à ton linker.

          -
          Edité par Anonyme 11 janvier 2018 à 21:57:57

          • Partager sur Facebook
          • Partager sur Twitter
            7 janvier 2018 à 15:11:52

            Salut ! Merci pour ce code mais il ne marche pas chez moi :( J'utilise ces commandes pour compiler (qui sont normalement correct) :

            nasm -fwin64 hello.asm
            golink /console hello.obj C:\Windows\System32\kernel32.dll

            J'ai juste un petit Warning : 

            Warning!
            Assumed entry point (Start) was not found.
            Output file: hello.exe
            Format: X64 size: 2,048 bytes

            Mais lorsque j’essaye de lancer l'exe j'ai l'erreur "hello.exe a cessé de fonctionner"

            PS : Comment as-tu appris a programmé en asm 64 bits ? :)

            Et pourquoi ont-ils retiré les fonctions fonctionnant avec int 21h genre mov ah, 9 etc... ? Il n'y a plus aucun moyen de passer par ces fonctions ? :'( Je trouvais sa jolie x)

            -
            Edité par Jupiter41 7 janvier 2018 à 15:14:12

            • Partager sur Facebook
            • Partager sur Twitter
            Anonyme
              7 janvier 2018 à 16:04:03

              Héhé ! Ça n'a rien d'un "petit warning" justement ! Il ne trouve pas le point d'entrée du programme ! Il semblerait que golink cherche "Start", sauf que moi je l'ai appelé "main". Ajoute ceci aux paramètres de golink pour qu'il utilise main comme point d'entrée, et ça devrait fonctionner :

              golink /entry main etc...

              Si ça crash toujours après ça c'est que j'ai peut-être fait une erreur dans le programme (même si chez moi il marche...)

              Jupiter41 a écrit:

              PS : Comment as-tu appris a programmé en asm 64 bits ? :)

              En fait je sais pas trop... Au début j'ai fait de l'asm 16 bit (un tout petit peu) parce que il faut toujours commencer par là, et après j'ai fait un peu de MASM 32 et 64 bit, avant de repasser sur NASM... Le problème c'est qu'il n'y a pas vraiment de tuto (en tout cas je n'en connais pas) qui enseigne "l'assembleur 64 bit pour les nuls en partant de 0", donc à force de recherche tu finis par comprendre petit à petit comment ça marche...

              Jupiter41 a écrit:

              Et pourquoi ont-ils retiré les fonctions fonctionnant avec int 21h genre mov ah, 9 etc... ? Il n'y a plus aucun moyen de passer par ces fonctions ? :'( Je trouvais sa jolie x) 

              Concernant mov ah, 21 et toutes ces instructions (et pas fonctions), elles n'ont pas été enlevées, elles existent toujours, seulement ah correspond au 8 bits de poids faibles du registre ax, qui lui même correspond aux 16 bits de poids faibles du registre eax, qui lui même correspond aux 32 bits de poids forts du registre rax (registre 64 bit). Comme ici je manipule des données sur 32 ou 64 bits, j'utilise les registres eax, rax, etc...

              Et pour les int 0x21, elles ne sont plus disponibles, déjà car elles sont extrêmement limitées, et en plus parce qu'elles font appel aux services du BIOS, or, on ne peut pas envisager qu'une application quelconque sur un OS moderne accède directement au services du BIOS, aujourd'hui un programme communique avec les périphériques par le biais de l'OS (API Windows par exemple), et c'est une très bonne chose.

              Il faut penser aussi que l'assembleur en tant que tel, à plus forte raison sous Windows, est relativement inutile pour la plupart des taches. Il vaut mieux avoir un code en C (ou autre) qui fait appel à quelques fonctions écrites en assembleur (parce qu'on a pas le choix par exemple).

              Voici quand même un petit document qui permet de comprendre quels sont les registres 64 bits (les principaux étant juste des registres 16 bits étendus à 64 bits), et qui parle aussi des conventions d'appel sous Windows, Linux...

              • Partager sur Facebook
              • Partager sur Twitter
                7 janvier 2018 à 16:46:46

                Effectivement sa marche beaucoup mieux x) ! (pour les curieux il faut rajouter "/entry main" dans la commande pour compiler"). MErci beaucoup pour tes explications et ton pdf !

                Ah bon ? j'ai lu ici : http://benoit-m.developpez.com/assembleur/tutoriel/ que c'était des fonctions o_O

                :waw: Je pensais pourtant que instructions/fonctions et interruptions été lié :( Pour reprendre l'exemple de mov ah, 9 que c'est une instructions spécifique de int 21h

                • Partager sur Facebook
                • Partager sur Twitter
                Anonyme
                  7 janvier 2018 à 17:27:36

                  Jupiter41 a écrit:

                  Effectivement sa marche beaucoup mieux x) ! (pour les curieux il faut rajouter "/entry main" dans la commande pour compiler*"). MErci beaucoup pour tes explications et ton pdf !instructions spécifique de int 21h

                  *linker (attention c'est pas pareil)

                  Jupiter41 a écrit:

                  Ah bon ? j'ai lu ici : http://benoit-m.developpez.com/assembleur/tutoriel/ que c'était des fonctions o_O

                  mov ah, 9 est une instruction, on dit au processeur : "Place l'entier 9 dans le registre ah".

                  Par contre pour int 21h c'est plus compliqué. C'est une instruction, mais elle déclenche une interruption (Pour résumer, int 21h signifie pour le processeur "Déclenche l'interruption 21h"), et le code appelé par cet interruption va appeler une fonction du BIOS. Je sais c'est pas très clair, j'essaye de détailler ça en bas.

                  Jupiter41 a écrit:

                  Je pensais pourtant que instructions/fonctions et interruptions été lié :( Pour reprendre l'exemple de mov ah, 9 que c'est une instructions spécifique de int 21h

                  Euh... Quoi ?

                  mov ah, 9
                  int 21h

                  Voilà ce que fait ce bout de code :

                  • Je place la valeur 9 dans le registre ah
                  • Je fais déclenche l'interruption 21h du BIOS
                  • L'interruption 21h regarde la valeur contenue dans ah, et voit que c'est 9
                  • Elle va faire appel à la fonction 9 de l'interruption 21h, c'est à dire afficher une chaîne de caractère terminée par '$', l'adresse de la chaîne étant contenue dans le registre dx.

                  J'en fais un autre :

                  mov ah, 2
                  int 21h
                  • Je place la valeur 2 dans le registre ah
                  • Je déclenche l'interruption 21h du BIOS
                  • L'interruption 21h du BIOS regarde la valeur contenue dans ah, et voit que c'est 2
                  • Elle va faire appel à la fonction 2 de l'interruption 21h, c'est à dire afficher la caractère contenu dans le registre dl

                  Mais une fonction ce n'est pas forcément une fonction du BIOS, ça peut aussi être un bout de programme qu'on appelle par l'instruction call, et qui se termine par l'instruction ret (return). Par exemple dans mon exemple du haut j'appelle successivement les fonctions GetStdHandle, WriteFile, Sleep, et ExitProcess (qui font partie de l'API Windows, mais on peut aussi écrire soi-même ses fonctions, je pense que tu verras ça un peu plus tard).

                  Voilà, j'espère ne pas trop t'avoir embrouillé, c'est pas facile à expliquer...

                  • Partager sur Facebook
                  • Partager sur Twitter
                    7 janvier 2018 à 18:10:43

                    Tu as bien compris ce que je voulais dire et je ne suis pas embrouillé :) Du coup on ne peux plus enclencher de fonction BIOS... Je trouve dommage que l'on soit obligé de passer par les fonctions de L'API alors que l'assembleur est censé être le langage le plus proche du langage machine et donc peux interagir et manipuler plus "profondément" et directement l'ordinateur...  On ne peut même plus détourner d'interruption du coup ? X) Et certaines fonctions ont-elles disparu ?

                    -
                    Edité par Jupiter41 7 janvier 2018 à 18:14:32

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      7 janvier 2018 à 18:59:32

                      En fait on me peut plus en déclencher sous Windows, et c'est logique puisque c'est non seulement un système archaïque qui n'est plus du tout compatible avec le fonctionnement actuel des OS (les OS n'utilisent plus les fonctions du BIOS mais leurs propres driver depuis bien longtemps), mais en plus ça permet un niveau de privilège bien trop élevé (tu peux écrire sur le disque, du moins sur le début). C'est d'ailleurs pour ça que je disais que l'assembleur sous Windows a peu d'intérêt.

                      Mais au démarrage, l'ordinateur est en "mode réel" (16 bit) et permet l'utilisation des interruptions du BIOS, tu peux donc t'amuser à programmer un OS archaïque 16 bit, ou même un bootsector, je te met plus bas un lien vers un genre de tuto/exemple (PoorOS) qui fait pas à pas un petit bootsector, avec le passage en mode protégé, etc...

                      https://www.enib.fr/~harrouet/misc.html#pooros (Bien lire le README, il contient les explications)

                      -
                      Edité par Anonyme 7 janvier 2018 à 19:02:47

                      • Partager sur Facebook
                      • Partager sur Twitter
                        7 janvier 2018 à 19:05:19

                        Le fait d'avoir des privilege élevé était l'un des intérêts les plus importants je trouve : on pouvait faire ce que l'on voulait au niveau de la mémoire etc... Mais bon tant pis X) J'arrive trop tard :p

                        Merci beaucoup pour tes explications ! :)

                        • Partager sur Facebook
                        • Partager sur Twitter
                          11 janvier 2018 à 10:57:53

                          Bonjour.

                          Pour la programmation en assembleur 64 bits avec nasm j'avais crée un forum l'année dernière mais que j'ai laissé un peu tombé pour différentes raisons mais il peut toujours servir à des débutants :

                          http://assembleur64.forumactif.com/

                          • Partager sur Facebook
                          • Partager sur Twitter
                            11 janvier 2018 à 19:09:58

                            Bonjour PitchPitch, moi personnellement je laisse un "shadow space" de 40 bytes pour WriteFile :

                            	sub rsp, 48
                            	mov QWORD [rsp + 40], 0
                            	call WriteFile
                            	add rsp, 48

                            Je me trompe de faire ça ou pas ? (j'ai trouvé cette valeur en analysant le code de la fonction WriteFile avec un débogueur 64 (0x90-0x60=0x30))

                            PS: je suis aussi débutant en asm 64 intel

                            • Partager sur Facebook
                            • Partager sur Twitter
                              11 janvier 2018 à 19:12:47

                              PS: Je vais répondre sur ce compte petite erreur de login
                              • Partager sur Facebook
                              • Partager sur Twitter
                              Anonyme
                                11 janvier 2018 à 21:53:02

                                Oui tu as raison, j'avoue que je ne le savais (il faut dire que je ne manipule jamais des fonctions de l'API Windows en assembleur), du coup je vais essayer d'expliquer à Jupiter comment ça marche et pourquoi il faut le faire.

                                Il faut d'abord savoir d'où vient ce shadow space. En 32 bit (avec l'architecture x86), la totalité des paramètres d'une fonction étaient passés par la pile. Avec l'arrivée du 64 bit et ses registres r8 à r15 (architecture x86-64 ou AMD64, c'est la même), on a inventé de nouvelles conventions pour le passage de paramètre, utilisant les registres. Sous Windows, cette convention dit que les 4 premiers paramètres sont passés respectivement par les registres rcx, rdx, r8, r9, et le reste par la pile. Mais, même si les premiers paramètres sont passés par les registre, les fonctions appelées considèrent qu'ils occupent une place sur la pile, voici donc comment doit être organisée la pile juste avant l'instruction "call fct", dans le cas d'une fonction à 5 arguments :

                                Il faut noter que la fonction lira les valeurs des 4 premiers arguments dans les registres, et qu'il n'est donc pas nécessaire de mettre leurs valeurs sur la pile là où leur "fantôme" est. Je rappelle aussi que :

                                push rax
                                ;Revient au même que :
                                sub rsp, 8   ;Il est important de noter le sub
                                mov QWORD [rsp], rax

                                Pour appeler WriteFile il faut donc faire ceci (je vais mettre à jour mon "Hello World" plus haut):

                                sub rsp, 40
                                mov rcx, hFile
                                mov rdx, lpBuffer
                                mov r8, nNumberOfBytesToWrite
                                mov r9, lpNumberOfBytesWritten
                                mov QWORD [rsp + 32], lpOverlapped
                                call WriteFile
                                add rsp, 40



                                Mais ce n'est pas tout, en faisant les recherches sur le sujet, j'ai remarqué que j'avais oublié un autre détail (oui ça fait beaucoup d'erreurs). En fait, pour appeler les fonctions de l'API Windows, il faut aligner la pile sur sur un multiple de 16*. La meilleure façon de la faire est d'aligner la pile sur sur un multiple de 16 au début de la fonction main, et de s'arranger pour que, lorsqu'on appelle une fonction de l'API Windows (ou même d'une autre API), la pile soit alignée sur un multiple de 16. C'est à dire que, si une fonction a un nombre impair d'arguments, on soustrait le pointeur de pile de 8 octets de plus pour garder l'alignement sur 16.

                                Pour aligner la pile sur un multiple de 16 :

                                and rsp, 0xFFFF_FFFF_FFFF_FFF0

                                *Cela signifie que l'adresse est de la forme 0x....0

                                Voilà, je dois avouer que je suis pas sûr de tout ce que j'ai avancé parce que les sources se contredisent un peu parfois, du coup n'hésitez pas à me reprendre si j'ai dit une bêtise, et je vais mettre à jour le "Hello World".

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  12 janvier 2018 à 8:12:43

                                  Merci beaucoup pour ces explications !
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    12 janvier 2018 à 17:27:59

                                    Merci beaucoup, même en cherchant beaucoup sur internet je n'ai pas réussi à trouver autant d'infos,

                                    Je voulais aussi savoir comment faire un hello world sans la WINAPI (printf et autres...) avec un syscall, honnêtement j'ai trouvé sur linux mais pas windows. Avec un débogueur j'ai essayé de voir comment GetStdHandle et WriteFile marche, GetStdHandle m'a l'aire d'un algorithme simple et WriteFile j'ai du mal à comprendre

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      12 janvier 2018 à 19:28:30

                                      Salut !

                                      Je me permet de revenir poser une petite question :) :

                                      Ayant Ubuntu installé sur mon ordi (sur un disque dur externe ^^)  , j'ai décidé de passer sur Linux pour programmer en ASM car on pouvait toujours utilisé les appels systèmes (et même les interruptions en 32bits et il y a syscall en 64bits, j'ai aussi vu des interruptions sur des codes 64bits mais en remplaçant syscall par elle mon code compilé sans erreur mais le message ne s'affichait pas...). Mais je me retrouve avec un problème d’où ma question : Auriez vous un lien vers l'ABI ou un équivalent 64bits ? Car dès que je sort du simple "Hello world" avec l'utilisation de la fonction printf (write plus précisément) en appels systèmes, et que j'aimerais par exemple utilisé scanf j'ai du mal à trouver la fonction correspondante (read peut-être pour scanf ?). Comment faire ?

                                      Cordialement et Merci d'avance !

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        14 janvier 2018 à 11:32:07

                                        Je me permet de faire un petit UP :)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                        Anonyme
                                          14 janvier 2018 à 14:33:22

                                          Je pense que tu devrais faire un nouveau post, éventuellement sur un forum plus spécialisé.

                                          Pour récupérer des saisies de chaînes de caractères, c'est très probablement read, mais il faut trouver le flux standard d'entrée.

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            14 janvier 2018 à 14:54:18

                                            Ok et merci pour ta réponse ! Sur quel forum me conseillerais-tu d'aller ?
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              18 janvier 2018 à 18:05:02

                                              Les fonctions syscall de linux sont référencées sur ce site http://syscalls.kernelgrok.com/

                                              et en français : http://manpagesfr.free.fr/man/man2/Index.2.html

                                              Pour lire des données c'est la fonction read code 03h 

                                              Mais il faudrait creer un nouveau post car le titre est nasm Win64 don rien à voir avec linux.

                                              -
                                              Edité par PaulDurelin 18 janvier 2018 à 18:07:08

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                21 janvier 2018 à 13:28:53

                                                Merci pour ta réponse ! Ce poste est du coup definitivamente clôt :)
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  26 juin 2018 à 14:56:41

                                                  Je ne sais pas si c'est un peu tard mais il y a un tutoriel en beta que je transforme en livre qui traite vraiment bien de ce sujet. 

                                                  Voici le lien https://openclassrooms.com/courses/1837751?status=waiting-for-publication (il faut être iscrit sur le site pour le voir) et  voici le forum de discusion

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  tu aimerais apprendre l'assembleur avec NASM depuis zéro ? clique ici suis le fil de discussions ici
                                                    16 juillet 2018 à 9:06:19

                                                    Salut ! :)

                                                    Désolé pour le retard de ma réponse, je connaissais déjà ce tutoriel ^^ mais pas le fil de discussion donc merci ! Mais ce tutoriel est-il en pause ? Car cela fait longtemps qu'il n'a pas été mis à jour, non ? :p
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      21 juillet 2018 à 16:28:41

                                                      je suis actuellement en train de publier un livre complet qui reprend les bases de la programmation en "assembleur" en douceuravec beaucoup de pratiques orientées cyber sécurité, programmation d'OS etc...Le livre sors dans quelques jours (je suis joignable à ahounoukhaled@gmail.com) 

                                                      edit:les version 32 et 64 bits de Windows sont pris en compte. Et le retoru des betas testeurs me font croire que lelivre est assez bien. Mais tu jugeras dès que tu l'auras

                                                      -
                                                      Edité par cotoporto 21 juillet 2018 à 16:31:49

                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                      tu aimerais apprendre l'assembleur avec NASM depuis zéro ? clique ici suis le fil de discussions ici
                                                        23 juillet 2018 à 12:54:57

                                                        D'accord c'est cool et ça m'a l'air très intéressant ! :) Je lirais ton livre ^^, donc prévient moi quand il sort s'il te plaît :)

                                                        -
                                                        Edité par Jupiter41 23 juillet 2018 à 12:56:10

                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          24 juillet 2018 à 11:28:39

                                                          Excellent! je le ferai...Peux-tu me faire parvenir ton e-mail par MP. merci
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                          tu aimerais apprendre l'assembleur avec NASM depuis zéro ? clique ici suis le fil de discussions ici

                                                          [NASM Win64] Bug Hello World

                                                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                          • Editeur
                                                          • Markdown