Link to home
Start Free TrialLog in
Avatar of aerelorn
aerelorn

asked on

Calling inline assembly directly

Howdy,

Basically, I need a way to get the memory address of the first instruction in an __asm block.  Here's an example of what I'm talking about:

void ThisFunctionNeverGetsCalledDirectly()
{
  __asm
  {
     mov eax, 1
     add eax, 2
     jmp MEMADDRESS
  }
  printf("This never gets executed because the asm block jumps back to where it was called from");
}

Basically, at runtime I'm going to change the instruction at MEMADDRESS-1 to jmp to the first statement, "mov eax, 1"(obviously just a placeholder for now).  The rest of the asm block runs, then jmps back to MEMADDRESS and the program will proceed as normal.

The only problem is I need to find the address of that first instruction in order to make the jmp to it.  I don't want to call ThisFunctionNeverGetsCalledDirectly() because __asm modifies all the registers, the stack pointer,etc.  The point is I want the assembly code to execute seamlessly as though it actually existed between MEMADDRESS-1 and MEMADDRESS.

Thanks for the help.
Avatar of AlexFM
AlexFM

This is not fixed address, function is allocated on stack. Possibly this is [ESP], but all your idea looks strange, try to describe what you want to do. Maybe thete are another ways.
Why don't you want to use label:

__asm
{
start:
    mov eax, 1
    add eax, 2
    jmp start
}
HGLOBAL WINAPI MyGlobalAlloc(UINT uFlags, SIZE_T dwBytes)
{
    PDWORD pRetAddr = (PDWORD)((&pRetAddr) + 2);
    pRetAddr = (PDWORD)*pRetAddr;
}

pRetAddr is the return address.
But don't forget to clear the stack before jmp.
Some kind of protection code?
Good luck.
ASKER CERTIFIED SOLUTION
Avatar of grg99
grg99

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi grg99,
I forgive you "the valiant attempts" and remind you again - take your points here:

http://oldlook.experts-exchange.com/questions/20766073/Points-for-grg99.html

Good luck.
>> //  printf("This never gets executed because the asm block jumps back to where it was called from");

This would never get called anyway because it is commented out. :-)

Sorry grg99, I couldn't resist.
Exceter
>Hi grg99,
>I forgive you "the valiant attempts" and remind you again - take your points here:

>http://oldlook.experts-exchange.com/questions/20766073/Points-for-grg99.html

>Good luck.

The EE user interface being like it is, I don't see any hint or button on that question that says "TAKE YOUR POINTS".
Also it's a bit curious why one would have to TAKE one's points.  You'd think that could be done automatically.


>> The EE user interface being like it is, I don't see any hint or button on that question that says "TAKE YOUR POINTS".

It says that in the question title.

>> Also it's a bit curious why one would have to TAKE one's points.  You'd think that could be done automatically.

I won't get into it here but, if you are interested, you can create a thread in referecne to this in the expert input TA.

Exceter
>> The EE user interface being like it is, I don't see any hint or button on that question that says "TAKE YOUR POINTS".

>It says that in the question title.

I know it says that.... but HOW, Fawlty, HOW?  

I know, it was posted at the Town Hall, in the barricaded bathroom in the basement,
in the filing cabinet with "STAY OUT. RABID COUGAR" emblazened.

 

>> I know it says that.... but HOW, Fawlty, HOW?  

All you have to do is post. AlexFM will then accept your comment as the answer to the question. It's been standard proceedure around here for quite awhile.

Exceter
void ThisFunctionNeverGetsCalledDirectly()
{
 __asm
 {
  Here:
    mov eax, 1
    add eax, 2
    lea ebx, Here
    jmp [ebx]
 }
 printf("This never gets executed because the asm block jumps back to where it was called from");
}
Avatar of aerelorn

ASKER

Okay, evidently I haven't explained this well enough.  I posted it right before I went to bed hoping to have an answer by morning, but I was too tired to be clear.  Please ignore everything I said above, it wouldn't work.

Here's what I'm starting with.  This is code in my executable.  The memory address(for this example 0040000) is found after my program loads:

00400000  MOV EAX,DWORD PTR SS:[ESP+2C]
00400004  ADD EAX,10h
00400007  PUSH EAX

What I want to do is execute a block of instructions seamlessly between the ADD and the PUSH.  I figured I could do this by overwriting the original instructions like so:


00400000  NOP
00400001  NOP
00400002  JMP SOMEMEMORYADDRESS
00400007  PUSH EAX

SOMEMEMORYADDRESS+0 MOV EAX,DWORD PTR SS:[ESP+2C]
SOMEMEMORYADDRESS+4 ADD EAX,10h
SOMEMEMORYADDRESS+7 Insert my code here
SOMEMEMORYADDRESS+X jmp 00400007


Right now the only way I can think to do this is to:

