Add TD8
This commit is contained in:
parent
7c934bcefb
commit
453d88282f
8 changed files with 588 additions and 0 deletions
27
content/secu_logicielle/td8-gdb/files/Makefile
Normal file
27
content/secu_logicielle/td8-gdb/files/Makefile
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
CFLAGS=-g -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-array-bounds -Wno-stringop-overflow -m32 -no-pie -fno-pie
|
||||||
|
LDFLAGS=-m32
|
||||||
|
LDLIBS=-lpthread
|
||||||
|
C=$(wildcard *.c)
|
||||||
|
O=$(C:.c=)
|
||||||
|
O2=$(C:.c=.O2)
|
||||||
|
|
||||||
|
pframe:
|
||||||
|
curl -o pframe.tgz https://dept-info.labri.fr/~thibault/SecuLog/pframe.tgz && \
|
||||||
|
tar -xf pframe.tgz &&\
|
||||||
|
rm -rf pframe.tgz
|
||||||
|
|
||||||
|
.gdbinit:
|
||||||
|
|
||||||
|
configure: pframe .gdbinit
|
||||||
|
$(shell echo "python import pframe" > .gdbinit)
|
||||||
|
%.O2: %.c
|
||||||
|
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -O2 $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
all: $O $(O2)
|
||||||
|
|
||||||
|
PHONY: gdb_%
|
||||||
|
gdb_%: $(subst gdb_,,%)
|
||||||
|
PYTHONPATH=${PWD}/pframe${PYTHONPATH:+:${PYTHONPATH}} gdb $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $O $(O2)
|
21
content/secu_logicielle/td8-gdb/files/modif-rev.c
Normal file
21
content/secu_logicielle/td8-gdb/files/modif-rev.c
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void f(int *x) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 10000; i++)
|
||||||
|
(*x)++;
|
||||||
|
(*x) *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void g(int *y) {
|
||||||
|
return f(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int b = 0;
|
||||||
|
int a = 0;
|
||||||
|
int c = 0;
|
||||||
|
g(&a);
|
||||||
|
printf("%d\n", a);
|
||||||
|
return 0;
|
||||||
|
}
|
18
content/secu_logicielle/td8-gdb/files/modif.c
Normal file
18
content/secu_logicielle/td8-gdb/files/modif.c
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void f(int *x) {
|
||||||
|
(*x)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void g(int *y) {
|
||||||
|
return f(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int b = 1;
|
||||||
|
int a = 2;
|
||||||
|
int c = 3;
|
||||||
|
g(&a);
|
||||||
|
printf("%d\n", a);
|
||||||
|
return 0;
|
||||||
|
}
|
19
content/secu_logicielle/td8-gdb/files/modif2.c
Normal file
19
content/secu_logicielle/td8-gdb/files/modif2.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void f(char *x, int n) {
|
||||||
|
memset(x, '\0', n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void g(char *y, int n) {
|
||||||
|
return f(y, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
int b = 1234567890;
|
||||||
|
int c = 1234567890;
|
||||||
|
char a[] = "Hello, you!";
|
||||||
|
g(a, sizeof(a) + 1);
|
||||||
|
printf("%p:%d %p:%d %p\n", &b, b, &c, c, &a);
|
||||||
|
return 0;
|
||||||
|
}
|
19
content/secu_logicielle/td8-gdb/files/modif3.c
Normal file
19
content/secu_logicielle/td8-gdb/files/modif3.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void f(char *x, int n) {
|
||||||
|
memset(x, '\0', n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void g(char *y, int n) {
|
||||||
|
return f(y, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
char *a = strdup("aaa");
|
||||||
|
g(a, sizeof(a)+1);
|
||||||
|
printf("%p\n", &a);
|
||||||
|
free(a);
|
||||||
|
return 0;
|
||||||
|
}
|
17
content/secu_logicielle/td8-gdb/files/optim.c
Normal file
17
content/secu_logicielle/td8-gdb/files/optim.c
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int __attribute__((noinline)) f(int x) {
|
||||||
|
return x+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __attribute__((noinline)) g(int y) {
|
||||||
|
int z = y+1;
|
||||||
|
int a = f(z);
|
||||||
|
printf("%d\n", a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("%d\n", g(1));
|
||||||
|
return 0;
|
||||||
|
}
|
15
content/secu_logicielle/td8-gdb/files/stack.c
Normal file
15
content/secu_logicielle/td8-gdb/files/stack.c
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int f(int *x) {
|
||||||
|
return *x+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int g(int y) {
|
||||||
|
int z = y+1;
|
||||||
|
return f(&z);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("%d\n", g(1));
|
||||||
|
return 0;
|
||||||
|
}
|
452
content/secu_logicielle/td8-gdb/index.md
Normal file
452
content/secu_logicielle/td8-gdb/index.md
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
---
|
||||||
|
title: "Sécurité logicielle : TD8 Utiliser GDB"
|
||||||
|
date: 2023-04-07
|
||||||
|
author:
|
||||||
|
- Yorick Barbanneau
|
||||||
|
- Gwendal Aupee
|
||||||
|
tags: ["gdb", "x86", "debug"]
|
||||||
|
categories: ["Sécurité logicielle", "TD"]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Partie 1
|
||||||
|
|
||||||
|
Commençons par récupérer l'ensemble des éléments de `x` à savoir
|
||||||
|
|
||||||
|
* son contenu (une adresse)
|
||||||
|
* le contenu pointé cette adresse
|
||||||
|
* son adresse
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p x
|
||||||
|
$1 = (int *) 0xffffd690
|
||||||
|
(gdb) p *x
|
||||||
|
$2 = 2
|
||||||
|
(gdb) p &x
|
||||||
|
$3 = (int **) 0xffffd680
|
||||||
|
```
|
||||||
|
|
||||||
|
Regardons maintenant le contenu de la pile et retrouvons les différents
|
||||||
|
élements:
|
||||||
|
|
||||||
|
```
|
||||||
|
0xffffd6b8 0xf7ffcff4
|
||||||
|
0xffffd6b4 0x00000070
|
||||||
|
0xffffd6b0 0x00000000
|
||||||
|
0xffffd6ac 0xf7c23295
|
||||||
|
0xffffd6a8 0x00000000
|
||||||
|
0xffffd6a4 0xffffd6c0
|
||||||
|
0xffffd6a0 0x00000001
|
||||||
|
0xffffd69c 0x00000001
|
||||||
|
0xffffd698 0x08049198
|
||||||
|
0xffffd694 0xffffd6a8
|
||||||
|
0xffffd690 0x00000002 <- La valeur de x (son adresse sur la pile)
|
||||||
|
0xffffd68c ... 0xf7fc14a0
|
||||||
|
0xffffd688 arg3 0xf7c1ca2f
|
||||||
|
0xffffd684 arg2 0xf7fd98cb
|
||||||
|
0xffffd680 arg1 0xffffd690 <- L'adresse de x (&x)
|
||||||
|
0xffffd67c ret@ 0x0804917b
|
||||||
|
0xffffd678 bp sp 0xffffd694
|
||||||
|
```
|
||||||
|
|
||||||
|
La *backtrace* de `f()`:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) bt
|
||||||
|
#0 f (x=0xffffd690) at stack.c:4
|
||||||
|
#1 0x0804917b in g (y=1) at stack.c:9
|
||||||
|
#2 0x08049198 in main () at stack.c:13
|
||||||
|
```
|
||||||
|
|
||||||
|
Adresse de retour dans pframe:
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
0xffffd680 arg1 0xffffd690
|
||||||
|
0xffffd67c ret@ 0x0804917b <- adresse de retour de f() (vers g())
|
||||||
|
0xffffd678 bp sp 0xffffd694
|
||||||
|
```
|
||||||
|
|
||||||
|
Après un `up`, voici les adresses demandées:
|
||||||
|
|
||||||
|
```
|
||||||
|
Breakpoint 1, f (x=0xffffd690) at stack.c:4
|
||||||
|
4 return *x+1;
|
||||||
|
(gdb) up
|
||||||
|
#1 0x0804917b in g (y=1) at stack.c:9
|
||||||
|
9 return f(&z);
|
||||||
|
(gdb) p y
|
||||||
|
$1 = 1
|
||||||
|
(gdb) p&y
|
||||||
|
$2 = (int *) 0xffffd69c
|
||||||
|
(gdb) p z
|
||||||
|
$3 = 2
|
||||||
|
(gdb) p &z
|
||||||
|
$4 = (int *) 0xffffd690
|
||||||
|
(gdb)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Partie 2
|
||||||
|
|
||||||
|
Lançons `gdb` sur optim.02 et posons notre point d'arrêt sur `f()`
|
||||||
|
|
||||||
|
```
|
||||||
|
Breakpoint 1, f (x=2) at optim.c:4
|
||||||
|
4 return x+1;
|
||||||
|
(gdb) bt
|
||||||
|
#0 f (x=2) at optim.c:4
|
||||||
|
#1 0x080491c1 in g (y=1) at optim.c:9
|
||||||
|
#2 0x08049068 in main () at optim.c:15
|
||||||
|
(gdb) up
|
||||||
|
#1 0x080491c1 in g (y=1) at optim.c:9
|
||||||
|
9 int a = f(z);
|
||||||
|
(gdb) p z
|
||||||
|
$1 = 2
|
||||||
|
(gdb) p &z
|
||||||
|
Can't take address of "z" which isn't an lvalue.
|
||||||
|
(gdb)
|
||||||
|
```
|
||||||
|
Effectivement `gdb` ne peut nous afficher la valeur.
|
||||||
|
|
||||||
|
Après avoir désassemblé la fonction `g()`, nous pouvons effectivement voir que
|
||||||
|
`z` n'existe pas en tant que tel: il **est directement mis sur la pile**.
|
||||||
|
|
||||||
|
```
|
||||||
|
0x080491b4 <+4>: mov 0x10(%esp),%eax
|
||||||
|
0x080491b8 <+8>: add $0x1,%eax <- z
|
||||||
|
0x080491bb <+11>: push %eax
|
||||||
|
```
|
||||||
|
|
||||||
|
Lorsqu'on essaye d'afficher `a`, *gdb* nous affiche que cette variable a été
|
||||||
|
optimisée
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p a
|
||||||
|
$2 = <optimized out>
|
||||||
|
```
|
||||||
|
|
||||||
|
En observant le code assembleur, ici encore la variable `a` n'existe que sur la
|
||||||
|
pile dans `%eax`. Le programme passe ensuite `%eax` dans `%ebx` pour le passer à
|
||||||
|
la fonction `printf`
|
||||||
|
|
||||||
|
```
|
||||||
|
...
|
||||||
|
0x080491c5 <+21>: mov %eax,%ebx
|
||||||
|
0x080491c7 <+23>: push $0x804a008
|
||||||
|
0x080491cc <+28>: call 0x8049040 <printf@plt>
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans la version optimisée du programme, le compilateur a donc réduit au maximum
|
||||||
|
la création de variables.
|
||||||
|
|
||||||
|
La *backtrace* complète, `a` est aussi `<optimized out>` :
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) bt full
|
||||||
|
#0 f (x=2) at optim.c:4
|
||||||
|
No locals.
|
||||||
|
#1 0x080491c1 in g (y=1) at optim.c:9
|
||||||
|
z = 2
|
||||||
|
a = <optimized out>
|
||||||
|
#2 0x08049068 in main () at optim.c:15
|
||||||
|
```
|
||||||
|
|
||||||
|
### Partie 3
|
||||||
|
|
||||||
|
Nous lançons puis plaçons un point d'arrêt sur `main()`:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) b main
|
||||||
|
Breakpoint 1 at 0x804918a: file modif.c, line 12.
|
||||||
|
(gdb) r
|
||||||
|
Breakpoint 1, main () at modif.c:12
|
||||||
|
12 int b = 1;
|
||||||
|
(gdb) wa a
|
||||||
|
Watchpoint 2: a
|
||||||
|
```
|
||||||
|
|
||||||
|
Après avoir continué l'exécution de notre programme, `gdb` s'arrête lors de la
|
||||||
|
modification de `a`:
|
||||||
|
|
||||||
|
```
|
||||||
|
[...]
|
||||||
|
(gdb) c
|
||||||
|
Continuing.
|
||||||
|
Watchpoint 2: a
|
||||||
|
Old value = -134474120
|
||||||
|
New value = 2
|
||||||
|
main () at modif.c:14
|
||||||
|
14 int c = 3;
|
||||||
|
```
|
||||||
|
|
||||||
|
Nous pouvons maintenant afficher `%eip` et désassembler:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p $eip
|
||||||
|
$2 = (void (*)()) 0x8049198 <main+31>
|
||||||
|
(gdb) disassemble
|
||||||
|
Dump of assembler code for function main:
|
||||||
|
0x08049179 <+0>: lea 0x4(%esp),%ecx
|
||||||
|
0x0804917d <+4>: and $0xfffffff0,%esp
|
||||||
|
0x08049180 <+7>: push -0x4(%ecx)
|
||||||
|
0x08049183 <+10>: push %ebp
|
||||||
|
0x08049184 <+11>: mov %esp,%ebp
|
||||||
|
0x08049186 <+13>: push %ecx
|
||||||
|
0x08049187 <+14>: sub $0x14,%esp
|
||||||
|
0x0804918a <+17>: movl $0x1,-0xc(%ebp)
|
||||||
|
0x08049191 <+24>: movl $0x2,-0x14(%ebp) <- initialisation de a
|
||||||
|
=> 0x08049198 <+31>: movl $0x3,-0x10(%ebp) <- %eip
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
On peut demander à gdb de calculer l'adresse de `%ebp -14` et de la comparer
|
||||||
|
avec l'adresse de `a`:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) p $ebp - 0x14
|
||||||
|
$8 = (void *) 0xffffd694
|
||||||
|
(gdb) p &a
|
||||||
|
$9 = (int *) 0xffffd694
|
||||||
|
```
|
||||||
|
|
||||||
|
Demandons à `gdb` de nous afficher le contenu de cette case mémoire:
|
||||||
|
|
||||||
|
```
|
||||||
|
#0 main () at modif.c:14
|
||||||
|
(gdb) p/x *(int*)($ebp - 0x14)
|
||||||
|
$8 = 0x2
|
||||||
|
```
|
||||||
|
|
||||||
|
Continuons maintenant l'exécution
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) c
|
||||||
|
Continuing.
|
||||||
|
|
||||||
|
Watchpoint 2: a
|
||||||
|
|
||||||
|
Old value = 2
|
||||||
|
New value = 3
|
||||||
|
f (x=0xffffd694) at modif.c:5
|
||||||
|
```
|
||||||
|
|
||||||
|
On peu observer l'incrémentation de `a` dans la fonction `f()`:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) disassemble
|
||||||
|
Dump of assembler code for function f:
|
||||||
|
0x08049156 <+0>: push %ebp
|
||||||
|
0x08049157 <+1>: mov %esp,%ebp
|
||||||
|
0x08049159 <+3>: mov 0x8(%ebp),%eax
|
||||||
|
0x0804915c <+6>: mov (%eax),%eax
|
||||||
|
0x0804915e <+8>: lea 0x1(%eax),%edx <-incrémentation de a
|
||||||
|
0x08049161 <+11>: mov 0x8(%ebp),%eax
|
||||||
|
0x08049164 <+14>: mov %edx,(%eax) <- a est placé dans %eax
|
||||||
|
=> 0x08049166 <+16>: nop
|
||||||
|
0x08049167 <+17>: pop %ebp
|
||||||
|
0x08049168 <+18>: ret
|
||||||
|
End of assembler dump.
|
||||||
|
```
|
||||||
|
|
||||||
|
La variable `a` est incrémentée en utilisant `lea`, le résultat de cette
|
||||||
|
opération est placé dans `%ebx` avant d'être positionnée dans `%eax`. C'est ce
|
||||||
|
qui cause l'arrêt de *gdb*.
|
||||||
|
|
||||||
|
Après avoir relancé le programme, nous obtenons l'adresse de `a`:
|
||||||
|
|
||||||
|
```
|
||||||
|
Breakpoint 1, main () at modif.c:12
|
||||||
|
12 int b = 1;
|
||||||
|
(gdb) p &a
|
||||||
|
$1 = (int *) 0xffffd694
|
||||||
|
```
|
||||||
|
|
||||||
|
Effectivement en positionnant un `watch` sur l'adresse de `a`, on obtient le
|
||||||
|
même comportement:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) wa *(int *)0xffffd694
|
||||||
|
Hardware watchpoint 2: *(int *)0xffffd694
|
||||||
|
(gdb) c
|
||||||
|
Continuing.
|
||||||
|
Hardware watchpoint 2: *(int *)0xffffd694
|
||||||
|
Old value = -134474120
|
||||||
|
New value = 2
|
||||||
|
main () at modif.c:14
|
||||||
|
14 int c = 3;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Partie 4
|
||||||
|
|
||||||
|
|
||||||
|
Exécution du programme `modif2`:
|
||||||
|
|
||||||
|
```
|
||||||
|
./modif2
|
||||||
|
0xffe7d18c:1234567890 0xffe7d188:1234567680 0xffe7d17c
|
||||||
|
```
|
||||||
|
|
||||||
|
On voit bien que le second entier est différent du premier. Exécutons le
|
||||||
|
programme avec `gdb` en posant un *watchpoint* sur les deux entiers. Pour ce
|
||||||
|
faire nous allons poser un *breackpoint* sur `main()`, exécuter pas à pas pour
|
||||||
|
repérer l'initialisation des deux entiers et poser nos *watchpoint* dessus:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) b main
|
||||||
|
Breakpoint 1 at 0x80491ad: file modif2.c, line 13.
|
||||||
|
(gdb) r
|
||||||
|
[...]
|
||||||
|
13 int b = 1234567890;
|
||||||
|
(gdb) n
|
||||||
|
14 int c = 1234567890;
|
||||||
|
(gdb) wa b
|
||||||
|
Hardware watchpoint 2: b
|
||||||
|
(gdb) wa c
|
||||||
|
Hardware watchpoint 3: c
|
||||||
|
```
|
||||||
|
|
||||||
|
Nous voyons biens que ces entiers ont été initialisée avec *1234567890*.
|
||||||
|
Continuons l'exécution du programme, nous pouvons alors voir que la variable `c`
|
||||||
|
est modifiée dans `memset-sse2.S` :
|
||||||
|
|
||||||
|
```
|
||||||
|
[...]
|
||||||
|
Old value = 1234567890
|
||||||
|
New value = 1234567680
|
||||||
|
__memset_sse2_rep () at ../sysdeps/i386/i686/multiarch/memset-sse2-rep.S:173
|
||||||
|
```
|
||||||
|
|
||||||
|
En désassemblant,, nous pouvons effectivement voir que nous sommes au beau
|
||||||
|
milieu de la fonction `memset`:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) disass
|
||||||
|
Dump of assembler code for function __memset_sse2_rep:
|
||||||
|
[...]
|
||||||
|
0xf7d779fc <+108>: mov %eax,-0xd(%edx)
|
||||||
|
0xf7d779ff <+111>: mov %eax,-0x9(%edx)
|
||||||
|
0xf7d77a02 <+114>: mov %eax,-0x5(%edx)
|
||||||
|
0xf7d77a05 <+117>: mov %al,-0x1(%edx)
|
||||||
|
=> 0xf7d77a08 <+120>: mov 0x8(%esp),%eax
|
||||||
|
0xf7d77a0c <+124>: pop %ebx
|
||||||
|
0xf7d77a0d <+125>: ret
|
||||||
|
[...]
|
||||||
|
End of assembler dump.
|
||||||
|
```
|
||||||
|
Maintenant remontons dans la fonction appelante:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) up
|
||||||
|
#1 0x0804917d in f (x=0xffffd67c "", n=13) at modif2.c:5
|
||||||
|
5 <c code that we don't see>
|
||||||
|
(gdb) disassemble
|
||||||
|
Dump of assembler code for function f:
|
||||||
|
0x08049166 <+0>: push %ebp
|
||||||
|
0x08049167 <+1>: mov %esp,%ebp
|
||||||
|
0x08049169 <+3>: sub $0x8,%esp
|
||||||
|
0x0804916c <+6>: mov 0xc(%ebp),%eax
|
||||||
|
0x0804916f <+9>: sub $0x4,%esp
|
||||||
|
0x08049172 <+12>: push %eax
|
||||||
|
0x08049173 <+13>: push $0x0
|
||||||
|
0x08049175 <+15>: push 0x8(%ebp)
|
||||||
|
0x08049178 <+18>: call 0x8049050 <memset@plt>
|
||||||
|
=> 0x0804917d <+23>: add $0x10,%esp
|
||||||
|
0x08049180 <+26>: nop
|
||||||
|
0x08049181 <+27>: leave
|
||||||
|
0x08049182 <+28>: ret
|
||||||
|
End of assembler dump.
|
||||||
|
```
|
||||||
|
|
||||||
|
Nous allons maintenant relancer notre exécution en posant un point d'arrêt sur
|
||||||
|
l'adresse `0x08049178`.
|
||||||
|
|
||||||
|
Lançons maintenant notre exécution:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) b * 0x08049178
|
||||||
|
Breakpoint 1 at 0x8049178: file modif2.c, line 5.
|
||||||
|
(gdb) r
|
||||||
|
[...]
|
||||||
|
Breakpoint 1, 0x08049178 in f (x=0xffffd67c "Hello, you!", n=13) at modif2.c:5
|
||||||
|
(gdb) p &x[0]
|
||||||
|
$3 = 0xffffd67c "Hello, you!"
|
||||||
|
(gdb) up
|
||||||
|
(gdb) up
|
||||||
|
(gdb) p &c
|
||||||
|
$5 = (int *) 0xffffd688
|
||||||
|
(gdb) p &b
|
||||||
|
$6 = (int *) 0xffffd68c
|
||||||
|
```
|
||||||
|
|
||||||
|
Maintenant que nous avons les adresses, intéressons nous à la fonction `memset`.
|
||||||
|
Sa signature est `memset(void s, int c, size_t n)`, elle remplie `n` élément de
|
||||||
|
la zone mémoire `s` avec `c`.
|
||||||
|
|
||||||
|
D'après `gdb`, voici l'appel de cette fonction dans `f()` :
|
||||||
|
`memset(x, '\0', n);` où `x` est un pointeur vers `a` et `n` est égal à *13*.
|
||||||
|
|
||||||
|
Adresse | Variable | Memset
|
||||||
|
---------|:--------:|--------
|
||||||
|
... | ... | ...
|
||||||
|
0xffffd68c | b |
|
||||||
|
0xffffd68b | c |
|
||||||
|
0xffffd68a | c |
|
||||||
|
0xffffd689 | c |
|
||||||
|
0xffffd688 | c | memset[12]
|
||||||
|
0xffffd687 | a[11] | memset[11]
|
||||||
|
0xffffd686 | a[10] | memset[10]
|
||||||
|
... | ... | ...
|
||||||
|
0xffffd67e | a[2] | memset[2]
|
||||||
|
0xffffd67d | a[1] | memset[1]
|
||||||
|
0xffffd67c | a[0] | memset[0]
|
||||||
|
|
||||||
|
Comme nous pouvons le voir sur le tableau, le `memset` écrase le **bit de poids
|
||||||
|
faible** de notre variable `c`. Nous avons la cause de sa modification!
|
||||||
|
|
||||||
|
Le calcul est simple : adresse de `a` + 12 bits = `0xfffd67c + 0xc = 0xfffd688`,
|
||||||
|
notre `memset` empiète bien sur `c`.
|
||||||
|
|
||||||
|
Le bug est simple le développeur a ajouter un à `sizeof(a)` surement pour
|
||||||
|
prendre en compte le caractère `/0`, or cette opération est effectuée dès
|
||||||
|
l'initialisation de notre constante :
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) frame 2
|
||||||
|
|
||||||
|
#2 0x080491de in main () at modif2.c:16
|
||||||
|
16 g(a, sizeof(a) + 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Partie 5
|
||||||
|
|
||||||
|
Effectivement, lors de l'exécution du programme avec *Valgring*, celui-ci
|
||||||
|
reporte une erreur:
|
||||||
|
|
||||||
|
```
|
||||||
|
[...]
|
||||||
|
==4666== Invalid write of size 1
|
||||||
|
==4666== at 0x4049FF0: memset (in /usr/libexec/valgrind/vgpreload_memcheck-x86-linux.so)
|
||||||
|
==4666== by 0x804919C: f (modif3.c:6)
|
||||||
|
==4666== by 0x80491B6: g (modif3.c:10)
|
||||||
|
==4666== by 0x80491ED: main (modif3.c:15)
|
||||||
|
==4666== Address 0x428a02c is 0 bytes after a block of size 4 alloc'd
|
||||||
|
==4666== at 0x4040660: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-x86-linux.so)
|
||||||
|
==4666== by 0x4101315: strdup (strdup.c:42)
|
||||||
|
==4666== by 0x80491D9: main (modif3.c:14)
|
||||||
|
[...]
|
||||||
|
```
|
||||||
|
Après avoir lancé *Valgrind* avec le paramètre `--vgdb-error=1` et lancé gdb
|
||||||
|
avec `target remote | /usr/bin/vgdb --pid=<pid>`, nous pouvons observer la même
|
||||||
|
erreur que pour la partie précédente:
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) bt
|
||||||
|
#0 0x04049ff0 in _vgr20210ZZ_libcZdsoZa_memset () from /usr/libexec/valgrind/vgpreload_memcheck-x86-linux.so
|
||||||
|
#1 0x0804919d in f (x=0x428a028 "", n=5) at modif3.c:6
|
||||||
|
#2 0x080491b7 in g (y=0x428a028 "", n=5) at modif3.c:10
|
||||||
|
#3 0x080491ee in main () at modif3.c:15
|
||||||
|
(gdb) frame 3
|
||||||
|
#3 0x080491ee in main () at modif3.c:15
|
||||||
|
15 g(a, sizeof(a)+1);
|
||||||
|
```
|
||||||
|
|
||||||
|
Un a été ajouté à `sizeof(a)` **alors qu'il ne faut pas**.
|
Loading…
Add table
Add a link
Reference in a new issue