View Full Version : Help with Quick ASM Translation.
Adri_Magnon
June 20th, 2002, 22:22
Hi,
Can someone please tell me what the follwoing means...
push ebp
mov ebp, esp
push [ebp+10]
push [ebp+OC]
push [ebp+08]
call 0043B5F0
add esp, 0000000C
pop ebp
ret
I think it means, 1) Get the information at register EBP 2) Move the information from register ESP to EBP 3-5)?? add "10/0C/08" to EBP?? 6) Call the command at offset 0043B5F0 7) Add 0000000C to ESP 8) Restore the info at EBP 9) Return the call that started that bit of code.
Is that close?
Thanks,
Adri_Magnon
nikolatesla20
June 20th, 2002, 22:45
The first two instructions are setting up what is known as a "stack frame" this enables you to reference local variables, and variables that were passed to you, using the ebp register. It is not fun to use the esp register for that because anytime you push or pop something your offsets change. This is why we store the original value of esp into ebp when we enter the function. The value of ebp will now be constant (unless you muck with it) and we can reference locals by [ebp - xx] and parameters passed to us by [ebp + xx ]. Now, one thing to note for parameters passed in, is that the first parameter will be [ebp + 08] . Why? Well, because our parameters were pushed in right to left when they were sent to us. (tradition C call) Now, esp points to the first parameter which is on top of the stack. BUT when a call is made, the Intel chip automagically pushes the RETURN aDDRESS on top of the stack AND we did a PUSH EBP BEFORE we loaded ESP into EBP. So there is two more values on top of the stack, and we need to skip them. Two more DWORDS. Adds up to 8.

It can be easy to forget about the return address being pushed on the stack when you read ASM. Don't forget about that!
Ok, the push [ebp+10] , etc calls are pushing arguments unto the stack for the CALL afterwards. Traditional C code and most ASM routines use the stack for function arguments. The ebp+10 was an argument which was passed INTO this routine. Remember, ebp was based off of esp. And esp points to the stack. The stack where the arguments were passed in to us. Now we are also pushing it again to pass it to another routine. One thing to notice too is see how once again the arguments are being pushed from right to left, in the same order as we received them. Hope that makes sense to you.
The add, esp 0000000C is removing the arguments off of the stack that were passed to us. In C code it is the callee's responsiblity to remove the parameters from the stack before returning. This could have been done by also using a "leave" statement, or by simply doing a mov esp, ebp, but to each his own. Leave is slow and isn't used much I guess. A "leave" is basically a "mov esp, ebp - pop ebp".
And the last of course is pop ebp, which just pops the original ebp back off of the stack again, and then the RET which goes back to the caller.
-nt20
hack3r2k
June 20th, 2002, 22:46
I love ASM !!!!!!!!!!!!!!!!!!
push ebp ; preserve base pointer
mov ebp, esp ; stack pointer into ebp
push [ebp+10] ; push C param
push [ebp+OC] ;push B param
push [ebp+08] ;push A param
call 0043B5F0 ; call a procedure (ex.SomeProc proc A:SomeType, B:SomeType, C:Sometype l where SomeType can be Byte, Word, Dword, Qword)
add esp, 0000000C ;restore stack pointer
pop ebp ;restore base pointer
ret ;return from the procedure cause the code u pasted coresponds to a procedure
TIP:
EBP in this context is actually a memory operand and the displacement in either direction is the address of either a parameter or a LOCAL variable.
WIN32ASM strikes back (u can't call yourself a cracker if u don't know asm


))
best regards,
.:hack3r2k:.
-=i'm fuckin' tired right now (2 am)=-
NervGaz
June 21st, 2002, 00:08
judging by the values... 08h, 0Ch ,10h it's dwords... and you seem to have two unused arg to the routine... otherwise it would be 00h, 04h, 08h... unless the stackframe was manually created and for some reason made to start att 08h
nikolatesla20
June 21st, 2002, 04:39
Quote:
Originally posted by NervGaz
judging by the values... 08h, 0Ch ,10h it's dwords... and you seem to have two unused arg to the routine... otherwise it would be 00h, 04h, 08h... unless the stackframe was manually created and for some reason made to start att 08h |
NervGaz - Remember, when a procedure is called (we can tell this is a called routine BECAUSE it has [ebp+xx] values in it, and it creates a stack frame), the return address gets pushed unto the stack. And we also pushed EBP as the first operation of our routine. SO we have two DWORDS that we pushed on the stack on top of the parameters BEFORE we do anything with them. We have modified the stack pointer (ESP) before we stored it into EBP itself. This is why the parameters always start at [ebp + 08] in most functions. We need to skip the return address, and skip the EBP we pushed.
-nt20
NervGaz
June 21st, 2002, 11:43
umm your right... forgot about that stuff... but it oonly applies in some cases... depends on what caling convention and stuff too... could be a long discussion... anyway it's safe to assume what said is correct in most cases... i was a bit tired when i wrote that...
fjrp2
June 21st, 2002, 19:38
Very interesting nikolatesla20,
but:
if the parameters where already IN the stack, why do you push them again?
I guess the compilar does that for you, is it?
hack3r2k
June 21st, 2002, 19:45
The assembler doesn't do this for you while the compiler does that ...
bye, bye
nikolatesla20
June 21st, 2002, 19:51
Well, the parameters ARE in the stack yet, but they wouldn't be in the correct place to just CALL another routine, because we have that return address and the EBP register on the stack above them. So we really don't have any choice but to push them again.
This is really the only "clean" way to do it, otherwise each function would depend on the other functions not to mess up the stack. Just by CALLING we are pushing the return address on the stack and we already shift anything out of place anyway. Plus the function usually has the SUB ESP, XX at the end to restore the stack frame. If that was still there when we called the second routine, we would crash because the stack wouldn't be going to its original place as where it was when we entered our top function. (For example, say we don't push the params to the second called routine. But the second call still does a SUB. Well the SUB removes the params off the stack. Now we come back to our routine, which also does a SUB. Whoops. don't need to do that anymore. You are screwed ! It is better to have the convention of each function taking care of its own parameters. This is also why function calls have so much "overhead" compared to inline code.)
Yes, it is not necessary to create a stack frame if you want to "optimize". You could hand code ASM routines that don't use it, just be careful how you use the stack and the registers ! In fact, Delphi apps usually don't use stack frames in their procedures (parameters are passed in other registers, yuck.) This is why delphi is harder to read in asm

