Toon posts:

[ASM] c for loop vraag

Pagina: 1
Acties:

Verwijderd

Topicstarter
ik heb in c een simpele for loop geschreven en deze gedissambled

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
00401288  /$ 55             PUSH EBP                ; sla base pointer op in stack
00401289  |. 89E5           MOV EBP,ESP             ; sla stack pointer op in base pointer
0040128B  |. 83EC 08        SUB ESP,8               ; ESP = ESP - 8
0040128E  |. 83E4 F0        AND ESP,FFFFFFF0            ; ESP = ESP && FFFFFFF0
00401291  |. B8 00000000    MOV EAX,0               ; initialiseer variable op 0
00401296  |. 8945 F8        MOV DWORD PTR SS:[EBP-8],EAX    ; sla EAX(= 0) op 
00401299  |. 8B45 F8        MOV EAX,DWORD PTR SS:[EBP-8]    ; EAX = 0
0040129C  |. E8 CF160000    CALL for_loop.00402970
004012A1  |. E8 0A010000    CALL for_loop.004013B0
004012A6  |. C745 FC 000000>MOV DWORD PTR SS:[EBP-4],0      ; DWORD PTR SS:[EBP-4] = 0
004012AD  |> 837D FC 0A     /CMP DWORD PTR SS:[EBP-4],0A    ; vergelijk met 10
004012B1  |. 7E 02          |JLE SHORT for_loop.004012B5    ; if < 10 ga naar 004012B5
004012B3  |. EB 1A          |JMP SHORT for_loop.004012CF    ; einde for loop
004012B5  |> 83EC 08        |SUB ESP,8              ; ESP = ESP - 8
004012B8  |. FF75 FC        |PUSH DWORD PTR SS:[EBP-4]          ; sla variable op
004012BB  |. 68 80124000    |PUSH for_loop.00401280             ; format = "a = %i"
004012C0  |. E8 5B170000    |CALL <JMP.&msvcrt.printf>          ; roep printf op
004012C5  |. 83C4 10        |ADD ESP,10             ; ESP = ESP + 16    
004012C8  |. 8D45 FC        |LEA EAX,DWORD PTR SS:[EBP-4]   ; laad adres variable
004012CB  |. FF00           |INC DWORD PTR DS:[EAX]     ; variable += 1
004012CD  |.^EB DE          \JMP SHORT for_loop.004012AD    ; terug naar loop
004012CF  |> B8 00000000    MOV EAX,0               ; EAX = 0;
004012D4  |. C9             LEAVE       
004012D5  \. C3             RETN                ; Einde Programma


nu is mij vraag wat die SUB ESP, 8 & AND ESP,FFFFFFF0 nou voor nut hebben, wat doen ze, want deel is het enige wat ik niet echt snap.

bij het opslaan van de variable gebruiken ze MOV DWORD PTR SS:[EBP-8],EAX, waarom is het EBP-8.

ALs iemand me dat kan uitleggen zou dat het super zijn

al vast bedankt

  • Opi
  • Registratie: Maart 2002
  • Niet online

Opi

Ik denk dat je je het best kan gaan verdiepen in assembler (hier zal ongetwijfeld iets over in de FAQ staan). :)
Misschien heb je iets aan deze link:
http://homepages.ius.edu/rwisman/c335/Html/ProcInvoke.htm

Verwijderd

Wellicht, omdat op de stack ook nog (return) variabelen worden opgeslagen? Die je zodra de loop afgelopen is nog nodig hebt.

Verder lijkt het mij ook wel handig om de C-code hier ook neer te planten.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 04:06

.oisyn

Moderator Devschuur®

Demotivational Speaker

16 byte stack aligning

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
de c code is

code:
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

int main()
{
    int a;
    for(a=0;a<10;a++)
        printf("a = %i",a);
        
    return 0;
}


en wat houd 16 byte stack aligning in :?

Verwijderd

