News:

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

how to insert opcodes directly into .code segment

Started by allynm, June 20, 2011, 06:26:00 PM

Previous topic - Next topic

allynm

Hi again JJ and 'dave

JJ:  Having spent the afternoon perusing masmbasic.inc I now see why I was really grossly misunderstanding the meaning of "basic" in your MasmBasic package.  I believe I owe you an apology!  If you have a moment or can direct me to a relevant link I would like to understand better the origin of MASMBASIC and how to use its many macros!  Is there a primer/tute around that documents them?

'dave:  As always:  Thanks.  I sometimes wonder why you and the other experts assembled here are willing to put up with my naivete.

Regards,
Mark

dedndave

 :bg
thanks, but i have much to learn before i am in the same zip-code as "expert"   :P

jj2007

Quote from: allynm on June 26, 2011, 09:19:07 PM
I would like to understand better the origin of MASMBASIC and how to use its many macros!  Is there a primer/tute around that documents them?

Mark,
Thanks for the flowers :bg
The origin is that I needed a 32-bit dialect that resembles 16-bit GfaBasic. The tutor is \masm32\MasmBasic\MbGuide.rtf, which can be opened in WordPad or \masm32\RichMasm\RichMasm.exe. Let me know if you need more.

allynm

Hi 'dave,

I'm still studying the code you sent in your zipfile.  It's short but extremely subtle for a beginner like me.  The code ran fine, btw.  I have two questions:

In the MAIN_PROC why do you push eax and pop edx after the call to VirtualProtect?  What is happening that requires these instructions.  I can see you are using esp for its address to the code segment, but I can't see why this requires the push/pop.

Thanks,
Mark

dedndave

the VirtualProtect function wants to write a dword to memory that represents the previous attribute for the block
we have no need of that value, so it's "discardable"

you could do it this way...
PrevAttr dd ?
;
;
;
        INVOKE  VirtualProtect,Dest,1024,PAGE_EXECUTE_READWRITE,offset PrevAttr


that method wastes about 6 bytes, because we do not intend to restore the previous setting   :P

as for PUSH EAX and POP ECX - any register will do - i just like to keep the stack balanced

jj2007

       push    eax
       INVOKE  VirtualProtect,Dest,1024,PAGE_EXECUTE_READWRITE, esp
       pop     edx


Old elegant trick: The last para is out  PDWORD lpflOldProtect
Dave creates a dword variable with push eax, .i.e. the stack decreases by 4, then esp = lpflOldProtect is being pushed as first para by the invoke macro; when that is finished, you just pop the return value OldProtect into a register, in this case edx.

dedndave

it works great when it's the last parameter for INVOKE
each INVOKE parameter that gets pushed changes the ESP register
so, if it is not the last parm, you have to do something like this...
        push    eax
        mov     edx,esp
        INVOKE  SomeFunction,edx,Parm2
        pop     ecx


things may go nuts if you try to use ESP to point to parm2   :P
        INVOKE  SomeFunction,esp,Parm2
:naughty:

allynm

Hi JJ and 'Dave,

I think I understand what you are both saying.  What is confusing to me is the stack balancing bit.  I thought that INVOKE took care of cleaning up the stack and keeping it balanced.  Did I get this wrong?  It's obviously a non-trivial bit of ignorance I am wandering about with.  If we don't care about the OldProtect, then why are we popping/pushing anything?  Why don't we just go straightaway to INVOKE VirtualProtect, blah, blah, blah, blah?  I can see how if you push eax you need to pop to something (why not eax?) after the INVOKE macro gets finished cleaning up to keep it balanced, but since we don't care about OldProtect, then why bother pushing eax in the first place? Maybe I need to get Olly out and watch exactly what's happening.

