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.)