Bij nader inzien moet ik concluderen dat dit een niet zo'n slimme compiler is.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
00401288  /$ 55             PUSH EBP                ; sla base pointer op in stack
00401289  |. 89E5           MOV EBP,ESP             ; EBP = ESP
0040128B  |. 83EC 08        SUB ESP,8               ; 2x 32-bit variabelen (a+dummy) op de stack reserveren.
0040128E  |. 83E4 F0        AND ESP,FFFFFFF0            ; ESP = ESP - 1 (even stackpointer)
00401291  |. B8 00000000    MOV EAX,0               ; EAX = 0 (=a)
00401296  |. 8945 F8        MOV DWORD PTR SS:[EBP-8],EAX    ; EAX op stack (zie 0040128B)
00401299  |. 8B45 F8        MOV EAX,DWORD PTR SS:[EBP-8]    ; EAX = 0 (duh)
0040129C  |. E8 CF160000    CALL for_loop.00402970
004012A1  |. E8 0A010000    CALL for_loop.004013B0
004012A6  |. C745 FC 000000>MOV DWORD PTR SS:[EBP-4],0      ; DWORD PTR SS:[EBP-4] = 0
004012AD  |> 837D FC 0A     /CMP DWORD PTR SS:[EBP-4],0A    ; vergelijk met 10
004012B1  |. 7E 02          |JLE SHORT for_loop.004012B5    ; if < 10 ga naar 004012B5
004012B3  |. EB 1A          |JMP SHORT for_loop.004012CF    ; einde for loop
004012B5  |> 83EC 08        |SUB ESP,8              ; nog 2x 32-bit variabelen op stack
004012B8  |. FF75 FC        |PUSH DWORD PTR SS:[EBP-4]          ; a weer op stack voor printf
004012BB  |. 68 80124000    |PUSH for_loop.00401280             ; format = "a = %i"
004012C0  |. E8 5B170000    |CALL <JMP.&msvcrt.printf>          ; roep printf op
004012C5  |. 83C4 10        |ADD ESP,10             ; ESP = ESP + 16 (tijdelijke var. weer opruimen)
004012C8  |. 8D45 FC        |LEA EAX,DWORD PTR SS:[EBP-4]   ; a weer terughalen in EAX
004012CB  |. FF00           |INC DWORD PTR DS:[EAX]     ; a += 1
004012CD  |.^EB DE          \JMP SHORT for_loop.004012AD    ; terug naar loop
004012CF  |> B8 00000000    MOV EAX,0               ; EAX = 0;
004012D4  |. C9             LEAVE       
004012D5  \. C3             RETN                ; Einde Programma
nu is mij vraag wat die SUB ESP, 8 & AND ESP,FFFFFFF0 nou voor nut hebben, wat doen ze, want deel is het enige wat ik niet echt snap.

bij het opslaan van de variable gebruiken ze MOV DWORD PTR SS:[EBP-8],EAX, waarom is het EBP-8.

ALs iemand me dat kan uitleggen zou dat het super zijn
Doe maar een cursus stack interpreteren ;)

Afbeeldingslocatie: http://goforit.unk.edu/asm/images/asm_5a.gif

[ Voor 5% gewijzigd door Verwijderd op 20-08-2003 18:05 . Reden: typo ]


Verwijderd

bij ne call naar een subroutine wordt zowel het basis register als de verplaatsing + nog twee andere zaken erop gezet zodat hij weet van waar hij komt.
elk ding = 2 bytes
2*4 = 8 bytes moet hij terug gaan voor de stackpointer juist te zetten
niet?

"MOV DWORD PTR SS:[EBP-8],EAX" >> zie hierboven

