Hi everyone.  I've come across some odd behaviour when attempting to use local variables using masm.  I've no doubt that the solution is trivial and I've just misunderstood some basic principle, but I've played with this all morning and can't seem to figure it out.

I'm attempting to change the access of a certain page in memory.  When I use the following code, VirtualProtect fails and GetLastError reports ERROR_NOACCESS:


xormem proc pMemory:DWORD, nSize:DWORD, nByte:BYTE
LOCAL pOldProtect:DWORD
push pOldProtect ;<-- Points to the RETN of the previous function (the last instruction prior to the xormem function)
push PAGE_EXECUTE_READWRITE
push nSize
push pMemory
call VirtualProtect
...
...
...
xormem endp


OllyDbg showed that the pOldProtect variable points to the end of the procedure that precedes my xormem function.  When I insert a dummy dword local variable (as shown below), the VirtualProtect call succeeds and the old protection variable is stored where it should be.


xormem proc pMemory:DWORD, nSize:DWORD, nByte:BYTE
LOCAL pDummy:DWORD
LOCAL pOldProtect:DWORD
push pOldProtect ;<-- Points to the stack (where it should)
push PAGE_EXECUTE_READWRITE
push nSize
push pMemory
call VirtualProtect
...
...
...
xormem endp


Questions:

- Does this have anything to do with alignment?  I'm aware that some code requires dword alignment and one of the parameters I'm passing to the procedure is BYTE.
- Why does the second example succeed whereas the first one fails?

Any help would be greatly appreciated,

Tim
Posted on 2008-09-18 22:08:39 by Timbo
Shouldn't that be
push ADDR pOldProtect

since it is a pointer to a dword whereas your code pushes the dword, which could be anything.
Posted on 2008-09-18 22:24:06 by sinsi
Thanks for the reply.


Shouldn't that be
push ADDR pOldProtect

since it is a pointer to a dword whereas your code pushes the dword, which could be anything.


When I add the ADDR keyword, I receive the following error when assembling:

error A2008: syntax error : ADDR

As I mentioned in my original post, the second code sample I provided works perfectly (and with out the addition of the ADDR keyword).  I'd just like to know why I need the dummy local variable for the call to VirtualProtect to succeed.
Posted on 2008-09-18 22:30:12 by Timbo
Sorry, ADDR works with INVOKE. If you're pushing manually you need
  lea eax,pOldProtect ; LEA EAX,
  push eax

Posted on 2008-09-18 23:20:02 by sinsi
Thanks sinsi, worked like a charm.

As a test I used the INVOKE syntax and examined the disassembly using ollydbg, which revealed the lea eax, and the push eax instructions.  I should've done that in the first place and saved myself the hassle!
Posted on 2008-09-18 23:41:33 by Timbo
Any time a function needs the address of a local variable you need to do the lea/push thing - that's what invoke does for you (as long as the proto definition is OK).
Posted on 2008-09-19 00:04:59 by sinsi
Yup. Otherwise you're pushing the value of the variable, not its address. And you can't use "addr" because you can't know the address of the variable at compile-time.
Posted on 2008-09-19 03:21:15 by ti_mo_n
It would be nice if the assembler said "oh, you used addr apon a Local variable, I'll just write the LEA code for you".
Posted on 2008-09-19 04:19:51 by Homer
HLLs do that for you ;)
Posted on 2008-09-19 06:56:07 by ti_mo_n
My code is now working (thanks to all the replies!) but I'm still curious as to why the second example works whereas the first one fails.  Any ideas?
Posted on 2008-09-19 07:11:54 by Timbo
Of course. You are supposed to pass the address of the memory as a parameter to the function, yet you pass the data instead.

lea eax, means the same as eax = value of ebp - 4
What you did was push the data in to the stack
Posted on 2008-09-19 07:29:17 by roticv