Messing with a stack in assembly and C ++

I want to do the following:

I have a function that is not mine (this is really not important here, but just to say that I do not control it), and that I want to fix it to call my function, keeping a list of arguments (the transition is not an option).

What I'm trying to do is to put the stack pointer, as it was before this function is called, and then call mine (for example, go back and do the same, but with a different function). This does not work directly because the stack is getting corrupted. I believe that when I make a call, it replaces the return address. So, I took a step to save the return address by storing it in a global variable, and it works, but thatโ€™s not normal, because I want it to resist recursion, and you know what I mean. Anyway, I'm new to the assembly, so I'm here.

Please do not tell me about programs already done to do this, because I want to do everything my own way.

Of course, this code must be independent of the compiler and optimization.

My code (if it is more than acceptable, tell me how to place it):

// A function that is not mine but to which I have access and want to patch so that it calls a function of mine with its original arguments void real(int a,int b,int c,int d) { } // A function that I want to be called, receiving the original arguments void receiver(int a,int b,int c,int d) { printf("Arguments %d %d %d %d\n",a,b,c,d); } long helper; // A patch to apply in the "real" function and on which I will call "receiver" with the same arguments that "real" received. __declspec( naked ) void patch() { _asm { // This first two instructions save the return address in a global variable // If I don't save and restore, the program won't work correctly. // I want to do this without having to use a global variable mov eax, [ebp+4] mov helper,eax push ebp mov ebp, esp // Make that the stack becomes as it were before the real function was called add esp, 8 // Calls our receiver call receiver mov esp, ebp pop ebp // Restores the return address previously saved mov eax, helper mov [ebp+4],eax ret } } int _tmain(int argc, _TCHAR* argv[]) { FlushInstructionCache(GetCurrentProcess(),&real,5); DWORD oldProtection; VirtualProtect(&real,5,PAGE_EXECUTE_READWRITE,&oldProtection); // Patching the real function to go to my patch ((unsigned char*)real)[0] = 0xE9; *((long*)((long)(real) + sizeof(unsigned char))) = (char*)patch - (char*)real - 5; // calling real function (I'm just calling it with inline assembly because otherwise it seems to works as if it were un patched // that is strange but irrelevant for this _asm { push 666 push 1337 push 69 push 100 call real add esp, 16 } return 0; } 

Seal (and should):

Arguments 100 69 1337 666

Edit:

The code I'm testing after Vladโ€™s suggestion (still not working)

 // A patch to apply in the real function and on which I will call receiver with the same arguments that "real" received. __declspec( naked ) void patch() { _asm { jmp start mem: nop nop nop nop start : // This first two instructions save the return address in a global variable // If I don't save and restore the program won't work correctly. // I want to do this without having to use a global variable mov eax, [ebp+4] mov mem, eax push ebp mov ebp, esp // Make that the stack becomes as it were before the real function was called add esp, 8 // Calls our receiver call receiver mov esp, ebp pop ebp // Restores the return address previously saved mov eax, mem mov [ebp+4],eax ret } } 
+6
assembly hook
source share
4 answers

The following code snippets have been tested with mingw-g ++, but should work in VC ++ with minor changes. Complete sources available with Launchpad: 1

The only way to safely store data associated with a particular call is to save it on the stack. One way is to rotate part of the stack.

patch.s excerpt (patchfun-rollstack):

 sub esp, 4 # allocate scratch space mov eax, DWORD PTR [esp+4] # first we move down mov DWORD PTR [esp], eax # our return pointer mov eax, DWORD PTR [esp+8] # then our parameters mov DWORD PTR [esp+4], eax mov eax, DWORD PTR [esp+12] mov DWORD PTR [esp+8], eax mov eax, DWORD PTR [esp+16] mov DWORD PTR [esp+12], eax mov eax, DWORD PTR [esp+20] mov DWORD PTR [esp+16], eax mov eax, DWORD PTR [esp] # save return pointer mov DWORD PTR [esp+20], eax # behind arguments add esp, 4 # free scratch space call __Z8receiveriiii mov eax, DWORD PTR [esp+16] # restore return pointer mov DWORD PTR [esp], eax ret 

