问题描述
我正在尝试将一个函数复制到内存中的缓冲区中并从那里执行它。
我已经创建了对实际函数的引用,并将其复制到具有 PAGE_EXECUTE_READ
权限的内存地址中。
出于某种原因,我收到了访问冲突错误。
这是代码:
void function1()
{
WinExec("calc.exe",SW_norMAL);
}
int main()
{
void* mem = VirtualAlloc(nullptr,4096,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
copyMemory(mem,&function1,4096);
VirtualProtect(mem,PAGE_EXECUTE_READ,NULL);
((void(*)())mem)();
return 1;
}
mem 中的缓冲区:
e9 b1 03 00 00 e9 7c 28 00 00 e9 63 40 00 00 e9 52 2e 00 00 e9 dd 24 00 00 e9 28 41 00 00 cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc
错误信息:
0xC0000005:访问冲突执行位置0x0000*****
解决方法
您肯定遇到的一个问题是,编译器通常会生成使用相对调用和跳转的代码。
例如,您在 mem 中的缓冲区以以下 5 个十六进制字节开头:
e9 b1 03 00 00
那个 0xe9 是一个操作码,它表示将接下来的 4 个字节视为小端顺序的有符号数,并跳转到通过将该有符号数添加到指令后第一个字节的地址而形成的地址。
>通过将代码从实际函数复制到缓冲区,您正在将相对跳转指令更改为“跳转到通过将 0x3b1 添加到缓冲区中该 5 字节指令末尾的地址而形成的地址”,解析为“跳转到缓冲区地址+0x3b6”。
关键是您通常不能在没有首先检查您没有任何会因复制而中断的相对寻址的情况下,将函数从一个地方复制到另一个地方。您可以反汇编您的函数(例如使用来自 windbg 的“u”命令)来检查此类指令。