" AND ESP,FFFFFFF0" ik zou het begot niet weten: missch nen invert van uw stack pointer... somebody?

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Verwijderd schreef op 20 August 2003 @ 17:27:
" AND ESP,FFFFFFF0" ik zou het begot niet weten: missch nen invert van uw stack pointer... somebody?
Zoals .oisyn al zei is dit stack alignment op 16 bytes.. Alignment op x is ervoor zorgen dat een adres een veelvoud is van x (16 dus in dit geval). Dat is efficienter te gebruiken door de processor omdat data ook zo wordt opgeslagen in het geheugen, de processor kan alleen maar geheugen op adressen opvragen/opslaan die een veelvoud zijn van een bepaalde waarde. Stel dat die waarde bijvoorbeeld 4 is, maar je zou een waarde op een niet-aligned adres zetten, valt deze waarde over 2 aligned blokken heen. De processor is dan genoodzaakt beide blokken binnen te halen omdat die aligned zijn en het orginele adres niet. Daarna worden de 2 losse stukjes weer aan elkaar geplakt (tenminste op x86, sommige processoren weigeren zelfs gewoon unaligned adressen te gebruiken).

De and zorgt ervoor dat de laatste 4 bits van esp op 0 komen te staan en de rest van de bits hetzelfde blijft. Dat heeft als effect dat esp afgerond wordt naar beneden op de eerstvolgende waarde die een veelvoud is van 16. Vaak gaat het andersom, dan wordt er afgerond op de eerstvolgende waarde die een veelvoud is van x maar omdat de stack naar beneden groeit moet het hier naar beneden.

www.madwizard.org


Verwijderd

ooow datte
basisadres * 16 + verplaatsing

das die maal 16 :-)

Verwijderd

Topicstarter
staan er een paar tutorials over stack interpreteren ?, want ik wil er graag meer over weten

Verwijderd

http://www.cs.ndsu.nodak.edu/~kamel/373/slides/ch05.pdf
edit:
http://atrevida.comprenica.com/atrtut15.html
deze heb ik gebruikt om mijn examen assembler te leren en héél da stack gedoe grondig te snappen

[ Voor 58% gewijzigd door Verwijderd op 20-08-2003 22:48 ]


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Jeremy Gordon heeft een 2 delige tutorial op z'n site staan (hier en hier). Op m'n eigen site staat ook een (windows) assembler tutorial maar die gaat niet heel diep op de stack in.

www.madwizard.org


Verwijderd

Topicstarter
mensen, bedankt, die tutorials zien er goed uit dus ik ga ze even grondig doornemen :D

edit:
ik heb zelf ook een website gevonden http://www.acm.uiuc.edu/sigmil/RevEng/index.html waar alles uitgelegd staat, dus als andere nog geinteresseerd zijn

[ Voor 52% gewijzigd door Verwijderd op 20-08-2003 23:13 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 04:06

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 20 August 2003 @ 17:27:
bij ne call naar een subroutine wordt zowel het basis register als de verplaatsing + nog twee andere zaken erop gezet zodat hij weet van waar hij komt.
elk ding = 2 bytes
2*4 = 8 bytes moet hij terug gaan voor de stackpointer juist te zetten
niet?

"MOV DWORD PTR SS:[EBP-8],EAX" >> zie hierboven

" AND ESP,FFFFFFF0" ik zou het begot niet weten: missch nen invert van uw stack pointer... somebody?
je leeft nog in het 16 bits realmode tijdperk
Registers zijn 32 bits, oftewel 4 bytes.

Als een C-functie wordt aangeroepen dan worden eerst alle parameters in omgekeerde volgorde op de stack gepushed. Daarna wordt de functie aangeroepen (waarbij het returnadres op de stack komt te staan), en daarna wordt de waarde van ebp erop gezet.

Locale variabelen worden ook op de stack opgeslagen. Van boven naar beneden ziet de stack er dus alsvolgt uit:
• parameters (n bytes)
• returnadres (4 bytes)
• ebp (4 bytes)
• locale vars (m bytes)

esp wijst op dit moment naar "ebp"
Omdat de stack natuurlijk wel bruikbaar moet zijn, en niet de locale variabelen moet overschrijven, worden de locale variabelen op de stack gereserveerd. Vandaar die sub 8, wat dus wil zeggen dat er 8 bytes aan locale variabelen zijn

Maar voordat er 8 vanaf wordt getrokken wordt er eerst een kopie gemaakt van esp in ebp, zodat er gemakkelijk naar de parameters en locale variabelen kan worden verwezen via ebp. Omdat er vanaf ebp gezien eerst de oude waarde van ebp komt, daarna het returnadres, en daarna de parameters, worden de parameters aangesproken vanaf [ebp-8] en verder. Parameter 2 is dan meestal 4 bytes verder terug, dus [ebp-12], etc. Deze 8 heeft echter niets met die sub ebp, 8 te maken :)
De locale variabelen beginnen bij [ebp+4], en gaan in dit geval t/m [ebp+7]. Vanaf [ebp+8] begint de stack
Verwijderd schreef op 20 August 2003 @ 18:20:
ooow datte
basisadres * 16 + verplaatsing

