Preserving eax and address of variables relative to stack

Started by Vortex, October 03, 2017, 06:18:49 AM

Previous topic - Next topic

Vortex

While pushing the address of variables relative to stack, the assembler uses the lea instruction destroying the content of eax :

lea     eax,var
push    eax


Inspired by GoAsm's method, I wrote a simple macro and modified my custom invoke macro to preserve eax while pushing the addresses to the stack :

push    ebp
sub     DWORD PTR [esp],offset_to_ebp


The @p macro calculates the offsets and this information is used by the custom invoke macro to pass the adress :

WinMain PROC hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD

    lcounter=0

    LOCAL @p(wc,WNDCLASSEX) : WNDCLASSEX
    LOCAL @p(msg,MSG) : MSG
    LOCAL @p(hwnd,DWORD) : DWORD


@p MACRO _name,_type

    lcounter=lcounter+SIZEOF(_type)

    @CatStr(<bytes>,<_name>) = lcounter

    EXITM <_name>

ENDM

jj2007

Interesting idea :t

00401095   ³.  55           push ebp
00401096   ³.  832C24 30    sub dword ptr [esp], 30              ; ÚpWndclassex => offset LOCAL.12
0040109A   ³.  E8 B8000000  call <jmp.&USER32.RegisterClassExA>  ; ÀUSER32.RegisterClassExA

mabdelouahab

 :t

@p MACRO _name,_type
    lcounter=lcounter+SIZEOF(_type)
    @CatStr(<bytes>,<_name>) = lcounter
    EXITM <_name : _type >
ENDM
...
LOCAL @p(wc,WNDCLASSEX) : WNDCLASSEX


Maybe better

jj2007

include \masm32\include\masm32rt.inc ; plain Masm32
include local.mac

.code
somecode proc argText, argTitle, argMode
Local_ rc:RECT, buffer[8]:BYTE, L1:DWORD, @ ; last arg marks end of locals
  mov L1, 12345678h
  mov rc.left, 11111111h
  mov rc.top, 22222222h
  mov rc.right, 33333333h
  mov rc.bottom, 44444444h
  ; int 3
  invoke_ lstrcpy, addr buffer, argText
  print hex$(L1), "h is the DWORD var", 13, 10
  print hex$(rc.left), "h is rc.left", 13, 10
  print hex$(rc.top), "h is rc.top", 13, 10
  print hex$(rc.right), "h is rc.right", 13, 10
  print hex$(rc.bottom), "h is rc.bottom", 13, 10
  invoke_ MessageBox, 0, addr buffer, argTitle, argMode
  ret_
somecode endp

start:
  print "let's do a little test", 13, 10
  invoke_ somecode, chr$("text567"), chr$("title"), MB_OK
  inkey "we are done here"
  exit

end start


00401029   ³.  CC           int3
0040102A   ³.  FF75 08      push dword ptr [ebp+8]               ; ÚSrc = "text567"
0040102D   ³.  55           push ebp                             ; ³
0040102E   ³.  830424 E8    add dword ptr [esp], -18             ; ³Dest => offset LOCAL.6
00401032   ³.  E8 11020000  call <jmp.&kernel32.lstrcpyA>        ; ÀKERNEL32.lstrcpy


Tested with MASM 6.14 and some others ;)

Vortex

Hi mabdelouahab,

Thanks for the modification. It looks like that I missed that notation.

Hi Jochen,

Nice work. Me too, I have a custom version of the LOCAL statement.

Biterider

Hi
@habran/johnsa: is there a way to get the offsets of local vars from ebp or another address, like the proc entry point?

Regards, Biterider

johnsa

Hi,

I don't believe so, we would need to implement some sort of operator for it, which isn't a bad idea.. perhaps something like:



myProc PROC
   LOCAL aVar:DWORD

   mov eax,STACKOFS(aVar)        ; if stackbase=ebp this is the offset relative to ebp post prologue, else esp.
   mov eax,[ebp+eax]   
   mov eax,[ebp+STACKOFS(aVar)]   

...



Biterider

Hi
Yes, I like the idea. I would suggest FRAMEOFS or LOCALOFS or something similar.


Biterider

johnsa


www.terraspace.co.uk/uasm242.zip

supporting FRAMEOFS operator. Can be used as follows in 32bit and 64bit :




main proc c aParam:dword
local   dwWritten:dword
local   hConsole:dword

mov eax,FRAMEOFS(dwWritten)
mov eax,[ebp+FRAMEOFS(hConsole)]
;for comparison
mov eax,hConsole
mov ebx,dwWritten
mov eax,FRAMEOFS(aParam)
mov eax,aParam



Vortex

Hi johnsa,

Thanks for the FRAMEOFS operator. It works fine with my custom invoke macro :

            IF ((OPATTR(@SubStr(%arg,5+1))) EQ 98) OR ((OPATTR(@SubStr(%arg,5+1))) EQ 34)

                add     DWORD PTR [esp],FRAMEOFS(@SubStr(%arg,5+1))



Biterider

Hi John
I tested FRAMEOFS with a standard prologue & epilogue and all work well.
In case of an non existing FRAME and you want to access hte proc parameters using esp, you have to decrement the offset by 4.


OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE


TestProc proc dArg1:DWORD, dArg2:DWORD
    mov eax, [esp + FRAMEOFS(dArg1)-4]
    mov edx, [esp + FRAMEOFS(dArg2)-4]
    ret
TestProc endp


OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef



Regards, Biterider


Biterider

#12
Hi John
Now I have to add 4 --> [esp + FRAMEOFS(Arg) + 4]
Attached the test file.
Biterider

johnsa

Hi,

Try again.. same URL for download.

The problem actually wasn't the FRAMEOFS but a bug in the proc handling itself. When FPO is on or there is no prologue, there should be no stack frame setup.. but the parameters were still using ebp/rbp instead of esp to reference. that is fixed and this now works 100%:



include c:\masm32\include\masm32rt.inc

.code                                               ;Begin Code segment
TestProc1 proto :DWORD, :DWORD
TestProc2 proto :DWORD, :DWORD

TestProc1 proc dArg1:DWORD, dArg2:DWORD
    local dLoc1:DWORD
    local dLoc2:DWORD
   
    mov dLoc1, 100h
    mov dLoc2, 200h

mov eax, dArg1
mov edx, dArg2

    mov eax, [ebp + FRAMEOFS(dArg1)]
    mov edx, [ebp + FRAMEOFS(dArg2)]

    mov eax, [ebp + FRAMEOFS(dLoc1)]
    mov edx, [ebp + FRAMEOFS(dLoc2)]
    ret
TestProc1 endp

OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

TestProc2 proc dArg1:DWORD, dArg2:DWORD
    mov eax, [esp + FRAMEOFS(dArg1)]
    mov edx, [esp + FRAMEOFS(dArg2)]
    mov eax, dArg1
    mov edx, dArg2
    ret
TestProc2 endp

OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef


start:                                              ;Program entry point
    invoke TestProc1, 1, 2
    invoke TestProc2, 3, 4

    invoke ExitProcess, 0                           ;Exit program returning 0 to Windows OS
end start                                           ;End of code and define the program entry point



I added a few extra regular movs just to check offsets/stack locations and values.

Biterider

Hi John
Perfect. No extra add/sub needed anymore!  :t
Biterider