1. Reserve an area of memory for my custom code
2. Copy a hand-assembled version of the code to that location
3. Set the final instruction, "JMP 00400007" because 00400007 isn't known at compile time(like I thought when I initially posted)
4. Overwrite the original memory with the 2 NOP's and the JMP to the reserved mem area


That should work(if it won't, somebody please correct me).  The part I'm trying to avoid is the hand-assembled part.  I was hoping there's some way I can trick the compiler into doing it for me.

Hopefully this is a bit clearer.
I went and re-read the previous comments, and am thinking that the following modification of  grg99's code would work.  


void ThisFunctionReturnsTwoPointers(void* Begin, void* End)
{
  __asm
  {
    lea  Begin,BeginLabel
    lea  End,EndLabel
    jmp  Ret

BeginLabel:
     mov EAX,DWORD PTR SS:[ESP+2C]
     add EAX,10h
     mov eax, 1
     add eax, 2
     //more of my code here
EndLabel:

Ret:
  }
}


In my main program:

#define JMP 0xE9
#define NOP 0x90

DWORD ReturnAddress,Temp;
void* Mem,Begin,End;
DWORD Length;
BYTE jmp=JMP;
BYTE nop=NOP;

ReturnAddress = GetReturnAddress();              //this would be the 00400007 from above
ThisFunctionReturnsTwoPointers(Begin, End);       //gets begin and end of asm block
Length = (DWORD)Begin - (DWORD)End;
Mem = malloc(Length + 5);
CopyMemory(Mem, Begin, Length);              //copy the asm code to my reserved block
CopyMemory(Mem + Length, (void*)&jmp, 1);       //add the jmp code
CopyMemory(Mem + Length + 1, (void*)&ReturnAddress, 4); //add the jmp address

//change original code
CopyMemory((void*)(ReturnAddress - 7), (void*)&nop, 1);
CopyMemory((void*)(ReturnAddress - 6), (void*)&nop, 1);
CopyMemory((void*)(ReturnAddress - 5), (void*)&jmp, 1);
Temp=(DWORD)Begin;
CopyMemory((void*)(ReturnAddress - 4), (void*)&Temp, 4);



Could someone look over this and confirm that it would work and does what I want?
Okay, I was able to get a variant on what's above working.  Thanks grg99, I didn't know lea could be used on labels like that.
grg99,

In the question you helped me I wrote: take your points here... and you could read this after receiving e-mail notification. Possibly you missed this e-mail or didn't read my comment. Usually this works without adding any special features to EE.
By the way, I saved this page and will read it carefully to improve my rudimentary Assembly knowledge.
I'm not sure if you'll read this again AlexFM, but if you do here's the final version of the code so you can see how it all fit together:

#define JMP 0xE9
#define NOP 0x90
#define REPLACEADDR 0x0050D5DD
#define RETADDR 0x0050D5F6

void SetupFunction()
{
      DWORD BeginLabel,EndLabel;
      __asm
      {
            lea  eax,BeginLabel
            mov  Begin,eax
            lea  eax,EndLabel
            mov  End,eax
                jmp  EndLabel

            BeginLabel:
            mov eax,DWORD PTR SS:[ESP+0x2C]      
            add eax,10h
            //more of my code here
            nop  //placeholders for jmp
            nop  //placeholders for jmp
            nop  //placeholders for jmp
            nop  //placeholders for jmp
            nop  //placeholders for jmp
            EndLabel:
      }
      DWORD ReplaceAddr,RetAddr,Length;
      long Offset;
      BYTE jmp=JMP,nop=NOP;

      RetAddr=RETADDR;
      ReplaceAddr=REPLACEADDR;
      Length=End-Begin;

      hProcess=OpenProcess(PROCESS_ALL_ACCESS,false,hProcessId);

      Offset=RetAddr-(Begin+Length);
        //add jmp instruction
      WriteProcessMemory(hProcess,(void*)(Begin+Length-5),(void*)&jmp,sizeof(jmp),NULL);
       
       //add the jmp address
       WriteProcessMemory(hProcess,(void*)(Begin+Length-4),(void*)&Offset,sizeof(Offset),NULL);

      //change original code
      Offset=Begin-ReplaceAddr;
      WriteProcessMemory(hProcess,(void*)(ReplaceAddr-7),&nop,sizeof(nop),NULL);
      WriteProcessMemory(hProcess,(void*)(ReplaceAddr-6),&nop,sizeof(nop),NULL);
      WriteProcessMemory(hProcess,(void*)(ReplaceAddr-5),&jmp,sizeof(jmp),NULL);
      WriteProcessMemory(hProcess,(void*)(ReplaceAddr-4),&Offset,sizeof(Offset),NULL);
}

void ClearFunction()
{
      DWORD ReplaceAddr;
      ReplaceAddr=REPLACEADDR;
      WriteProcessMemory(hProcess,(void*)(ReplaceAddr-7),(void*)(Begin+1),7,NULL);
}

Cheers.
Thanks.