.:ASM tutorial day1 by rAsM:.
- 0x00 Intro - 0x01 Les registres - 0x02 Les types de données - 0x03 Declaration de variables - 0x04 Les adresses - 0x05 L'instruction mov - 0x06 Les sauts - 0x07 Les instructions de comparaison - 0x08 Les labels - 0x09 L'instruction call - 0x0A Les procedures ou les fonctions - 0x0B La pile - 0x0C Configurer FASM - 0x0D Les APIs - 0x0E Le premier programme
- 0×00 Intro:
Voici un petit tutorial pour les débutants en assembleur, j’y explique
somairement quelques notions de base le but est avant tout de fournir une
source asm commentée et que vous découvriez un peu par vous mêmes comment
ça fonctionne.
Vous aurez besoin de FASM pour windows et ollydbg v1.10.
La source day1 contient 2 petits bugs j’espère que vous
serez assez malins pour les trouver.
Mais tout d’abord lisez le texte
avant de commencer à faire joujou avec FASM et la source.
- 0×01 Les registres:
Ce sont des emplacements dans le processeur qui peuvent contenir des valeurs
et bien plus. Ils sont essenciels à la programmation car ils permetent de
manipuller les données.
En voici quelques uns avec leurs sudivisions par exemple eax se sudivise en
AX et AX en AH et AL.
+---------------+ | EAX | EAX, taille 32bits +-------+---+---+ | | AX | AX, taille 16 bits +-------+-------+ | | AH| AL| AL, AH, taille 8 bits +-------+---+---+ +---------------+ | EBX | +-------+---+---+ | | BX | +-------+-------+ | | BH| BL| +-------+---+---+ +---------------+ | ECX | +-------+---+---+ | | CX | +-------+-------+ | | CH| CL| +-------+---+---+ +---------------+ | EDX | +-------+---+---+ | | DX | +-------+-------+ | | DH| DL| +-------+---+---+
Ceux-ci servent à effectuer la plus part des opérations de notre programme.
Nous avons encore quelques registres spéciaux: ESP et EBP qui définissent la
pile ou stack, j’en parle plus loin.
Il existe encore ESI et EDI qui servent dans le programe day1 comme pointeurs
sur des chaines de caractères.
EIP sert de pointeur sur la prochaine instruction à éxecuter on ne peut pas
le modifier directement.
Et pour finir il nous reste le registre des flags, il fait 32bits en taille
chaque bit represente un flag. Et il ne peut être modifié directement. Mise à
part certaines instructions qui arment les flags, par exemple si le flag Z (zéro)
vaut 1 un saut tel que jz (jump if zero) sera exécuté.
On peut tout faire avec les registres sauf avec certains, vous verrez plus
loin comment leur affecter des valeurs, etc.
- 0×02 Les types de données:
Le DWORD, c’est un nombre qui a pour taille 32bits soit 4 octets.
Le WORD, il a pour taile 16bits soit 2 octets.
Le BYTE contient 8bits et est égal à 1 octet.
Vous l’aurez compris qu’avec EAX vous pouvez y mettre un DWORD, avec AX un
WORD et avec AL ou AH un BYTE.
- 0×03 Déclaration de variables:
Les variables sont des données contenues dans la mémoire pour y accéder nous
devons savoir ou elles se situent. Les emplacements dans la mémoire ont pour
taille un octet, chaqun de ces emplacements a une adresse. Dans les
processeurs 32 bits une adresse possede comme taille 32bits.
Dans nos programmes nous n’avons pas à faire directement à des adresses mais
à des noms que nous donnons aux variables pour y acceder facilement.
Les chaines de caractères MonString db ‘kikooolol’,0
Les chaines de bytes MonByte db 09h,08h,0
Les buffers (chaine de bytes vide) MonBuffer db 20 dup(?)
20 est la taille (nombre de bytes) et dup(?) l’initialise à 0
- 0×04 Les adresses:
Dans les processeurs 32 bits les adresses sont des nombres de 32 bits également
elles pointent sur des emplacements dans la mémoire. Ainsi chaque variable
possede son adresse. Comme vous l’aurez sans doute compris nous accédons aux
variables par une adresse mais FASM nous facilite grandement la tâche en nous
permetant d’utiliser un nom ou un label au lieu d’une adresse.
- 0×05 L’instruction mov:
Celle-ci est la base des intructions elle permet d’affecter des valeurs à
des registres ou bien à des variables.
mov eax,1
EAX aura comme valeur 1.
mov eax,1 mov edx,eax
EDX aura comme valeur 1 et EAX aussi.
Imaginons une variable DWORD (MonDword dd 1234):
mov eax,MonDword
EAX aura pour valeur l’adresse mémoire de MonDword à la quelle se trouve
la valeur 1234.
mov eax, dword [MonDword]
Aura comme conséquences d’affecter la valeur 1234 à EAX. Lors de la lecture/
écriture de valeurs il faut spécifier la taille de ce qu’on va lire elle doit
être la même que le registre.
Imaginons maintenant que nous voulons lire la seconde lettre d’une chaine
de caracteres. (Machaine db “abcde”,0)
mov al, byte [Machaine]
AL aura la valeur ascii de “a” soit 61h. Pour lire le second caractère il faut
ajouter 1 à l’adresse de Machaine.
mov al, byte [Machaine+1]
Et comme ça AL aura la valeur “b” ou 62h.
On peut aussi utiliser un registre pour incrémenter l’adresse de la variable:
mov ecx,1 mov al, byte [Machaine+ecx]
Ou bien on peut utiliser un registre comme pointeur et incrémenter celui-ci:
mov eax,Machaine inc eax ;incrémente de 1 EAX mov al,[eax]
On peut aussi utiliser d’autres opérandes:
mov ecx,1 mov al, byte [Machaine+ecx*2] ;AL aura la valeur de “c” inc ecx mov al, byte [Machaine+ecx*2] :AL aura la valeur de “d”
Encore un code equivalent:
mov eax,Machaine mov ecx,1 mov al,byte [eax+ecx]
Sachez que ces modes d’accès aux données sont compatibles avec toutes les
instructions qui prement des adresses comme opérandes. Par exemple “cmp”.
- 0×06 Les sauts:
Ces instructions permetent de modifier EIP indirectement. En gros ca nous permet
de sauter du’un endroit du code à l’autre.
jmp label ...code1 label: ...code2
Lors de l’éxecution du jmp code1 ne sera pas éxecuté mais code2 le sera.
Il existe des sauts conditionels tels que jz (jmp if zero) jnz (jmp if not
zero) la condition depend du registre de flags si le flag Z est égal à 1
le saut jz sera executé.
- 0×07 Les instructions de comparaison
Cmp sert à comparer 2 opérandes et vont modifier les flags selon le
résultat de la comparaison.
mov eax,200 cmp eax,100 jz egal ...code1 egal: ...code2
Le code2 ne sera jamais executé car les opérandes ne sont pas égales donc
le flag Z sera à 0.
- 0×08 Les labels:
Les labels servent à définir une zone du code en gros votre code sera en mémoire
et aura une adresse précise que nous ne pouvons pas connaitre avant la compilation.
Donc au lieu de faire jmp 00400000 nous fesons jmp label.
- 0×09 L’instruction call:
Elle permet apeller une fonction une fois que la fonction est terminée, l’execution
du code retourne juste après le call.
call label ...code1 label: ...code2 ret
On va sauter à code2 une fois l’intruction ret exectutée on retourne à code1.
Notez que le call ajoute dans la pile l’adresse de retour ce qui permet au
ret de retourner à code1 en utilisant cette adresse.
- 0×0A Les procédures ou fonctions:
L’intruction qui permet d’appeller une fonction est le call, par exemple:
call Monproc. On peut aussi utiliser un registre: genre call eax pour autant
que EAX contienne l’adresse de notre procédure.
Elles servent à simplifier le code surtout lorsqu’on doit éxécuter le même
code plusieurs fois à des endroits differents. Cela permet aussi le diviser
en petites fonctions pour faciliter la compréhesion de celui-ci.
Pour déclarer une procédure on utilise la macro proc:
proc Maprocedure,parametre1:DWORD,parametre2:DWORD ...notre code ret endp ;marque la fin de la procédure
DWORD indique à FASM la taille des paramètres. Le ret est l’instruction de fin
de la procedure elle permet de retourner juste après le call qui l’a appelée.
- 0×0B La pile:
C’est une zone mémoire delimitée par les registres esp et ebp, esp pointe sur
le bas de la pile et ebp à sa base, le haut.
En gros elle permet d’y stocker des variables temporairement.
push eax
Ce code sauvegarde la valeur eax dans la pile on la recupere grace a:
pop eax
Qu’arrive t’il a esp quand on met une valeur dans la pile:
push 1234
esp 00220000 pointe sur 00001234
esp+4 00220004 pointe sur 00000000
esp+8 00220008 pointe sur 00000000
Si on enleve va valeur avec un pop eax.
esp-4 00220008 pointe sur 00001234
esp 00220004 pointe sur 00000000
esp+4 00220000 pointe sur 00000000
Donc quand on ajoute une valeur dans la pile on soustrait 4 à esp. Quand on
enlève une valeur on aditione 4 à esp. Pour plus de compréension regardez
dans ollydbg ce qui se passe lors des push/pop.
Maintenant qu’est ce qui se passe lors de l’appel d’une fonction:
push 1 ;parametre 1 push 2 ;parametre 2 call mafonction
La pile aura ressemblera a ça:
esp 00220000 pointe sur 00402200 ;ceci est l'adresse de retour
esp+4 00220004 pointe sur 00000002
esp+8 00220008 pointe sur 00000001
Donc le code de la fonction va ressember a ceci:
push ebp mov ebp,esp ...code leave ret 8
Le push ebp permet de sauvegarder ebp temporairement, en affectant la valeur
de ebp à esp on va créer une nouvelle pile temporaire qui ressemble a ça:
esp = ebp 0021fffc pointe sur l'ancienne valeur de ebp esp+4 00220000 pointe sur l'adresse de retour
Maintenant la fonction peut utiliser la petite pile qu’elle a reservé pour
y metre des valeurs, par exemple:
push 1234 esp 0021fff8 pointe sur 1234 ebp = esp+4 0021fffc pointe sur l'ancienne valeur de ebp esp+8 00220000 pointe sur l'adresse de retour
Lorsque la fonction quite “leave” va utiliser EBP pour remetre esp à pointer
sur l’ancienne valeur de EBP et faire l’équivalent d’un pop ebp ce qui va
restaurer la valeur de EBP précedament sauvegardée. Ceci aura pour conséquence
de faire pointer ESP sur l’adresse de retour lors du ret on revient au code et
la pile n’a pas changé.
Ce qu’il faut en conclure ici: il ne faut pas empiller des valeurs sans les
retirer car à la fin de votre fonction, esp peut ne pas pointer sur l’adresse
de retour, et kaboom votre programe est mort.
Le “ret” peut prendre une operande ex: ret 8, il permet non seulement de retourner
au code comme d’enlever les parametres pushés avant le call.
(ret 8 -> 2 paramétres * 4)
- 0×0C Configurer FASM
Demarez fasmw.exe et fermez le. Il va créer un fichier FASMW.INI dans ce fichier
ajoutez ces deux lignes en prenant soin de mettre le path du dossier INCLUDE
de FASM.
[Environment] Include = c:\…\FASM\INCLUDE
- 0×0D Les APIs
Ce sont des fonctions contenues dans les fichiers DLL qui permentent aux
programmes d’interagir avec windows. Dans le programme un vous verrez que
j’en fais usage (GetCommandLineA, MessageBoxA, ExitProcess).
Je ne vais pas en parler dans ce tutoriel, ça sera pour le prochain. En
attendant si vous voullez de la documentation dessus allez voir dans la
MSDN.
- 0×0E Le premier programe:
Ce petit programe va nous permetre de revoir un peu toutes ces notions.
Tout d’abord ouvrez la source avec FASM et compillez ensuite ouvrez le avec
ollydbg et il y aura un champ d’édition pour passer les arguments au
programe entrez “-abcd” et ouvrez.
Ensuite regardez le code commenté et avec Ollydbg executez chaque instruction
pas à pas (avec F7) pour comprendre que qui se passe. En ragardant le changement
des les registres, la pile (en bas à droite), etc.
Le but n’est pas de tout vous expliquer mais que vous apreniez à comprendre
la source par vous mêmes.
Bon travail
Dans le day2 nous allons voir comment on fait un crackme.