das die maal 16 :-)
wederom een realmode thingy :)
Hedendaagse operating systems draaien in 32 bits protected mode. Daarin zijn geen segments, maar zogenaamde selectors. De selector wijst naar een descriptor in de local of global descriptor table, en zo'n descriptor beschrijft onder andere welk geheugen er aangesproken moet worden en wat de rechten hiervoor zijn

De 16 byte aligning heeft dan ook niets met die 16 waarmee je het realmode-segment mee moet vermenigvuldigen te maken :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


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

Skinkie

Op naar de 500

dan ga ik nog een vreemde vraag stellen: hoe copyeer je alle stack waarden om ze vervolgens te herstellen voordat je een call doet?

dus dat je een functie echt kunt hooken zonder iets met de parameters te doen?

Steun Elkaar, Kopieer Nederlands Waar!


Verwijderd

een stack dient juist om var's in op te slagen, de stack zelf blijf beschikbaar.
Of wat bedoel je juist?
@.oisyn: thx for the info

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Overigens kunnen veel compilers ook frame pointer omission als optimalisatie, wat inhoud dat je esp als basisadres gebruikt om lokale variabelen en parameters te lezen ([esp+xx] dus). Zo kan ebp vrij gebruikt worden voor andere dingen (extra register erbij dus). Zo'n functie kan wat lastiger te lezen zijn omdat esp wijzigt door push & pop etc., de offsets wijzigen dus ook (de ene keer is de parameter [esp+12] maar na een push is ie [esp+16]). Dat heb je bij ebp stackframes niet omdat ebp niet gewijzigd wordt.
Skinkie schreef op 21 August 2003 @ 03:45:
dan ga ik nog een vreemde vraag stellen: hoe copyeer je alle stack waarden om ze vervolgens te herstellen voordat je een call doet?

dus dat je een functie echt kunt hooken zonder iets met de parameters te doen?
Gewoon alles wat op de stack staat op het moment dat je hookt zo laten, dus wel lezen maar niet wijzigen. Je kan wel gewoon de stackruimte eronder gebruiken, als je maar voor het aanroepen van de functie weer zorgt dat esp z'n oude waarde heeft. Dan een jmp naar de functie (geen call) en het moet werken.

[ Voor 5% gewijzigd door madwizard op 21-08-2003 08:05 ]

www.madwizard.org


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

Skinkie

Op naar de 500

madwizard schreef op 21 August 2003 @ 08:03:
Gewoon alles wat op de stack staat op het moment dat je hookt zo laten, dus wel lezen maar niet wijzigen. Je kan wel gewoon de stackruimte eronder gebruiken, als je maar voor het aanroepen van de functie weer zorgt dat esp z'n oude waarde heeft. Dan een jmp naar de functie (geen call) en het moet werken.
als dit werkt heb je het tweede deel van het probleem opgelost
probleem is dus dat ik nooit exact weet hoeveel argumenten op de stack staan, op dat moment heb ik ook niets aan losse argumenten, alle argumenten bij elkaar moeten op de heap worden geplaatst, als geheel

Steun Elkaar, Kopieer Nederlands Waar!


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Skinkie schreef op 21 augustus 2003 @ 09:56:
[...]
als dit werkt heb je het tweede deel van het probleem opgelost
probleem is dus dat ik nooit exact weet hoeveel argumenten op de stack staan, op dat moment heb ik ook niets aan losse argumenten, alle argumenten bij elkaar moeten op de heap worden geplaatst, als geheel
Wat wil je dan precies doen? Je weet inderdaad nooit hoeveel argumenten er op staan, tenzij je weet welke functie het is dan natuurlijk wel. Je kunt wel gewoon een stuk of 16 argumenten kopieren ofzo, is meestal wel genoeg. Als ik je precieze bedoeling weet kan ik je misschien meer vertellen...

www.madwizard.org


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

Skinkie

Op naar de 500

zonder erg in specifieke details te treden wil ik het volgende doen:

programma wordt gestart door server, programma draait in specifieke env waar LD_PRELOAD is aangepast, de preloaded SO bestaat uit een SO waarin alle functies zijn opgenomen die shared gelinked zijn, de preload override alle andere bindings en hooked alsware de functie. Nu wil ik niet afhankelijk zijn van headerfiles om die preloaded SO te maken (automatisch that is), en wil ik dus ten eerste alle arguments die naar een functie gaan ontvangen en loggen voor later gebruik, en met die arguments die opgegeven zijn de echte functie aanroepen doormiddel van een DLSYM

wat heeft dit voor zin? als ik weet welke arguments zijn opgegeven kan ik ook een ander programma de zelfde functies laten uitvoeren (ja, ik ben me bewust van pointers etc)

Steun Elkaar, Kopieer Nederlands Waar!


  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Skinkie schreef op 23 augustus 2003 @ 03:19:
zonder erg in specifieke details te treden wil ik het volgende doen:

programma wordt gestart door server, programma draait in specifieke env waar LD_PRELOAD is aangepast, de preloaded SO bestaat uit een SO waarin alle functies zijn opgenomen die shared gelinked zijn, de preload override alle andere bindings en hooked alsware de functie. Nu wil ik niet afhankelijk zijn van headerfiles om die preloaded SO te maken (automatisch that is), en wil ik dus ten eerste alle arguments die naar een functie gaan ontvangen en loggen voor later gebruik, en met die arguments die opgegeven zijn de echte functie aanroepen doormiddel van een DLSYM

wat heeft dit voor zin? als ik weet welke arguments zijn opgegeven kan ik ook een ander programma de zelfde functies laten uitvoeren (ja, ik ben me bewust van pointers etc)
Zolang je niet weet bij welke functie je op dat moment zit (generieke hook dus) kan je niet achterhalen hoeveel parameters je hebt. Zoals ik al zei kan je wel gewoon zeg 16 parameters opslaan en daar dan later het juiste deel van gebruiken. Het uiteindelijk echt aanroepen van de functie kan gewoon met een jump zoals ik ook al uitgelegd had, zorg dat de stack van je hookfunctie weer helemaal zo is als aan het begin (dus alleen het return adres er nog op).

Vraag is wat je later met de data gaat doen, je hebt dan een lijstje functie calls met steeds 16 parameters, weet je op dat moment wel het juiste aantal? Of wil je het opnieuw aanroepen van de functies ook automatisch laten gebeuren zonder headers? Dat laatste kan in principe ook wel door de 16 parameters weer op de stack te gooien, de functie aan te roepen en de 16 er weer af te halen. De functie gebruikt dan toch alleen wat ie nodig heeft. Dat werkt trouwens alleen bij de C calling convention. Maar als je ook rekening houdt met pointers e.d. zal je nog wel meer moeten doen dan alleen dit denk ik.

www.madwizard.org


  • drZymo
  • Registratie: Augustus 2000
  • Laatst online: 09-08 22:22
Even snel tussendoor. Voor wat meer en een duidelijke uitleg over calling conventions in C kijk eens op http://www.codeproject.co...nventions_demystified.asp.

"There are three stages in scientific discovery: first, people deny that it is true; then they deny that it is important; finally they credit the wrong person."

Pagina: 1