News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Using ebp

Started by raleeper, June 23, 2007, 10:28:15 PM

Previous topic - Next topic

raleeper

I am using ebp inside a subroutine inside my windows procedure.

Naturally I save ebp and restore it before exiting this subroutine.

But I find I must restore it before invoking textout - and presumably any other API function.

I can do this, but I don't understand why the os needs the original ebp value, since it's going (I think) to create a new sub-stack and make new copies of all the parameters anyway.

Thanks.

    "Living within, but trying to understand, the rules"

hutch--

raleeper,

The use of EBP is almost exclusively done when a procedure isa written without a stack frame. In most instances the procedure has no local variables and gets its arguments directly off the stack (ESP). This is fine but you must be able to track the stack location if and when you use either PUSH or POP as this changes the current stack position.

There are a reasonable numvber of procedures in the masm32 library that are written without a stack frame. You can pick them by the OPTION PROLOGUE:NONE entry to the procedure.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

drizz

Quote from: raleeper on June 23, 2007, 10:28:15 PMBut I find I must restore it before invoking textout - and presumably any other API function.
Quote from: raleeper on June 23, 2007, 10:28:15 PMI can do this, but I don't understand why the os needs the original ebp value, since it's going (I think) to create a new sub-stack and make new copies of all the parameters anyway.
not true, the API functions do not depend on the previous value of ebp, they simply use ebp register as pointer to stack (preserving/restoring it at prologue/epilogue) or as work register (referencing arguments and local variables directly trough esp).

you probably just can't see the forest for the trees  :P
LOCAL ps:PAINTSTRUCT

invoke BeginPaint,hWnd,addr ps
invoke lstrlen,addr AppName
push ebp
xor ebp,ebp
invoke TextOut,ps.hdc,0,0,addr AppName,eax
pop ebp

in this code local variable "ps" is referenced by ebp. hence if you change ebp -> it will crash.
the solution is to not use ebp-referenced variables & arguments
LOCAL ps:PAINTSTRUCT

invoke BeginPaint,hWnd,addr ps
invoke lstrlen,addr AppName
mov edx,ps.hdc
push ebp
xor ebp,ebp
invoke TextOut,edx,0,0,addr AppName,eax
pop ebp



The truth cannot be learned ... it can only be recognized.

donkey

Quote from: raleeper on June 23, 2007, 10:28:15 PM
I am using ebp inside a subroutine inside my windows procedure.

Naturally I save ebp and restore it before exiting this subroutine.

But I find I must restore it before invoking textout - and presumably any other API function.

I can do this, but I don't understand why the os needs the original ebp value, since it's going (I think) to create a new sub-stack and make new copies of all the parameters anyway.

Thanks.

    "Living within, but trying to understand, the rules"

There is only one stack per process and no new "sub-stack" is created. The process stack is used and as explained by drizz the value of EBP must be preserved for local parameters (though usually not local variables) and for all calls outside your procedure, after all an API call is simply another procedure call as far as the CPU is concerned and EBP is used to point to the top of the stack (the new bottom) when its stack frame is built. If you must use EBP it is best not to call any procedure outside of its preservation scope while using it and avoid the use of local parameters, even better is to find a way not to use it, it will prove less complicated.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

raleeper

Using WinDbg to look at the first few instructions of TextOut (to see if it was using the entry value of ebp) I found something curious.

The first few instructions are (if my assumptions are right):

mov edi, edi
push ebp
mov ebp, esp

So it is not immediately overwriting ebp and may be using its value later.

But what about that mov edi, edi?

Can this have any purpose other than to reserve two bytes, possibly to allow for a short jump to be put there later by the os or an application?

Maybe if you poke in the right bytes it will tell you you've won a million dollars, or do something less benign.

drizz

Quote from: raleeper on June 24, 2007, 08:48:28 PM
Using WinDbg to look at the first few instructions of TextOut (to see if it was using the entry value of ebp) I found something curious.

The first few instructions are (if my assumptions are right):

mov edi, edi
push ebp
mov ebp, esp