Here we omitted ebp . If we add this, we will need to use 8 bytes of scratch space and save and restore ebp as well as eip . Note that when restoring the returned pointer, we overwrite parameter a . To avoid this, we will need to rotate the stack again.


Another way is to inform the caller about additional data in the stack and ignore it.

patch.s (patchfun-ignorepointers):

 push ebp mov ebp, esp call receiver leave ret 

receiver.cc:

 void receiver(const void *epb, const void *eip, int a,int b,int c,int d) { printf("Arguments %d %d %d %d\n",a,b,c,d); } 

Here I have included epb, if you remove it from asm, all that remains is call and ret , and the receiver will only have to accept and ignore eip .


Of course, all this is mainly for pleasure and curiosity. On the contrary, there is no simple advantage over a simple solution:

 void patch(int a,int b,int c,int d) { receiver(a,b,c,d); } 

The generated assembly will be shorter than our stack, but it will take another 16 bytes of the stack, because the values โ€‹โ€‹are copied to a new area below the patch() frame frame.

(Actually, the gcc-generated asm allocates 28 bytes on the stack, although it only uses 16. I'm not sure why. Perhaps the extra 12 bytes are part of some kind of stack stack protection scheme.)

+2
source share

You have once add esp, 8 and once add esp, 16 . One of them must be wrong.

Edit:
Oh, I see, after add esp, 8 you must remove the 2 instructions pressed from the ebp stack and return the address.

In [ebp + 4] there should be a return address for the _tmain call.

Edit2:
you can highlight the "internal" variable as follows:

  call next dd 0 next: pop eax mov [eax], yourinfo 

But it is still unclear why this value should be kept.

Edit3: (deleted, it was wrong)

Edit4:
Another idea:

 __declspec( naked ) void patch() { _asm { call next // here we temporarily save the arguments dd 0 dd 0 dd 0 dd 0 next: pop eax // eax points to the first dd // now store the args pop edx mov [eax], edx pop edx mov [eax+4], edx pop edx mov [eax+8], edx pop edx mov [eax+12], edx // now we can push the value mov edx, [ebp+4] push edx // now, push the args again mov edx, [eax+12] push edx mov edx, [eax+8] push edx mov edx, [eax+4] push edx mov edx, [eax] push edx // now continue with the old code // -------------------------------- // restore the arguments push ebp mov ebp, esp // Make that the stack becomes as it were before the real function was called add esp, 8 // Calls our receiver call receiver mov esp, ebp pop ebp // ---------------------------- pop edx mov [ebp+4], edx ret } } 

This solution can withstand recursion, but not simultaneous execution from two different threads.

0
source share

I never used C ++ for low-level things like this, so I will not go into the features of your example, but in general, if you want to intercept the call and have logic support recursion, you have two options: Copy the entire frame of the stack ( parameters) and call the โ€œconnectedโ€ original with a new copy or, if this is not possible, save your own small stack to store the original return value (for example, as a linked list) in a data-based TLS.

0
source share

During normal execution, function operands are pushed backwards onto the stack. When executing the call operation code, the processor first pushes the EIP (or CS / IP) register onto the stack. This is the return address. When execution reaches the function you want to replace, it looks like this:

 Return address 1 Operand 1 Operand 2 Operand 2 

At this point, you will call your own function, which will have such a stack:

 Return address 2 Return address 1 Operand 1 Operand 2 Operand 3 

Your function should know that there is an extra DWORD on the stack as it does what you want. This is easy to handle if you also wrote your assembly of replacement functions, just add 4 whenever you refer to ESP. When you call RET in your function, the first return address will be returned, and execution will return to the function you are replacing. The stack will again be:

 Return address 1 Operand 1 Operand 2 Operand 3 

A RET call in this function will again call the return address from the stack and return control to the calling function. This leaves your operands still on the stack, leading to corruption. I suggest calling RET with the number of function operands as follows:

 RET 3 

This will lead to the appearance of 3 (in my example) or, be that as it may, many operands, from the stack. Here are some links you might find useful:

http://pdos.csail.mit.edu/6.828/2009/readings/i386/CALL.htm http://pdos.csail.mit.edu/6.828/2009/readings/i386/RET.htm

0
source share

All Articles