JJ:  Thanks for alerting me to MbGuide--just what I had in mind.  Needed it to understand what your program (reference #6, I believe) was doing.

BTW, I already have used JJ's solution to discover that RET is 0C3h in 'Dave's code....very very cool!

Thanks,
Mark

dedndave

ok - sorry to have confused you, but it's good to learn from, anyways
as i said before, you CAN go straight to INVOKE...
PrevAttr dd ?
;
;
;
        INVOKE  VirtualProtect,Dest,1024,PAGE_EXECUTE_READWRITE,offset PrevAttr


have a look at the MSDN docs for VirtualProtect
http://msdn.microsoft.com/en-us/library/aa366898%28v=vs.85%29.aspx

as you can see, it requires 4 parameters
the last parameter is defined as follows:
QuotelpflOldProtect [out]
A pointer to a variable that receives the previous access protection value of the first page in the
specified region of pages. If this parameter is NULL or does not point to a valid variable, the function fails.

so, you can create a dword variable and pass the address of it to the function as shown above
however, we do not care what the value is - we have no  need to store it for future use, in this case
so, we can save a few bytes by creating a temporary (LOCAL) variable on the stack and pass a pointer to that
if we wanted to, we could use LOCAL to create it
however, that requires the initialization of EBP as a stack frame pointer

it is just a shortcut
we PUSH a dword register onto the stack
that is a single byte instruction and fast, too
it does not matter which register we use - we just want a dword space on the stack
at that point, the stack pointer (ESP) holds the address of the dword space we just created
it's very convenient - we reserved space - and we have a pointer to it in a register
and we did all that with a fast single-byte instruction

when we use INVOKE...
        INVOKE  SomeFunction,Parm1,Parm2,Parm3
the assembler generates code that actually looks something like this...
        push    Parm3
        push    Parm2
        push    Parm1
        call    SomeFunction


if we had created a dword in the data segment and pushed the address, that would be a 5-byte PUSH (1 byte instruction, 4-byte address)
but, because the address we want to pass is in register, it is a single byte
        INVOKE  SomeFunction,Parm1,Parm2,esp
        push    esp
        push    Parm2
        push    Parm1
        call    SomeFunction


now - you are correct in that the StdCall convention will balance the stack for us
that means that the 3 parameters will be automatically discarded when the function returns

however, we pushed a dword onto the stack ourselves - that needs to be balanced out
so, we pop it into a register - again, a single byte instruction
if we wanted to use the value immediately, we can use the same technique
the value filled in by the function is now in whichever register we elected to POP it into

so, it saves some space in the data segment (4 bytes)
and it saves some space in the code segment (2 bytes)

you can use the same method to retrieve values quickly
i use the technique quite often for WriteFile and ReadFile for the NumberOfBytes parameter

here is another example...
the QueryPerformanceCounter function requires a pointer to a QWORD (8 byte) variable
quite often, we want the value in registers, rather than in some memory location
so - we can use the same deal....
        push    edx
        push    eax
        INVOKE  QueryPerformanceCounter,esp
        pop     eax
        pop     edx

now, the qword value is in EDX:EAX   :bg

it also comes in handy for GetProcessAffinityMask, as well as several other functions


allynm

Hi 'Dave,

Thank you for your detailed explanation of what's going on.  The new things you taught me about the stack in this tutorial are very useful, but it was also reassuring to know that INVOKE does what I thought it did.  Whew!

I didn't know about the VirtualProtect API until you brought it up.  I looked it over on MSDN Library last night but for some reason the discussion there is quite abstact and hard to associate with this particular application (or any other, for that matter). 

Regards,
Mark

dedndave

well - the windows operating system places different access priviledge flags on different sections of the EXE
for example, the CONST section is read-only
the DATA and DATA? sections are read-write, no execute
the CODE section is execute only (or maybe read/execute)

if you violate these "rules" it raises an exception and crashes the program
i am sure you have seen the little Dr Watson windows   :P

in order to alter the priviledge level for a specific block of memory, you can use VirtualProtect
we want to write into the CODE section, so we can alter the setting for a block
the access is controlled in "pages", which means if you alter 1 byte of memory,
you alter the priviledge for the entire page that it is in
memory is organized in pages of 4 kB, each

another way to go is to modify the EXE PE header and set the flags for that section
that is messy, and is not as secure - but it can be done

allynm

Good morning, 'Dave and JJ2007:

'Dave:  OK, I didn't realize that this was what VirtualProtect does.  Clear enough, now that you've conneted the dots for me.  BTW, looked on OLLY and the .code section for your CopyCode proc is RE.  So, if you had chosen to write in the .data block there would be no need for this function.

JJ:  In your modified MasmBasic approach you use a jmp@F- @@F pair to go round the code snippet in the MAIN proc whose opcodes you want to read and print.  I don't understand why you need to do this jump around the around the ciao-bye labels.  I apologize for not having tested your code and observing it on OLLY before asking the question.

Regards,
Mark

jj2007

Quote from: allynm on June 28, 2011, 12:41:15 PM
JJ:  In your modified MasmBasic approach you use a jmp@F- @@F pair to go round the code snippet in the MAIN proc whose opcodes you want to read and print.  I don't understand why you need to do this jump around the around the ciao-bye labels.

Mark,

My editor has the bad habit to assemble, link and run the code when I hit the magic button. So it would run right into db "Ciao", which according to Olly means imul esp, [ecx+6F], -17AE8496 to the CPU... that's why I prefer to isolate this section with a little jmp :bg

   jmp @F
   db "Ciao"
   fild word ptr [esp]
   fldpi
   fmulp
   fistp word ptr [esp]
   db "Bye#"
@@:

allynm