So it is not immediately overwriting ebp and may be using its value later.
as i said, ebp is preserved, it doesn't use its value, "push ebp; mov ebp, esp" is part of the prologue code.

Quote from: raleeper on June 24, 2007, 08:48:28 PMBut what about that mov edi, edi?

Can this have any purpose other than to reserve two bytes, possibly to allow for a short jump to be put there later by the os or an application?
exactly, the term is hot patching

btw, did my suggestion help you solve your problem? if not could you paste the winproc code?
The truth cannot be learned ... it can only be recognized.

donkey

Quote from: raleeper on June 24, 2007, 08:48:28 PM
Using WinDbg to look at the first few instructions of TextOut (to see if it was using the entry value of ebp) I found something curious.

The first few instructions are (if my assumptions are right):

mov edi, edi
push ebp
mov ebp, esp

So it is not immediately overwriting ebp and may be using its value later.

But what about that mov edi, edi?

Can this have any purpose other than to reserve two bytes, possibly to allow for a short jump to be put there later by the os or an application?

Maybe if you poke in the right bytes it will tell you you've won a million dollars, or do something less benign.


Maybe they use the value FF89h in the function and store it there. There is no way to tell without examining the function as a whole why they might have an instruction like mov edi,edi. I will occasionally use an instruction for a value if I want to obfuscate my code a bit, it is an old and largely ineffective method. I once used ADD AL, 1 to store MAX_PATH in order to obfuscate a buffer size, pretty lame but it was something to try.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

raleeper

Quote from: drizz on June 24, 2007, 10:07:48 PM

btw, did my suggestion help you solve your problem? if not could you paste the winproc code?

Well, I see the point and I appreciate that, but I don't understand the particulars - You say:

    Code:
    LOCAL ps:PAINTSTRUCT

    invoke BeginPaint,hWnd,addr ps
    invoke lstrlen,addr AppName
    push ebp
    xor ebp,ebp
    invoke TextOut,ps.hdc,0,0,addr AppName,eax
    pop ebp
    in this code local variable "ps" is referenced by ebp. hence if you change ebp -> it will crash.

But I don't see that ps is referenced by ebp.

Anyway, I'm going to follow your advice:

    the solution is to not use ebp-referenced variables & arguments,

at least until I have a better grip on what's going on.

donkey

Why wouldn't ps be addressed by EBP ? There is no reason for it not to be after all any position on the local stack for the procedure can be expressed as relative to EBP. With GoAsm local variables are called by their offset from EBP, for example...

--------------------
Calling procedures stack
--------------------
parameter4 [EBP+20]
parameter3 [EBP+16]
parameter2 [EBP+12]
parameter1 [EBP+8]
Return address [EBP+4]
-------------------
Old value of EBP [EBP]
Local vars [EBP-4],[EBP-8],[EBP-12],[EBP-16],etc...
-------------------


I am not quite sure which MASM uses but even if it does not use EBP to address locals you cannot rely on a quirk in the compiler to protect your code, if you do you are bound to find it crashing one day.

Donkey
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

It only depends on whether you use a stack frame or not. With no stack frame the first arg is at [esp+4], if a stack frame is used it is at [ebp+8].
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

MichaelW

Quote from: raleeper on June 24, 2007, 08:48:28 PM
But what about that mov edi, edi?

I don't know if this is the reason, but ML uses mov edi, edi as a 2-byte nop:

http://www.masm32.com/board/index.php?topic=1622.0

eschew obfuscation

donkey

Quote from: hutch-- on June 25, 2007, 01:23:12 PM
It only depends on whether you use a stack frame or not. With no stack frame the first arg is at [esp+4], if a stack frame is used it is at [ebp+8].

Hi Hutch,

Since ps was declared as LOCAL there is no choice but to have a stack frame, but yes, the offsets change if no frame is used the may also change in some assemblers if you preserve any registers as they may be pushed onto the stack prior to adjusting EBP.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

tenkey

Quote from: raleeper on June 25, 2007, 01:24:01 AM
But I don't see that ps is referenced by ebp.

