Appel d'une fonction de l'API avec plus de 4 paramètres

Voir le sujet précédent Voir le sujet suivant Aller en bas

Appel d'une fonction de l'API avec plus de 4 paramètres

Message par Admin le Mer 30 Nov - 18:30

Nous avons vu que les parametres d'appel d'une fonction de l'API windows étaient passés dans les registres rcx,rdx, r8 et r9. Mais comment passer les autres paramètres si nous avons plus de 4 paramètres. Et bien, nous les passons par push en respectant un ordre bien précis (voir la documentation ).
Tout d'abord nous libérons la place éventuelle prise pour un appel de fonction précédent par add rsp,20H.
Puis nous devons 'pusher' les paramètres supplémentaires sur la pile mais il faudra que la pile soit alignée lors du dernier push.
Et donc suivant le nombre de paramètre supplémentaires il faudra ou non réaligner la pile avant !!
Dans l'exemple ci dessous, nous avons un seul paramètre  supplémentaire donc nous alignons la pile par sub rsp,8h et nous "pushons" notre paramètre.  Et maintenant nous allouons la place pour les 4 paramètres standards par sub rsp,20h puis alimentons les 4 registres et appelons la fonction wsprintfA. Mais ce n'est pas fini : après l'appel nous devons libérer la place pris par notre premier alignement et par le push du parametre  par l'instruction add rsp,10h  (équivalent à add rsp,16). Nous ne liberons pas tout de suite la place des 4 paramètres car nous avons un autre appel de la fonction MessageBoxA derrière.
Pour prendre de bonnes habitudes, nous testons le code retour des fonctions pour afficher un message d'erreur. Nous avons modifié la procédure afferreur pour afficher le numéro de ligne où s'est produit l'erreur en le passant dans le registre r9 :ça peut beaucoup aider par la suite !!!
Ah oui ! autre point : dans ce petit programme nous avons appelé la procédure d'affichage à partir d'une autre procédure. Dans cette dernière, nous n'appelons pas de fonctions windows mais nous avons quand même procédé à l'alignement de la pile en début de procédure.
Je vous conseille cette bonne habitude car sinon dans de longs programmes ou vous appelez des procédures variées en cascade, vous risquez de vous retrouver avec un désalignement de la pile et un crash.

Code:

;vidagepile.asm programme verification alignement de la pile
; appel fonction API avec plus de 4  parametres
global Main
extern ExitProcess,MessageBoxA,GetLastError,wsprintfA     ; fonction API windows
MB_OK equ 000h
MB_OKCANCEL equ 001h
MB_ICONERROR equ 010h
MB_ICONINFORMATION  equ 040h
;==============================================
;données initialisées
;==============================================
section .data
szTitre:  db 'Win64', 0
szTitreErreur:  db 'Win64', 0
szMsg:    db 'Hello world!', 0
szMsg1    db "Appel ok",0
szMsgErreur db "Erreur  N° %d  à la ligne %d ",0
szMsgForm db "Valeur de rsp : %p Valeur de rax : %p à la ligne %d",0

;==============================================
; données non initialisées
;==============================================
section .bss
szZoneRep   resb 80

section .text
Main:
    sub rsp, 28h  
  
    call appel
    mov  rcx,rax     ; code retour avec le code retour de MessageBoxA
    call ExitProcess  ; fonction de fin du programme
;=================================================================
; verification lors de l'appel
;=================================================================
appel:
 sub rsp,8h  ; alignement pile
    ;sub rsp,20h     ; inutile ici car pas d'appel de fonction
 mov rax,10    ; pour avoir quelque chose à afficher
 push __LINE__  ; pour afficher le N° de ligne
 push rsp       ; pour afficher la pile
 push rax       ; passage de 3 paramètres
 call vidpiles
.fin:
   ; add rsp,20h    ; libere la place des 4 parametres
 add rsp,8h     ; libere la place de l'alignement
    ret
;================================================================
;Appel d'une fonction avec plus de 4 parametres
;=================================================================
vidpiles:
 enter 0,0
 sub rsp,8h     ; 3 parametres donc pile à aligner
 sub rsp,20h     ; réservation place des 4 parametres
 ;eventuellement appel autres fonctions
 add rsp,20h     ; liberation place
 sub rsp,8h      ; pour aligner la pile avant les push suivant
    push qword[rbp+32] ; conient le N° de ligne
 sub rsp,20h     ; réservation place des 4 parametres
 mov rcx,szZoneRep   ; zone de retour du formatage
 mov rdx,szMsgForm ; libellé du message
 mov r8,[rbp+24]      ; vidage de rax
 mov r9,[rbp+16]      ; vidage de rsp
 call wsprintfA   ; appel de la fonction de formatage
 add rsp,10h      ; liberation de la place du push et de l'alignement
 mov r9,__LINE__ - 2   ; préparation du registre en cas d'erreur
 cmp rax,0         ; la fonction est-elle ok ?
 je .erreur        ; non afficahge de l'erreur avec le N° de ligne
 mov rcx, 0       ; handle  fenêtre
    mov rdx,szZoneRep  ; adresse du message formaté
    mov r8,szTitre  ; adresse du titre de la fenêtre
    mov r9, MB_OK       ;  Normal
    call MessageBoxA
 mov r9,__LINE__  - 1  ; verification si cette fonction est OK
 cmp rax,0
 jne .fin       ; si oui on termine la procedure
.erreur:
 call afferreur
.fin:
  ;  add rsp,28h   ; inutile car le leave restaure bien rsp
 leave       ; pendant du enter
 ret 24   ; 3 parametres
;=================================================================
; affichage du message d'erreur
;=================================================================
afferreur:
    sub rsp,8h
    sub rsp,20h
 call GetLastError   ;récupèration du code erreur dans le registre rax
 mov rcx,szZoneRep   ; zone de retour du formatage
 mov rdx,szMsgErreur ; libellé du message
 mov r8,rax       ; code erreur
 ; et r9 contient le N° de ligne
 call wsprintfA   ; on devrait tester aussi le code retour
 mov rcx, 0       ; handle  fenêtre
    mov rdx,szZoneRep   ; adresse du message
    mov r8,szTitreErreur   ; adresse du titre de la fenêtre
    mov r9, MB_OK|MB_ICONERROR      ;  type du message : Erreur
    call MessageBoxA
.fin:
   add rsp,28h
   ret

Comme vous pouvez le constater l'affichage est correct sans plantage. Et vous allez me dire que j'ai raconté des blagues car l'adresse de la pile affichée ne se termine pas par 0 !!!  Réflechissez !!  
Vous avez trouvé pourquoi ?   Et oui le push de la pile a été effectué après le push du N° de ligne et ce push a désaligné la pile de 8 octets.
Pour en être sûr, remplacer l'instruction mov rax,10 par mov rax,rsp et vous verrez que l'affichage du registre rax cad l'adresse de la pile avant tous les push se termine bien par 0 !!!!
avatar
Admin
Admin

Messages : 38
Date d'inscription : 28/11/2016

Voir le profil de l'utilisateur http://assembleur64.forumactif.com

Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum