Wat assembly code, vreemd stack gebruik

Pagina: 1
Acties:

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Dit is wat code uit een spel. Nu snap ik ongeveer wat deze functie doet, maar ik snap niet helemaal wat een bepaalde instructie met de stack doet. Het gaat om de volgende instructie:
code:
1
4FBF                 mov     [esp+10h], ebx

Volgens mij staat op die lokatie namelijk ecx (gepushed door eerste instructie). Het lijkt me niet dat daar gewoon overheen wordt geschreven.
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
4F80 CommonFunc20    proc near               
4F80
4F80 arg_0           = dword ptr  14h
4F80
4F80                 push    ecx
4F81                 push    ebx
4F82                 push    ebp
4F83                 push    esi
4F84                 mov     esi, [esp+arg_0]
4F88                 test    esi, esi
4F8A                 push    edi
4F8B                 mov     ebp, ecx
4F8D                 jz      loc_5142
4F93                 mov     edi, esi
4F95                 or      ecx, 0FFFFFFFFh
4F98                 xor     eax, eax
4F9A                 repne scasb
4F9C                 not     ecx
4F9E                 dec     ecx
4F9F                 jz      loc_5142
4FA5                 mov     eax, [ebp+0]
4FA8                 mov     ecx, ebp
4FAA                 call    dword ptr [eax+4]
4FAD                 push    esi             ; const char *
4FAE                 call    __strdup
4FB3                 mov     ebx, eax
4FB5                 or      ecx, 0FFFFFFFFh
4FB8                 mov     edi, ebx
4FBA                 xor     eax, eax
4FBC                 add     esp, 4
4FBF                 mov     [esp+10h], ebx
4FC3                 repne scasb
4FC5                 not     ecx
4FC7                 dec     ecx
4FC8                 jz      short loc_4FEB
4FCA                 mov     edi, ebx
4FCC                 or      ecx, 0FFFFFFFFh
4FCF                 repne scasb
4FD1                 not     ecx
4FD3                 dec     ecx
4FD4                 cmp     byte ptr [ecx+ebx-1], 0Ah
4FD9                 jnz     short loc_4FEB
4FDB                 mov     edi, ebx
4FDD                 or      ecx, 0FFFFFFFFh
4FE0                 xor     eax, eax
4FE2                 repne scasb
4FE4                 not     ecx
4FE6                 dec     ecx
4FE7                 mov     [ecx+ebx-1], al
4FEB
4FEB loc_4FEB:                           
4FEB                                         
4FEB                 mov     al, [ebx]
4FED                 xor     esi, esi
4FEF                 test    al, al
4FF1                 jz      short loc_4FF8
4FF3                 mov     esi, 1
4FF8
4FF8 loc_4FF8:                           
4FF8                 test    al, al
4FFA                 mov     ecx, ebx
4FFC                 jz      short loc_500B
4FFE
4FFE loc_4FFE:                           
4FFE                 cmp     al, 2Ch
5000                 jnz     short loc_5003
5002                 inc     esi
5003
5003 loc_5003:                           
5003                 mov     al, [ecx+1]
5006                 inc     ecx
5007                 test    al, al
5009                 jnz     short loc_4FFE
500B
500B loc_500B:                           
500B                 test    esi, esi
500D                 jz      loc_5142
5013                 mov     eax, [ebp+10h]
5016                 test    eax, eax
5018                 jz      short loc_5053
501A                 mov     ecx, [ebp+0Ch]
501D                 test    ecx, ecx
501F                 lea     eax, [ecx-1]
5022                 mov     [ebp+0Ch], eax
5025                 jz      short loc_5047
5027
5027 loc_5027:                           
5027                 mov     ecx, [ebp+10h]
502A                 mov     eax, [ecx+eax*4]
502D                 test    eax, eax
502F                 jz      short loc_503A
5031                 push    eax
5032                 call    sub_5A55
5037                 add     esp, 4
503A
503A loc_503A:                           
503A                 mov     ecx, [ebp+0Ch]
503D                 test    ecx, ecx
503F                 lea     eax, [ecx-1]
5042                 mov     [ebp+0Ch], eax
5045                 jnz     short loc_5027
5047
5047 loc_5047:                           
5047                 mov     edx, [ebp+10h]
504A                 push    edx
504B                 call    sub_57DD
5050                 add     esp, 4
5053
5053 loc_5053:                           
5053                 mov     [ebp+0Ch], esi
5056                 mov     dword ptr [ebp+10h], 0
505D                 shl     esi, 2
5060                 push    esi             ; size
5061                 call    new
5066                 mov     ecx, esi
5068                 mov     edi, eax
506A                 mov     edx, ecx
506C                 xor     eax, eax
506E                 shr     ecx, 2
5071                 mov     [ebp+10h], edi
5074                 add     esp, 4
5077                 repe stosd
5079                 mov     ecx, edx
507B                 and     ecx, 3
507E                 repe stosb
5080                 mov     edi, [esp+4+arg_0]
5084                 or      ecx, 0FFFFFFFFh
5087                 xor     eax, eax
5089                 repne scasb
508B                 not     ecx
508D                 sub     edi, ecx
508F                 mov     eax, ecx
5091                 mov     esi, edi
5093                 mov     edi, ebx
5095                 shr     ecx, 2
5098                 repe movsd
509A                 mov     ecx, eax
509C                 and     ecx, 3
509F                 repe movsb
50A1                 mov     ecx, [esp+10h]
50A5                 xor     edi, edi
50A7                 mov     [esp+4+arg_0], edi
50AB                 cmp     byte ptr [ecx], 0
50AE                 jz      short loc_5107
50B0
50B0 loc_50B0:                           
50B0                 mov     al, [ebx]
50B2                 mov     esi, ebx
50B4                 test    al, al
50B6                 jz      short loc_50C4
50B8
50B8 loc_50B8:                           
50B8                 cmp     al, 2Ch
50BA                 jz      short loc_50C4
50BC                 mov     al, [esi+1]
50BF                 inc     esi
50C0                 test    al, al
50C2                 jnz     short loc_50B8
50C4
50C4 loc_50C4:                           
50C4                                         
50C4                 cmp     byte ptr [esi], 0
50C7                 jz      short loc_50CD
50C9                 mov     byte ptr [esi], 0
50CC                 inc     esi
50CD
50CD loc_50CD:                           
50CD                 mov     edx, [esp+4+arg_0]
50D1                 shl     edi, 2
50D4                 inc     edx
50D5                 mov     [esp+4+arg_0], edx
50D9                 mov     edx, [ebp+10h]
50DC                 mov     eax, [edx+edi]
50DF                 test    eax, eax
50E1                 jz      short loc_50EC
50E3                 push    eax
50E4                 call    sub_5A55
50E9                 add     esp, 4
50EC
50EC loc_50EC:                           
50EC                 push    ebx             ; const char *
50ED                 call    __strdup
50F2                 mov     ecx, [ebp+10h]
50F5                 add     esp, 4
50F8                 mov     ebx, esi
50FA                 mov     [ecx+edi], eax
50FD                 mov     al, [esi]
50FF                 mov     edi, [esp+4+arg_0]
5103                 test    al, al
5105                 jnz     short loc_50B0
5107
5107 loc_5107:                           
5107                 mov     edx, [ebp+0Ch]
510A                 dec     edx
510B                 cmp     edi, edx
510D                 jnz     short loc_5135
510F                 mov     eax, [ebp+10h]
5112                 mov     eax, [eax+edi*4]
5115                 test    eax, eax
5117                 jz      short loc_5122
5119                 push    eax
511A                 call    sub_5A55
511F                 add     esp, 4
5122
5122 loc_5122:                           
5122                 push    offset noparams ; const char *
5127                 call    __strdup
512C                 mov     ecx, [ebp+10h]
512F                 add     esp, 4
5132                 mov     [ecx+edi*4], eax
5135
5135 loc_5135:                           
5135                 mov     edx, [esp+10h]
5139                 push    edx
513A                 call    sub_5A55
513F                 add     esp, 4
5142
5142 loc_5142:                           
5142                                         
5142                 pop     edi
5143                 pop     esi
5144                 pop     ebp
5145                 pop     ebx
5146                 pop     ecx
5147                 retn    4
5147 CommonFunc20    endp

Verwijderd

Op het adres dat op locatie esp+10h staat staat ecx? En als het de waarde van ecx is die aan het begin gepushed wordt dan maakt het toch niets uit ... deze wordt immers weer gepopped aan het einde?

  • -Michel-
  • Registratie: Oktober 2000
  • Laatst online: 21:08
Ok dit is voor mij wel een hele tijd geleden maar volgens mij is 10h de eerste vrije positie op de stack.

Volgens mij staat ESI op positie 0-3, EBP op 4-7, EBX op 8-11 en ECX op 12-15.
Dan is 10h (16) de eerste vrije positie die voor een temp variabele gebruikt kan worden.

Maar nogmaals: Dit is voor mij heel erg lang geleden dus wat hierboven staat kan pure onzin zijn :)

  • serkoon
  • Registratie: April 2000
  • Niet online

serkoon

mekker.

D'r staat ook nog een "add esp, 4" voor he..

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Verwijderd schreef op 17 augustus 2002 @ 20:18:
Op het adres dat op locatie esp+10h staat staat ecx? En als het de waarde van ecx is die aan het begin gepushed wordt dan maakt het toch niets uit ... deze wordt immers weer gepopped aan het einde?
Het maakt wel uit, want die waarde wordt dus overschreven (mov destination, source). En die pop gaat dus fout aan het eind.

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
-Michel- schreef op 17 augustus 2002 @ 20:21:
Ok dit is voor mij wel een hele tijd geleden maar volgens mij is 10h de eerste vrije positie op de stack.

Volgens mij staat ESI op positie 0-3, EBP op 4-7, EBX op 8-11 en ECX op 12-15.
Dan is 10h (16) de eerste vrije positie die voor een temp variabele gebruikt kan worden.

Maar nogmaals: Dit is voor mij heel erg lang geleden dus wat hierboven staat kan pure onzin zijn :)
Nee, dan zou op 16 dus eip staan. Er is geen ruimte gereserved voor local/temp vars. Maar jij bent "4F8A push edi" vergeten.

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
serkoon schreef op 17 augustus 2002 @ 20:26:
D'r staat ook nog een "add esp, 4" voor he..
Dat vond ik ook raar eerst, maar dat is de cleanup van de vorige functie aanroep.

Verwijderd

Ik heb er maar even snel naar gekeken, dus geen garantie ;) /disclaimer.

Volgens mij staat daar ESI.

code:
1
2
3
4
5
6
7
8
            ecx
            ebx
            ebp 
    16 (0x10)   esi  
        12  edi  
        8   esi  
        4   SKIP  
                0       current


Want SCASB gaat dus die string checken en daar heeft-ie data voor nodig. Die data komt via eax van strdup terug.
Dus ik denk ESI (maar ik heb vast iets over het hoofd gezien ;) )
edit:
toch maar de opmaak wat verandert ;)

Verwijderd

/me vindt assembly programmeurs kunstenaars

Snap er zelf 0,0 van als ik het zo voor me zie :)

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Verwijderd schreef op 17 augustus 2002 @ 22:43:
* Olaf van der Spek vindt assembly programmeurs kunstenaars

Snap er zelf 0,0 van als ik het zo voor me zie :)
Dit was C++ code, maar daar heb ik geen toegang toe :'(
Dut was ik aan het reverse engineren:
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
void CommonFunc20(const char* arg_0)
{
    if (!arg_0 || !strlen(arg_0))
        return;
    char* a = strdup(arg_0);
    if (strlen(a) && a[strlen(a) - 1] == '\n')
        a[strlen(a) - 1] = 0;
    int b = strlen(a) ? 1 : 0;
    {
        const char* r = a;
        while (*r)
        {
            if (*r++ == ',')
                b++;
        }
    }
    if (!b)
        return;
    int cc = 4;
    char** ca = NULL;
    if (ca)
    {
        while (cc--)
        {
            if (ca[cc])
                free(ca[cc]);
        }
        free(ca);
    }
    cc = b;
    ca = new char*[b];
    memset(ca, 0, b << 2);
    memcpy(a, arg_0, strlen(arg_0));
    int i = 0;
    for (char* r = a; *r; i++)
    {
        char* r2 = r;
        while (*r2 && *r2 != ',')
            r2++;
        if (*r2)
            *r2++ = 0;
        if (ca[i]) // never true
            free(ca[i]);
        ca[i] = strdup(r);
        r = r2;
    }
    if (cc != i) // never true
    {
        if (ca[cc]) // never true
            free(ca[cc]);
        ca[cc] = strdup("noparams");        
    }
    free(a);
}

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Verwijderd schreef op 17 augustus 2002 @ 22:34:
Ik heb er maar even snel naar gekeken, dus geen garantie ;) /disclaimer.

Volgens mij staat daar ESI.

code:
1
2
3
4
5
6
7
8
            ecx
            ebx
            ebp 
    16 (0x10)   esi  
        12  edi  
        8   esi  
        4   SKIP  
                0       current


Want SCASB gaat dus die string checken en daar heeft-ie data voor nodig. Die data komt via eax van strdup terug.
Dus ik denk ESI (maar ik heb vast iets over het hoofd gezien ;) )
edit:
toch maar de opmaak wat verandert ;)
Na een push staat [esp] op die waarde. Verder is die add esp, 4 om de push esi er weer af te halen (stack clean-up by caller).

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Iemand anders misschien? Ik ben bezig met wat meer 'disassembly' en nu kom ik weer zo'm vreemde instructie tegen.

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

madwizard

Missionary to the word of ska

Weet je zeker dat het een normale procedure is? Het lijkt erg op een C++ method. De VC compiler geeft meestal de this-pointer mee in ecx. Ecx wordt ook zo in de procedure gebruikt, normaal gesproken worden parameters via de stack doorgegeven, slechts soms via registers (fastcall doet dat geloof ik).
code:
1
2
3
4
5
6
7
8
4F8B                 mov     ebp, ecx ; ebp = ecx = this
...
4FA5                 mov     eax, [ebp+0]  ; eax = vtable
...
; this-pointer opnieuw setten:
4FA8                 mov     ecx, ebp 4FAA
;tweede (virtual) method uit de vtable:
call    dword ptr [eax+4]

Die call op 4FAA is waarschijnlijk een virtual method call binnen dezelfde class, die zie ik niet in je code terug (of ik kijk verkeerd). Misschien dat die de stack zo veranderd dat de 4FBF weer iets zinnigs doet?

www.madwizard.org


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

madwizard

Missionary to the word of ska

Heb er nog eens naar gekeken, volgens mij wordt die [esp+10] uiteindelijk van de stack gehaald door de pop ecx. Hij wordt gewoon als soort van locale var gebruikt denk ik. Dat ecx daardoor veranderd is maakt niet uit, in principe is de regel dat alleen esi, edi en ebx ongewijzigd moeten blijven (esp en ebp natuurlijk ook).
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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
4F80                 push    ecx
esp+0 -> ecx

4F81                 push    ebx
esp+4 -> ecx
esp+0 -> ebx

4F82                 push    ebp
esp+8 -> ecx
esp+4 -> ebx
esp+0 -> ebp

4F83                 push    esi
esp+C -> ecx
esp+8 -> ebx
esp+4 -> ebp
esp+0 -> esi
4F8A                 push    edi
esp+10-> ecx
esp+C -> ebx
esp+8 -> ebp
esp+4 -> esi
esp+0 -> edi
4FAD                 push    esi
esp+14-> ecx
esp+10-> ebx
esp+C -> ebp
esp+8 -> esi
esp+4 -> edi
esp+0 -> esi
4FBC                 add     esp, 4
esp+10-> ecx
esp+C -> ebx
esp+8 -> ebp
esp+4 -> esi
esp+0 -> edi
esp-4 -> esi
4FBF                 mov     [esp+10h], ebx
esp+10-> ebx <----
esp+C -> ebx
esp+8 -> ebp
esp+4 -> esi
esp+0 -> edi
esp-4 -> esi

504A                 push    edx        ;
5050                 add     esp, 4     ;

5060                 push    esi             ; size
5074                 add     esp, 4

50E3                 push    eax
50E9                 add     esp, 4

50EC                 push    ebx             ; const char *
50F5                 add     esp, 4

5119                 push    eax
511F                 add     esp, 4

5122                 push    offset noparams ; const char *
512F                 add     esp, 4

5139                 push    edx
513F                 add     esp, 4


5142                 pop     edi ;edi terug
5143                 pop     esi ;esi terug
5144                 pop     ebp ;ebp terug
5145                 pop     ebx ;ebx terug
5146                 pop     ecx ;<<<<< overschreven waarde

www.madwizard.org


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
madwizard schreef op 16 september 2002 @ 21:54:
Weet je zeker dat het een normale procedure is? Het lijkt erg op een C++ method. De VC compiler geeft meestal de this-pointer mee in ecx. Ecx wordt ook zo in de procedure gebruikt, normaal gesproken worden parameters via de stack doorgegeven, slechts soms via registers (fastcall doet dat geloof ik).
Klopt, ik denk ook dat het een method is.
Die call op 4FAA is waarschijnlijk een virtual method call binnen dezelfde class, die zie ik niet in je code terug (of ik kijk verkeerd).
Misschien dat die de stack zo veranderd dat de 4FBF weer iets zinnigs doet?
Nee, die andere method staat er niet bij, maar ik denk dat die de stack gewoon 'normaal' gebruikt.

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
madwizard schreef op 16 september 2002 @ 22:31:
Heb er nog eens naar gekeken, volgens mij wordt die [esp+10] uiteindelijk van de stack gehaald door de pop ecx. Hij wordt gewoon als soort van locale var gebruikt denk ik. Dat ecx daardoor veranderd is maakt niet uit, in principe is de regel dat alleen esi, edi en ebx ongewijzigd moeten blijven (esp en ebp natuurlijk ook).
Als dat zo is, waarom zijn de push/pop ecx instructies dan nodig?
Waarvoor worden ebx, edi en esi eigenlijk gebruikt? En ebp is niet per se nodig (frame pointer omission).

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 15:49
Je bent toch niet aan 't assembly hacken zonder debugger, hoop ik? Daarmee zou je namelijk wel moeten zien waar je stack pointer op welk moment naar wijst en dan is de vraag snel beantwoord...

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Eigenlijk wel, anders had ik zelf wel even gekeken.

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

madwizard

Missionary to the word of ska

OlafvdSpek schreef op 17 september 2002 @ 14:42:
Als dat zo is, waarom zijn de push/pop ecx instructies dan nodig?
Waarvoor worden ebx, edi en esi eigenlijk gebruikt?
Volgens mij wordt die esp+10 gebruikt als (enige?) lokale variabele dus ik denk dat de push ecx werd gebruikt ipv sub esp, 4 om een stack frame op te zetten. Maar het blijft onlogisch want sub esp, 4 zou sneller zijn (geen memory write) en de waarde wordt toch weer meteen overschreven.
En ebp is niet per se nodig (frame pointer omission).
Das ook waar, vreemd dat ie em toch weer terugzet...

Slechte compiler :) ?

www.madwizard.org


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
madwizard schreef op 17 september 2002 @ 16:56:
Volgens mij wordt die esp+10 gebruikt als (enige?) lokale variabele dus ik denk dat de push ecx werd gebruikt ipv sub esp, 4 om een stack frame op te zetten. Maar het blijft onlogisch want sub esp, 4 zou sneller zijn (geen memory write) en de waarde wordt toch weer meteen overschreven.
Das ook waar, vreemd dat ie em toch weer terugzet...

Slechte compiler :) ?
Geen idee wat Westwood Studios precies gebruikt, maar het lijkt op Visual C++ 6.

Waarvoor worden ebx, edi en esi eigenlijk gebruikt?

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

madwizard

Missionary to the word of ska

Geen idee wat Westwood Studios precies gebruikt, maar het lijkt op Visual C++ 6.
VC produceert over het algemeen wel goede code, misschien was het gewoon een verkeerde inschatting van de compiler ofzo.
Waarvoor worden ebx, edi en esi eigenlijk gebruikt?
De windows API gaat er vanuit dat ebx/edi/esi niet gewijzigd worden in callbacks en andersom zal de windows API ebx/edi/esi ook nooit wijzigen. C++ houd deze conventie meestal ook aan voor C++ functies, anders zou een call alle echt alle registers vervuilen.

www.madwizard.org

Pagina: 1