Anyway, I'm going to follow your advice:

the solution is to not use ebp-referenced variables & arguments,

at least until I have a better grip on what's going on.
To restate what donkey said:

When you use PROC, the PROC arguments and every LOCAL within the PROC will be referenced by EBP.

The reason is that both arguments and the locals are part of the current stack frame, and every data in the stack frame is referenced by EBP by default. MASM will create the EBP address mode for you. If you want to access the arguments or locals without EBP, you will need to, as hutch says, use ESP.
A programming language is low level when its programs require attention to the irrelevant.
Alan Perlis, Epigram #8

drizz

Quote from: raleeper on June 25, 2007, 01:24:01 AMBut I don't see that ps is referenced by ebp.
let me explain a little better.

;; func called at WM_PAINT
OnPaint proc hWnd:HWND
LOCAL ps:PAINTSTRUCT
int 3
invoke BeginPaint,hWnd,addr ps
invoke SetBkMode,ps.hdc,TRANSPARENT
invoke lstrlen,addr AppName
push ebp
xor ebp,ebp
invoke TextOut,ps.hdc,0,0,addr AppName,eax
pop ebp
invoke EndPaint,hWnd,addr ps
ret
OnPaint endp

i don't use WinDbg but i will try to paste some code from it
windbg disassembly (read comments):

00401000 55               push    ebp;;  \ prologue code
00401001 8bec             mov     ebp,esp;;  /
00401003 83c4c0           add     esp,0xffffffc0;; / allocate space forl locals == "PAINTSTRUCT"
00401006 cc               int     3;; break for windbg
00401007 8d45c0           lea     eax,[ebp-0x40];; load effective address of "ps"
0040100a 50               push    eax
0040100b ff7508           push    dword ptr [ebp+0x8];; hWnd,, as you can see arguments are also refferenced by ebp
0040100e ff1538204000     call    dword ptr [image00400000+0x2038 (00402038)];;BeginPaint
00401014 6a01             push    0x1
00401016 ff75c0           push    dword ptr [ebp-0x40]
00401019 ff1500204000     call    dword ptr [image00400000+0x2000 (00402000)];;SetBkMode
0040101f 680d304000       push    0x40300d
00401024 ff150c204000     call    dword ptr [image00400000+0x200c (0040200c)];;lstrlen
0040102a 55               push    ebp;; Now pay attention
0040102b 33ed             xor     ebp,ebp;; you change the ebp register
0040102d 50               push    eax
0040102e 680d304000       push    0x40300d
00401033 6a00             push    0x0
00401035 6a00             push    0x0
00401037 ff75c0           push    dword ptr [ebp-0x40];; but when you access local variables through ebp -> crash
;; ebp+something might actually point to a valid memory so it will not crash right here but inside TextOut
;; you can't see that ebp is used because you use local variable names !!!!
;; thats why i wrote "mov edx,ps.hdc" in the second code snippet
0040103a ff1504204000     call    dword ptr [image00400000+0x2004 (00402004)];;TextOut
00401040 5d               pop     ebp
00401041 8d45c0           lea     eax,[ebp-0x40]
00401044 50               push    eax
00401045 ff7508           push    dword ptr [ebp+0x8]
00401048 ff153c204000     call    dword ptr [image00400000+0x203c (0040203c)]
0040104e c9               leave;;\epilogue code
0040104f c20400           ret     0x4;;/

The truth cannot be learned ... it can only be recognized.

raleeper

Quote from: drizz on June 25, 2007, 07:58:06 PM
let me explain a little better.

;; func called at WM_PAINT
OnPaint proc hWnd:HWND
LOCAL ps:PAINTSTRUCT
int 3
invoke BeginPaint,hWnd,addr ps


[/quote]


OK, I see.  I appreciate all the trouble you went to.

I'll have to think this through in more detail, but the critical point I missed about your code was that it was all inside a procedure that uses a stack frame for local variables - as of course all of mine is, since it is all in my windows procedure.

Thanks.