我想做以下事情:
我有一个不是我的功能(这里真的没关系,只是说我无法控制它)而且我想修补它以便它调用我的函数,保留参数列表(跳跃不是一种选择).
我正在尝试做的是,在调用该函数之前将堆栈指针放在原来的状态,然后调用我的(就像回去再做同样的事情,但是使用不同的函数).这不起作用,因为堆栈变得混乱.我相信当我进行呼叫时它会替换返回地址.所以,我做了一个步骤来保存返回地址,将它保存在一个全局变量中它可以工作,但这不行,因为我希望它抵制recursitivy,你知道我的意思.无论如何,我是集会的新手,这就是我在这里的原因.
请不要告诉我有关已经制作软件的事情,因为我想以自己的方式做事.
当然,这段代码必须独立于编译器和优化.
我的代码(如果它比可接受的大,请告诉我如何发布):
// 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;
}
Run Code Online (Sandbox Code Playgroud)
打印(并且必须):
参数100 69 1337 666
编辑:
代码我正在测试Vlad建议(仍然不工作)
// 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
}
}
Run Code Online (Sandbox Code Playgroud)
你曾经有过add esp, 8一次add esp, 16。其中一定有一个是错误的。
编辑:
哦,我明白了,add esp, 8你必须从堆栈中删除ebp之前推送的 2 条指令和返回地址。
在 [ebp+4] 处必须有调用的返回地址_tmain。
Edit2:
您可以通过类似的方式分配“内部”变量:
call next
dd 0
next:
pop eax
mov [eax], yourinfo
Run Code Online (Sandbox Code Playgroud)
但仍然不清楚为什么我们需要保存该值。
Edit3:(已删除,错误)
编辑4:
另一个想法:
__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
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案可以在递归中幸存,但不能从两个不同的线程同时执行。