[C] Declaratie volgorde (linux) in combinatie met GCC

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik heb een functie in C waarin ik twee lokale variabelen declareer:
C:
1
2
3
4
5
int check_authentication(char *password) {
  char password_buffer[16];
  int auth_flag = 0;
  
  strcpy(password_buffer, password); /* break here */


Bij debuggen met gdb gooi ik een breakpoint op de plek die ik heb gemarkeerd. Vervolgens vraag ik de geheugen posities op van zowel password_buffer als auth_flag:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(gdb) print password_buffer
$10 = "ABCDEF\000\000\364\237\004\bh\364\377\277"
(gdb) x/32xw password_buffer
0xbffff42c: 0x44434241  0x00004645  0x08049ff4  0xbffff468
0xbffff43c: 0x00000000  0x0026f304  0x0026eff4  0xbffff468
0xbffff44c: 0x08048555  0xbffff6a3  0x0011dd20  0x080485ab
0xbffff45c: 0x0026eff4  0x080485a0  0x00000000  0xbffff4e8
0xbffff46c: 0x00144b56  0x00000002  0xbffff514  0xbffff520
0xbffff47c: 0xb7fff858  0xbffff4d0  0xffffffff  0x0012bff4
0xbffff48c: 0x080482bc  0x00000001  0xbffff4d0  0x0011d326
0xbffff49c: 0x0012c828  0xb7fffb40  0x0026eff4  0x00000000
(gdb) print &auth_flag
$11 = (int *) 0xbffff43c
(gdb)

Zoals je kan zien wordt er eerst geheugen gereserveerd voor password_buffer (waar de tekst ABCDEF\x000 inzit) en daarna voor auth_flag (op 0xbffff43c). Op zich logisch en goed te begrijpen, dus nog niets raars hier.

Als ik nu het programma wijzig op onderstaande manier:
C:
1
2
3
4
5
int check_authentication(char *password) {
  int auth_flag = 0;
  char password_buffer[16];
  
  strcpy(password_buffer, password);

Draai ik de volgorde van variabele declaratie om: Eerst auth_flag en daarna password_buffer. Als ik dit compileer (gcc -g -fno-stack-protector -o auth_overflow2 auth_overflow2.c) en daarna gdb er weer op zet, krijg ik dit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(gdb) print &password_buffer
$2 = (char (*)[16]) 0xbffff42c
(gdb) print &auth_flag
$3 = (int *) 0xbffff43c
(gdb) x/32xw 0xbffff42c
0xbffff42c: 0x08048378  0x0011dd20  0x08049ff4  0xbffff468
0xbffff43c: 0x00000000  0x0026f304  0x0026eff4  0xbffff468
0xbffff44c: 0x08048555  0xbffff6a3  0x0011dd20  0x080485ab
0xbffff45c: 0x0026eff4  0x080485a0  0x00000000  0xbffff4e8
0xbffff46c: 0x00144b56  0x00000002  0xbffff514  0xbffff520
0xbffff47c: 0xb7fff858  0xbffff4d0  0xffffffff  0x0012bff4
0xbffff48c: 0x080482bc  0x00000001  0xbffff4d0  0x0011d326
0xbffff49c: 0x0012c828  0xb7fffb40  0x0026eff4  0x00000000
(gdb)

Het rare is dat er wederom eerst geheugen is gereserveerd voor password_buffer en daarna pas voor auth_flag. Ik wilde dat juist andersom.

Vraag: Weet iemand waarom op die manier het geheugen gereserveerd is en met name hoe ik dat kan voorkomen (compiler optie)?

Acties:
  • 0 Henk 'm!

  • Skinkie
  • Registratie: Juni 2001
  • Laatst online: 09-06-2020

Skinkie

Op naar de 500

Waarschijnlijk kiest je compiler voor alignment :P Dus kijk eens wat er gebeurt als je met -O0 compileert.

Steun Elkaar, Kopieer Nederlands Waar!


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
-O0 is standaard bij mij dus helaas, dat was hem niet. Wel aardige gedachte...
(Note: ik gebruik GCC 4.4.1 -- op 3.3.6 draait eea wel zoals verwacht.....)

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Nu online
De declaratievolgorde zegt niets over de locatie waar variabelen in het geheugen geplaatst worden. Het staat de C-compiler vrij om die variabelen om te wisselen als 'ie denkt dat dat beter is. Waarschijnlijk heeft het niets met alignment te maken, want het gebeurt net zo goed zonder optimalisaties. Ik denk dat de compiler gewoon alle declaraties op één hoop gooit en ze daarna ordent zoals het uitkomt, wat volledig legaaal is. Je kunt er dus niet vanuit gaan dat ze op de ene of de andere locatie komen.
Vraag: Weet iemand waarom op die manier het geheugen gereserveerd is en met name hoe ik dat kan voorkomen (compiler optie)?
Een compileroptie ken ik niet, maar je zou de twee variabelen in één struct kunnen stoppen; de velden daarvan worden in de volgorde waarin ze gedeclareerd zijn in het geheugen geplaatst.

Maar een betere vraag is: waarom wil je dit eigenlijk?

Acties:
  • 0 Henk 'm!

  • MikeN
  • Registratie: April 2001
  • Laatst online: 18:48
http://stackoverflow.com/...e-allocation-on-the-stack geeft 'het probleem' ook weer. Uiteindelijk is het aan GCC in welke volgorde hij de lokale vars op de stack gooit, en kun je als programmeur nergens op vertrouwen. Het enige waarop je kunt vertrouwen is wat in de standaarden is vastgelegd, dus alles in een struct gooien (staat ook op de link uitgelegd).

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Goede antwoorden, daar kan ik wat mee. Ik ga met de struct optie spelen.

De reden waarom ik dit wil is een boek wat ik aan het lezen ben over o.a. buffer overflow. Als in het geheugen eerst ruimte voor password_buffer wordt gereserveerd en dan pas voor auth_flag dan genereer ik een overflow van password_buffer --> auth_flag.

Leuke experimenten en de auteur van het boek gebruikt Ubuntu 8 met GCC 3.3.6 en daar werkt het schijnbaar wel op de manier die ik beschrijf (volgorde van declaratie = volgorde van geheugen reservering)

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Snap je wat je -fno-stack-protector flag doet?

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik denk het ja :)
Zonder -fno-stack-protector kan ik m'n variabelen niet overloaden.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Overloaden ? Dat kan in C++ met functies. Niet met variabelen, en niet met C.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1