--- title: "Sécurité logicielle : L'assembleur - approfondissement" date: 2023-02-01 tags: ["assembleur", "intel"] categories: ["Sécurité logicielle", "Cours"] --- ## Un premier exemple Prenons `IP` comme compteur et `A` , `B`, `C` et `D` comme registres. ```asm {linenos=true} 0x00: mov $1, A 0x05: mov $2, B 0x0a: mov $3, C 0x0f: add A, B 0x10: cmp B, C 0x11: jz zero 0x12: mov $41, A 0x17: jmp end 0x18: zero: 0x18: mov $42, A 0x1d: end: ``` La première colonne représente le compteur d'instruction, nous pouvons vois que chaque *instruction prend 5 octets*. Ligne 4, la seconde opérande de l'instruction `add` est aussi le résultat Ligne 5, l'instruction `cmp` fait une comparaison, en fait il fait une soustraction des deux opérandes. Si le résultat de cette sourtraction (et dons que les opérandes sont égales) alors l'instruction `jz` (*jump zero*) réalisera un saut vers l'étiquette `zero`. ## Le langage ### Les registres Il étaient de 8 bits à l'origine et nommés `A`, `B`, `C` et `D`, lors du passage en 16 bits, ils se sont appelés `Ax`, `Bx`, `Cx`, `Dx` (pour *extended*). Lors du passage à 32 bits ils sont passé à `eAx`, `eBx`, `eCx`et `'eDx`. Enfin ils sont passé à `rAx`, `rBx`, `rCx` et `rDx` pour la version 64 bits. Lors de ce cours, nous utiliseront principalement les versions 32 bits. ### Les suffixes d'instructions Toute comme pour les registres, il existe des version de certaines instructins en fonction de la taille des opérandes : * `movb` : 8bits * `movb` : 16 bits * `movl` : 32 bits * `movq` : 64 bits ### Les usages Il existe plusieurs type de registres en fonction de leur usage * registres **généraux** : `rAx`, `rBx`, ... * registres **d'indexation** : `RSI` (source) et `RDI` (destination) * registres supplémentaire 64 bits : de `R8` à `R15` Nous en verrons d''autre un peu plus tard. ### Flags de résultats C'est un registre de 32 bits, chaque bit correspond à un drapeau spécifique : Les 16 premier bits repente les *flags* : position | flag | fonction ---------|------|---------- 0 | CF | Carry flag 2 | PF | Parity flag 4 | AF | Adjust flag 6 | ZF | Zero flag (si le résultat est 0) 7 | SF | Sign flag (valeur de bit de poids fort) 8 | TF | Trap flag 9 | IF | Interrupt enable flag 10 | DF | Direction flag (sens de lecture d'une chaine de caractère) 11 | OF | Overflow flag (positionné en cas d'overflow) 12 13| IOPL | IO privilege number 14 | NT | Nested tag flag Et les 16 suivants les *eflags*: position | flag | fonction ---------|------|---------- 16 | RF | Resume flag (Défini la réponse CPU pour la reprise à l'exception pour debug) 17 | VM | Virtual 8086 mode 18 | AC | Alignement check 19 | VIF | Virtual interrupt flag 20 | ID | CPUID flag (possibilité d'utiliser le CPUID) 21-31 | Réservé ### Les instructions #### Addition / soustraction / incrémentation / décrémentation * `add ` : addition de `` et ``, positionnement du résultat dans `` * `sub ` : soustraction de `` et ``, positionnement du résultat dans `` * `inc ` : incrémenter `` * `dec ` : décrémenter `` * `neg ` : renvoie le complément à deux de `` ```asm movl $20 %rax # rax = 15 addl $10 %rax # rax = rax + 10 = 25 subl $7 %rax # rax = rax - 7 = 18 incl %rax # rax += 1 = 19 decl %rax # rax -= 1 = 19 ``` #### Division / Multiplication * `mul ` : multiplication de `%eax` par ``, `%eax` est choisi en dur, le résultat est écrit sur deux registres `%edx` et `%eax`. `mul` retroune un résultat **non signé**. * `imul` : multiplication comme précédement, mais le résultat est cette fois **signé** * `div ` : divise le nombre contenu dans `%eax` et `%edx` par ``. Le quotien sera positionné dans `%eax` et le reste dans `%edx`. Le résultat est **non signé**. * `idiv ` : division comme précédement mais cette fois le résultat est **signé**. ```asm movl $0 %edx movl $8 %eax movl $2 %ebx divl %ebx # %eax = %edx.%eax / %ebx remainer : %edx movl $0 %edx movl $8 %eax movl $2 %ebx mull %ebx # %eax = %ebx * %eax ``` #### Shift, rotate On parle ici de décalage de bits que se soir à gauche (multilication par 2 puissance X) ou à droite (division par 2 puissance X). * `shl ` : décalage à gauche de `` de `` bits (` << n`). * `shr ` : décalage à droite de `` de `` bits (` >> n`). Ces deux instructions sont **non signées**, les versions **signées** sont `sal` et `sar`. * `sol ` : applique une rotation de `n` bits vers la gauche de `` * `sor ` : applique une rotation de `n` bits vers la droite de `` ```asm movl $0xa %eax rol $0x2 %eax # 00001010 -> 00101000 = 0x28 ``` #### Opération bit à bit * `and ` : réalisation de l'opération ` & `, positionnement de résultat dans `` * `or ` : réalisation de l'opėration ` | `, positinnement du résultat dans `` * `xor ` : réalisation de l'opėration ` ^ `, positinnement du résultat dans `` * `not ` : réalisation de l'opération `<~dst>` et poitionnement du résultat dans `` * `cmp <1> <2>` : réalisation de l'opération `<1> - <2>`, le résultat n'est pas affecté mais les drapeaux OF, ZF AF, CF PF son positionné en fonction du résultat. #### Instruction de branchement Certaines de ces instructions on plusieurs notations possibles. * `jmp ` : saut vers l'adresse `` sans condition * `ja ` : saut vers l'adresse `` si la comparaison au dessus donne comme résultat *strictement supérieur à* * `jae ` : saut vers l'adresse `` si la comparaison au dessus donne comme résultat *supérieur ou égal à* * `jnae ` : saut vers l'adresse `` si la comparaison au dessus donne comme résultat *strictement inférieur à* (not above or equal) -- peut être aussi `jng` (not greater) * `jz ` : saut vers l'adresse `` si la comparaison au dessus donne comme résultat *égal à* #### Instruction diverses * `loop `: décrémente `%ecx` et effectue un saut vers `` si `%ecx` et supérieur à 0. * `loope `: décrémente `%ecx` et effectue un saut vers `` si `%ecx` et supérieur à 0 et `ZF` = 1. Peut aussi être nommé `loopz` * `loopne `: décrémente `%ecx` et effectue un saut vers `` si `%ecx` et supérieur à 0 et `ZF` = 0. Peut aussi être nommé `loopnz` * `noop`: ne fait rien... ### Gestion de la Mémoire Nous avons différents types d'opérandes pour la mémoire. que se soit sur les registres : ```asm # affecter le contenu de %eax dans %ebx movl %eax %ebx ``` Pour les immediats: ```asm # Affecter 1 à %ebx movl $1 %ebx # Affecter 0xa à %ebx movl $0xa %ebx # Affecter l'adresse `a` à %ebx movl $a %ebx ``` Et pour l'acces direct à la mémoire ```asm # Erreur !! movl a %ebx # Référence à l'adresse `a` movl $a %ebx ``` Et enfin les accès indirects à la mémoire. Le principe ici est base + index * type + déplacement. Si le type est omit alors il vaut 1 si le déplacement est omis il vaut 0. Concrètement l'adresse est organisée comme suit: `(, , )` ```asm # Copie le contenu de la case mémoire pointé par le contenu de %ebx dans %eax movl (%ebx) %eax # Copie le contenu à l'adresse %ebx + 4 octets dans %eax movl 4(%ebx) %eax # Cette fois c'est le contenu à l'adresse %ebx - 4 movl -4(%ebx) %eax # le contenu à l'adresse %ecx + %ebx movl (%ebx, %ecx) %eax # contenu à l'adresse %ebx +t movl t(%ebx) %eax # contenu à l'adresse t + %ebx + %ecx * 4 movl t(%ebx, %ecx, 4) %eax ``` #### Move, xchg, lea Ces instructions servent à copier une valeur d'un endroit (registre, mémoire ) à un autre. * `movl ` : copie le contenu de `` vers ``, `` peut être une constante, un registre ou un adresse (label) et `` une adresse ou un registre. * `xchg ` : ;echange le contenu de `` et de `` * `leal ` : calcule l'adresse source (``) et place le résultat dans ``. Contrairement à `movl`, `leal` ne traite pas la valeur mais bien **l'adresse** Il est possible d'utiliser `leal` pour effectuer des calculs arithmétiques non signé. Ainsi on peut bénéficier d'un avantage : **les drapeaux ne sont pas impactés**. * `cmov `: copie `` vers `` en fonction de l'instruction de comparaison précédente et de l'instruction donnée par ``. ```asm cmpl %eax %ebx # %ebx - %eax cmovgel $1 %edx # si %ebx > ebx (res > 0) alors %edx = 1 ```