There is an option in Delphi to make it use stack frames. It's kinda up to each compiler's settings. But most C and C++ and ASM compilers use stack frames.
So to sum it up, the program compiler does most of this behind the scenes for you. You can code it in raw asm if you want, but for example MASM you can use the PROC directive to tell the compiler this is a procedure, etc. It is more readable then.
-nt20
hack3r2k
June 21st, 2002, 19:57
Hey !
Hey nikolatesla20 there no such thing as an assembler compiler !!!
Or is compiler or is assembler ...
Do you want me to explain you what's a compiler and what's an assembler, and what's the difference between them ???
I hope this to be just a silly mistake of yours...
bye !!

fjrp2
June 21st, 2002, 20:11
Thanx nicolatesla.
Then how can you access LOCAL variables?
nikolatesla20
June 21st, 2002, 21:07
Accessing local variables:
I used to wonder about this too when I first started asm. But it's really actually very easy.
When we first enter our function remember we are doing a MOV EBP,ESP. Then we push EBP to keep it for later so we can pop it and restore it before we leave the function. Now just remember that. We are storing ESP INTO EBP. Now we can use EBP to reference parameters, which would be [EBP + XX], since we pushed some crap on top of the parameters, they are further "down" the stack, hence we need to ADD an offset to get to them.
So how do you "create" local variables? WEll remember local variables go out of scope when you leave a function. So it really doesn't matter if we would use the stack to create them ! Because we are going to restore the ESP register value back to its original value before we leave the function anyway. So to create local variables we can just subtract a value from ESP itself - say we wanted a single DWORD local variable. We would subtract 4 from ESP like so: SUB ESP, 04.
Now, ESP is 4 less than it was. And remember that EBP holds the original value of ESP. So to access this local variable, we would have to subtract 4 from EBP as well. This is how it would be done : MOV EAX, [ EBP - 04] for example. This moves our local variable into EAX.
One thing you may wonder though is well that is fine and dandy, but why are we subtracting from ESP? I mean EBP knows where it is, we can always just subtract from EBP to get local variables - how in the heck does ESP affect EBP in this whole thing?
Well the reason is that other stack operations might be going on inside your function, and you don't know for sure what is going to happen. So say you didn't subtract 4 from ESP. But you are going to go ahead anyway and use a local variable by doing a [EBP - 04]. This might seem to work just fine. But now you do a PUSH EAX or something. Look what you just did. Since ESP is still in its original place, when you did the PUSH, you just overwrote the data location that you were using by doing a [EBP - 04]. If you would have subtracted 4 from ESP in the first place like you should have, any PUSH or POP operations would not affect EBP-04, because a PUSH would now occur at EBP - 08. (Or in other words, you subtract 4 from ESP to "make room" so ESP doesn't overwrite the data when other stack operations are performed. The first PUSH now ends up "above" your data.)
Hope that makes sense for u.
-nt20
fjrp2
June 26th, 2002, 17:40
It has take me long to understand it.
push [second parameter]
push [first parameter]
call Main
Main:
push ebp
mov ebp, esp
push,[ebp+0C] ;second parameter
push,[ebp+08] ;first parameter
call Second
mov esp,ebp
pop ebp
ret
Second:
sub esp,04 ;reserve 1 local
mov [ebp-04],first_local
.
.
.
ret ;No need to restore SP, I think
What do you think of it?
NervGaz
June 26th, 2002, 18:36
you should pretty much always save and restore (E)SP when doing functions... even if it's not needed it's better to do it all the time so you don't end up with something going straight to hell after adding a shitload of code in memory or someting...
fjrp2
June 26th, 2002, 18:39
Okay, thanks
nikolatesla20
June 27th, 2002, 03:54
In your example, you would have to restore ESP at the end of "Second", because it gets two parameters pushed to it. It's usually the responsiblity of the routine that is called to POP those back off of the stack. (Since the called routine usually knows how many arguments it takes in to begin with, it's easier for it to clear them off)
So at the end of Second, you would have a :
SUB ESP, 08 ; 8 because of 2 DWORD parameters.
Since you are not creating a normal stack frame in "Second" you would only need to do this. Be aware that stack offset errors are the largest causes of crashes, next to wild pointers. You need to make sure your stack remains the same IN to OUT of a function, whatever you do to the stack on the way IN, make sure you undo it before you come OUT.
The disadvantage to "Second" is you are not creating a stack frame, using EBP, so you will have a harder time accessing those parameters passed to it. For example, if you don't do any stack operations at all, the first parameter will be at [ESP + 08] (Because you have the return address pushed by the CALL (4 bytes), and you have the SUB ESP, 04 another 4 bytes). ANyway, the problem arises if you do any PUSH or POPS in this function. You never set up EBP as a base reference, so your only way to access parameters is with ESP - meanwhile if you are PUSHING and POPPING then ESP is changing all the time, which means your offsets to the parameters change. What a pain ! This is why it's best to set up the conventional stack frame, for your own sanity

Then all parameters and locals are offsets from EBP and stack operations do not affect you.
-nt20
fjrp2
June 28th, 2002, 19:10
Then, should a stack-frame be coded for EVERY called routine?
Would Second have to be like this:
Second: ;Enters with two arguments
push ebp
mov ebp,esp ;To access parqameters using BP
sub esp,04 ;reserve 1 local
mov [ebp-04],0 ;use local
.
.
.
push eax
pop eax
.
.
.
mov esp, ebp
pop ebp ;restore stack
sub esp,08 ;restore 2 arguments passed
ret
Do you think itīd work?
nikolatesla20
June 28th, 2002, 19:41
Your routine coded above is perfect.
That is exactly how you should do it !
-nt20
fjrp2
June 28th, 2002, 19:51
Thanx, but ALL the credits have to go to you.
Powered by vBulletin® Version 4.2.2 Copyright © 2018 vBulletin Solutions, Inc. All rights reserved.